summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/video_core/engines/shader_bytecode.h20
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp44
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp6
-rw-r--r--src/video_core/shader/decode/texture.cpp56
-rw-r--r--src/video_core/shader/node.h2
5 files changed, 120 insertions, 8 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 16f410538..9c7b9b370 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -1446,6 +1446,26 @@ union Instruction {
} tlds;
union {
+ BitField<28, 1, u64> is_array;
+ BitField<29, 2, TextureType> texture_type;
+ BitField<35, 1, u64> aoffi_flag;
+ BitField<49, 1, u64> nodep_flag;
+
+ bool UsesMiscMode(TextureMiscMode mode) const {
+ switch (mode) {
+ case TextureMiscMode::AOFFI:
+ return aoffi_flag != 0;
+ case TextureMiscMode::NODEP:
+ return nodep_flag != 0;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ } txd;
+
+ union {
BitField<24, 2, StoreCacheManagement> cache_management;
BitField<33, 3, ImageType> image_type;
BitField<49, 2, OutOfBoundsStore> out_of_bounds_store;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index b87ee2ae8..49f0b1620 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -44,8 +44,9 @@ using Operation = const OperationNode&;
enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat };
struct TextureAoffi {};
+struct TextureDerivates {};
using TextureArgument = std::pair<Type, Node>;
-using TextureIR = std::variant<TextureAoffi, TextureArgument>;
+using TextureIR = std::variant<TextureAoffi, TextureDerivates, TextureArgument>;
constexpr u32 MAX_CONSTBUFFER_ELEMENTS =
static_cast<u32>(Maxwell::MaxConstBufferSize) / (4 * sizeof(float));
@@ -1129,6 +1130,8 @@ private:
expr += GenerateTextureArgument(*argument);
} else if (std::holds_alternative<TextureAoffi>(variant)) {
expr += GenerateTextureAoffi(meta->aoffi);
+ } else if (std::holds_alternative<TextureDerivates>(variant)) {
+ expr += GenerateTextureDerivates(meta->derivates);
} else {
UNREACHABLE();
}
@@ -1198,6 +1201,36 @@ private:
return expr;
}
+ std::string GenerateTextureDerivates(const std::vector<Node>& derivates) {
+ if (derivates.empty()) {
+ return {};
+ }
+ constexpr std::array coord_constructors = {"float", "vec2", "vec3"};
+ std::string expr = ", ";
+ const std::size_t components = derivates.size() / 2;
+ std::string dx = coord_constructors.at(components - 1);
+ std::string dy = coord_constructors.at(components - 1);
+ dx += '(';
+ dy += '(';
+
+ for (std::size_t index = 0; index < components; ++index) {
+ const auto operand_x{derivates.at(index * 2)};
+ const auto operand_y{derivates.at(index * 2 + 1)};
+ dx += Visit(operand_x).AsFloat();
+ dy += Visit(operand_y).AsFloat();
+
+ if (index + 1 < components) {
+ dx += ", ";
+ dy += ", ";
+ }
+ }
+ dx += ')';
+ dy += ')';
+ expr += dx + ", " + dy;
+
+ return expr;
+ }
+
std::string BuildIntegerCoordinates(Operation operation) {
constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("};
const std::size_t coords_count{operation.GetOperandsCount()};
@@ -1777,6 +1810,14 @@ private:
return {tmp, Type::Float};
}
+ Expression TextureGradient(Operation operation) {
+ const auto meta = std::get_if<MetaTexture>(&operation.GetMeta());
+ ASSERT(meta);
+
+ std::string expr = GenerateTexture(operation, "Grad", {TextureDerivates{}, TextureAoffi{}});
+ return {expr + GetSwizzle(meta->element), Type::Float};
+ }
+
Expression ImageLoad(Operation operation) {
if (!device.HasImageLoadFormatted()) {
LOG_ERROR(Render_OpenGL,
@@ -2131,6 +2172,7 @@ private:
&GLSLDecompiler::TextureQueryDimensions,
&GLSLDecompiler::TextureQueryLod,
&GLSLDecompiler::TexelFetch,
+ &GLSLDecompiler::TextureGradient,
&GLSLDecompiler::ImageLoad,
&GLSLDecompiler::ImageStore,
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 8378b35ac..30a525e5d 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -982,6 +982,11 @@ private:
return {};
}
+ Id TextureGradient(Operation operation) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
Id ImageLoad(Operation operation) {
UNIMPLEMENTED();
return {};
@@ -1474,6 +1479,7 @@ private:
&SPIRVDecompiler::TextureQueryDimensions,
&SPIRVDecompiler::TextureQueryLod,
&SPIRVDecompiler::TexelFetch,
+ &SPIRVDecompiler::TextureGradient,
&SPIRVDecompiler::ImageLoad,
&SPIRVDecompiler::ImageStore,
diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp
index bb926a132..0e501919d 100644
--- a/src/video_core/shader/decode/texture.cpp
+++ b/src/video_core/shader/decode/texture.cpp
@@ -134,13 +134,55 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
auto coords_copy = coords;
- MetaTexture meta{sampler, {}, {}, {}, {}, {}, component, element};
+ MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, component, element};
values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy));
}
WriteTexsInstructionFloat(bb, instr, values, true);
break;
}
+ case OpCode::Id::TXD_B:
+ is_bindless = true;
+ [[fallthrough]];
+ case OpCode::Id::TXD: {
+ UNIMPLEMENTED_IF_MSG(instr.txd.UsesMiscMode(TextureMiscMode::AOFFI),
+ "AOFFI is not implemented");
+ const auto is_array = static_cast<bool>(instr.txd.is_array != 0);
+ UNIMPLEMENTED_IF_MSG(is_array, "TXD Array is not implemented");
+
+ u64 base_reg = instr.gpr8.Value();
+ const auto derivate_reg = instr.gpr20.Value();
+ const auto texture_type = instr.txd.texture_type.Value();
+ const auto coord_count = GetCoordCount(texture_type);
+
+ const auto& sampler = is_bindless
+ ? GetBindlessSampler(base_reg, {{texture_type, false, false}})
+ : GetSampler(instr.sampler, {{texture_type, false, false}});
+ if (is_bindless) {
+ base_reg++;
+ }
+
+ std::vector<Node> coords;
+ std::vector<Node> derivates;
+ for (std::size_t i = 0; i < coord_count; ++i) {
+ coords.push_back(GetRegister(base_reg + i));
+ const std::size_t derivate = i * 2;
+ derivates.push_back(GetRegister(derivate_reg + derivate));
+ derivates.push_back(GetRegister(derivate_reg + derivate + 1));
+ }
+
+ Node4 values;
+ for (u32 element = 0; element < values.size(); ++element) {
+ auto coords_copy = coords;
+ MetaTexture meta{sampler, {}, {}, {}, derivates, {}, {}, {}, element};
+ values[element] =
+ Operation(OperationCode::TextureGradient, meta, std::move(coords_copy));
+ }
+
+ WriteTexInstructionFloat(bb, instr, values);
+
+ break;
+ }
case OpCode::Id::TXQ_B:
is_bindless = true;
[[fallthrough]];
@@ -158,7 +200,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
if (!instr.txq.IsComponentEnabled(element)) {
continue;
}
- MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, element};
+ MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, {}, element};
const Node value =
Operation(OperationCode::TextureQueryDimensions, meta,
GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0)));
@@ -213,7 +255,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
continue;
}
auto params = coords;
- MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, element};
+ MetaTexture meta{sampler, {}, {}, {}, {}, {}, {}, {}, element};
const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params));
SetTemporary(bb, indexer++, value);
}
@@ -461,7 +503,7 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
auto copy_coords = coords;
- MetaTexture meta{sampler, array, depth_compare, aoffi, bias, lod, {}, element};
+ MetaTexture meta{sampler, array, depth_compare, aoffi, {}, bias, lod, {}, element};
values[element] = Operation(read_method, meta, std::move(copy_coords));
}
@@ -594,7 +636,7 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
auto coords_copy = coords;
- MetaTexture meta{sampler, GetRegister(array_register), dc, aoffi, {}, {}, component,
+ MetaTexture meta{sampler, GetRegister(array_register), dc, aoffi, {}, {}, {}, component,
element};
values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy));
}
@@ -628,7 +670,7 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
auto coords_copy = coords;
- MetaTexture meta{sampler, array_register, {}, {}, {}, lod, {}, element};
+ MetaTexture meta{sampler, array_register, {}, {}, {}, {}, lod, {}, element};
values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
}
@@ -664,7 +706,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
auto coords_copy = coords;
- MetaTexture meta{sampler, array, {}, {}, {}, lod, {}, element};
+ MetaTexture meta{sampler, array, {}, {}, {}, {}, lod, {}, element};
values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
}
return values;
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 2d11facaf..6c5046d3b 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -151,6 +151,7 @@ enum class OperationCode {
TextureQueryDimensions, /// (MetaTexture, float a) -> float4
TextureQueryLod, /// (MetaTexture, float[N] coords) -> float4
TexelFetch, /// (MetaTexture, int[N], int) -> float4
+ TextureGradient, /// (MetaTexture, float[N] coords, float[N*2] derivates) -> float4
ImageLoad, /// (MetaImage, int[N] coords) -> void
ImageStore, /// (MetaImage, int[N] coords) -> void
@@ -363,6 +364,7 @@ struct MetaTexture {
Node array;
Node depth_compare;
std::vector<Node> aoffi;
+ std::vector<Node> derivates;
Node bias;
Node lod;
Node component{};