|
|
|
@ -19,6 +19,7 @@ |
|
|
|
#include "video_core/renderer_opengl/gl_device.h"
|
|
|
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
|
|
|
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
|
|
|
|
#include "video_core/shader/node.h"
|
|
|
|
#include "video_core/shader/shader_ir.h"
|
|
|
|
|
|
|
|
namespace OpenGL::GLShader { |
|
|
|
@ -398,8 +399,6 @@ public: |
|
|
|
usage.is_read, usage.is_written); |
|
|
|
} |
|
|
|
entries.clip_distances = ir.GetClipDistances(); |
|
|
|
entries.shader_viewport_layer_array = |
|
|
|
IsVertexShader(stage) && (ir.UsesLayer() || ir.UsesViewportIndex()); |
|
|
|
entries.shader_length = ir.GetLength(); |
|
|
|
return entries; |
|
|
|
} |
|
|
|
@ -725,36 +724,20 @@ private: |
|
|
|
const char* image_type = [&] { |
|
|
|
switch (image.GetType()) { |
|
|
|
case Tegra::Shader::ImageType::Texture1D: |
|
|
|
return "image1D"; |
|
|
|
return "1D"; |
|
|
|
case Tegra::Shader::ImageType::TextureBuffer: |
|
|
|
return "imageBuffer"; |
|
|
|
return "Buffer"; |
|
|
|
case Tegra::Shader::ImageType::Texture1DArray: |
|
|
|
return "image1DArray"; |
|
|
|
return "1DArray"; |
|
|
|
case Tegra::Shader::ImageType::Texture2D: |
|
|
|
return "image2D"; |
|
|
|
return "2D"; |
|
|
|
case Tegra::Shader::ImageType::Texture2DArray: |
|
|
|
return "image2DArray"; |
|
|
|
return "2DArray"; |
|
|
|
case Tegra::Shader::ImageType::Texture3D: |
|
|
|
return "image3D"; |
|
|
|
return "3D"; |
|
|
|
default: |
|
|
|
UNREACHABLE(); |
|
|
|
return "image1D"; |
|
|
|
} |
|
|
|
}(); |
|
|
|
|
|
|
|
const auto [type_prefix, format] = [&]() -> std::pair<const char*, const char*> { |
|
|
|
if (!image.IsSizeKnown()) { |
|
|
|
return {"", ""}; |
|
|
|
} |
|
|
|
switch (image.GetSize()) { |
|
|
|
case Tegra::Shader::ImageAtomicSize::U32: |
|
|
|
return {"u", "r32ui, "}; |
|
|
|
case Tegra::Shader::ImageAtomicSize::S32: |
|
|
|
return {"i", "r32i, "}; |
|
|
|
default: |
|
|
|
UNIMPLEMENTED_MSG("Unimplemented atomic size={}", |
|
|
|
static_cast<u32>(image.GetSize())); |
|
|
|
return {"", ""}; |
|
|
|
return "1D"; |
|
|
|
} |
|
|
|
}(); |
|
|
|
|
|
|
|
@ -765,8 +748,12 @@ private: |
|
|
|
qualifier += " writeonly"; |
|
|
|
} |
|
|
|
|
|
|
|
code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform " |
|
|
|
"{} {};", |
|
|
|
std::string format; |
|
|
|
if (image.IsAtomic()) { |
|
|
|
format = "r32ui, "; |
|
|
|
} |
|
|
|
|
|
|
|
code.AddLine("layout ({}binding = IMAGE_BINDING_{}) {} uniform uimage{} {};", format, |
|
|
|
image.GetIndex(), qualifier, image_type, GetImage(image)); |
|
|
|
} |
|
|
|
if (!images.empty()) { |
|
|
|
@ -1234,28 +1221,13 @@ private: |
|
|
|
} |
|
|
|
|
|
|
|
std::string BuildImageValues(Operation operation) { |
|
|
|
constexpr std::array constructors{"uint", "uvec2", "uvec3", "uvec4"}; |
|
|
|
const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
|
|
|
const auto [constructors, type] = [&]() -> std::pair<std::array<const char*, 4>, Type> { |
|
|
|
constexpr std::array float_constructors{"float", "vec2", "vec3", "vec4"}; |
|
|
|
if (!meta.image.IsSizeKnown()) { |
|
|
|
return {float_constructors, Type::Float}; |
|
|
|
} |
|
|
|
switch (meta.image.GetSize()) { |
|
|
|
case Tegra::Shader::ImageAtomicSize::U32: |
|
|
|
return {{"uint", "uvec2", "uvec3", "uvec4"}, Type::Uint}; |
|
|
|
case Tegra::Shader::ImageAtomicSize::S32: |
|
|
|
return {{"int", "ivec2", "ivec3", "ivec4"}, Type::Uint}; |
|
|
|
default: |
|
|
|
UNIMPLEMENTED_MSG("Unimplemented image size={}", |
|
|
|
static_cast<u32>(meta.image.GetSize())); |
|
|
|
return {float_constructors, Type::Float}; |
|
|
|
} |
|
|
|
}(); |
|
|
|
|
|
|
|
const std::size_t values_count{meta.values.size()}; |
|
|
|
std::string expr = fmt::format("{}(", constructors.at(values_count - 1)); |
|
|
|
for (std::size_t i = 0; i < values_count; ++i) { |
|
|
|
expr += Visit(meta.values.at(i)).As(type); |
|
|
|
expr += Visit(meta.values.at(i)).AsUint(); |
|
|
|
if (i + 1 < values_count) { |
|
|
|
expr += ", "; |
|
|
|
} |
|
|
|
@ -1264,29 +1236,6 @@ private: |
|
|
|
return expr; |
|
|
|
} |
|
|
|
|
|
|
|
Expression AtomicImage(Operation operation, const char* opname) { |
|
|
|
constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("}; |
|
|
|
const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
|
|
|
ASSERT(meta.values.size() == 1); |
|
|
|
ASSERT(meta.image.IsSizeKnown()); |
|
|
|
|
|
|
|
const auto type = [&]() { |
|
|
|
switch (const auto size = meta.image.GetSize()) { |
|
|
|
case Tegra::Shader::ImageAtomicSize::U32: |
|
|
|
return Type::Uint; |
|
|
|
case Tegra::Shader::ImageAtomicSize::S32: |
|
|
|
return Type::Int; |
|
|
|
default: |
|
|
|
UNIMPLEMENTED_MSG("Unimplemented image size={}", static_cast<u32>(size)); |
|
|
|
return Type::Uint; |
|
|
|
} |
|
|
|
}(); |
|
|
|
|
|
|
|
return {fmt::format("{}({}, {}, {})", opname, GetImage(meta.image), |
|
|
|
BuildIntegerCoordinates(operation), Visit(meta.values[0]).As(type)), |
|
|
|
type}; |
|
|
|
} |
|
|
|
|
|
|
|
Expression Assign(Operation operation) { |
|
|
|
const Node& dest = operation[0]; |
|
|
|
const Node& src = operation[1]; |
|
|
|
@ -1809,6 +1758,19 @@ private: |
|
|
|
return {tmp, Type::Float}; |
|
|
|
} |
|
|
|
|
|
|
|
Expression ImageLoad(Operation operation) { |
|
|
|
if (!device.HasImageLoadFormatted()) { |
|
|
|
LOG_ERROR(Render_OpenGL, |
|
|
|
"Device lacks GL_EXT_shader_image_load_formatted, stubbing image load"); |
|
|
|
return {"0", Type::Int}; |
|
|
|
} |
|
|
|
|
|
|
|
const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
|
|
|
return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image), |
|
|
|
BuildIntegerCoordinates(operation), GetSwizzle(meta.element)), |
|
|
|
Type::Uint}; |
|
|
|
} |
|
|
|
|
|
|
|
Expression ImageStore(Operation operation) { |
|
|
|
const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
|
|
|
code.AddLine("imageStore({}, {}, {});", GetImage(meta.image), |
|
|
|
@ -1816,31 +1778,14 @@ private: |
|
|
|
return {}; |
|
|
|
} |
|
|
|
|
|
|
|
Expression AtomicImageAdd(Operation operation) { |
|
|
|
return AtomicImage(operation, "imageAtomicAdd"); |
|
|
|
} |
|
|
|
|
|
|
|
Expression AtomicImageMin(Operation operation) { |
|
|
|
return AtomicImage(operation, "imageAtomicMin"); |
|
|
|
} |
|
|
|
|
|
|
|
Expression AtomicImageMax(Operation operation) { |
|
|
|
return AtomicImage(operation, "imageAtomicMax"); |
|
|
|
} |
|
|
|
Expression AtomicImageAnd(Operation operation) { |
|
|
|
return AtomicImage(operation, "imageAtomicAnd"); |
|
|
|
} |
|
|
|
|
|
|
|
Expression AtomicImageOr(Operation operation) { |
|
|
|
return AtomicImage(operation, "imageAtomicOr"); |
|
|
|
} |
|
|
|
|
|
|
|
Expression AtomicImageXor(Operation operation) { |
|
|
|
return AtomicImage(operation, "imageAtomicXor"); |
|
|
|
} |
|
|
|
template <const std::string_view& opname> |
|
|
|
Expression AtomicImage(Operation operation) { |
|
|
|
const auto meta{std::get<MetaImage>(operation.GetMeta())}; |
|
|
|
ASSERT(meta.values.size() == 1); |
|
|
|
|
|
|
|
Expression AtomicImageExchange(Operation operation) { |
|
|
|
return AtomicImage(operation, "imageAtomicExchange"); |
|
|
|
return {fmt::format("imageAtomic{}({}, {}, {})", opname, GetImage(meta.image), |
|
|
|
BuildIntegerCoordinates(operation), Visit(meta.values[0]).AsUint()), |
|
|
|
Type::Uint}; |
|
|
|
} |
|
|
|
|
|
|
|
Expression Branch(Operation operation) { |
|
|
|
@ -2035,6 +1980,12 @@ private: |
|
|
|
Func() = delete; |
|
|
|
~Func() = delete; |
|
|
|
|
|
|
|
static constexpr std::string_view Add = "Add"; |
|
|
|
static constexpr std::string_view And = "And"; |
|
|
|
static constexpr std::string_view Or = "Or"; |
|
|
|
static constexpr std::string_view Xor = "Xor"; |
|
|
|
static constexpr std::string_view Exchange = "Exchange"; |
|
|
|
|
|
|
|
static constexpr std::string_view ShuffleIndexed = "shuffleNV"; |
|
|
|
static constexpr std::string_view ShuffleUp = "shuffleUpNV"; |
|
|
|
static constexpr std::string_view ShuffleDown = "shuffleDownNV"; |
|
|
|
@ -2172,14 +2123,14 @@ private: |
|
|
|
&GLSLDecompiler::TextureQueryLod, |
|
|
|
&GLSLDecompiler::TexelFetch, |
|
|
|
|
|
|
|
&GLSLDecompiler::ImageLoad, |
|
|
|
&GLSLDecompiler::ImageStore, |
|
|
|
&GLSLDecompiler::AtomicImageAdd, |
|
|
|
&GLSLDecompiler::AtomicImageMin, |
|
|
|
&GLSLDecompiler::AtomicImageMax, |
|
|
|
&GLSLDecompiler::AtomicImageAnd, |
|
|
|
&GLSLDecompiler::AtomicImageOr, |
|
|
|
&GLSLDecompiler::AtomicImageXor, |
|
|
|
&GLSLDecompiler::AtomicImageExchange, |
|
|
|
|
|
|
|
&GLSLDecompiler::AtomicImage<Func::Add>, |
|
|
|
&GLSLDecompiler::AtomicImage<Func::And>, |
|
|
|
&GLSLDecompiler::AtomicImage<Func::Or>, |
|
|
|
&GLSLDecompiler::AtomicImage<Func::Xor>, |
|
|
|
&GLSLDecompiler::AtomicImage<Func::Exchange>, |
|
|
|
|
|
|
|
&GLSLDecompiler::Branch, |
|
|
|
&GLSLDecompiler::BranchIndirect, |
|
|
|
|