diff options
Diffstat (limited to 'src/shader_recompiler')
14 files changed, 172 insertions, 21 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 5f3868bfe..7f8dc8eed 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -126,6 +126,7 @@ add_library(shader_recompiler STATIC | |||
| 126 | frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp | 126 | frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp |
| 127 | frontend/maxwell/translate/impl/texture_gather_swizzled.cpp | 127 | frontend/maxwell/translate/impl/texture_gather_swizzled.cpp |
| 128 | frontend/maxwell/translate/impl/texture_gather.cpp | 128 | frontend/maxwell/translate/impl/texture_gather.cpp |
| 129 | frontend/maxwell/translate/impl/texture_query.cpp | ||
| 129 | frontend/maxwell/translate/impl/vote.cpp | 130 | frontend/maxwell/translate/impl/vote.cpp |
| 130 | frontend/maxwell/translate/impl/warp_shuffle.cpp | 131 | frontend/maxwell/translate/impl/warp_shuffle.cpp |
| 131 | frontend/maxwell/translate/translate.cpp | 132 | frontend/maxwell/translate/translate.cpp |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 50793b5bf..c2d13f97c 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -244,8 +244,9 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) { | |||
| 244 | if (desc.count != 1) { | 244 | if (desc.count != 1) { |
| 245 | throw NotImplementedException("Array of textures"); | 245 | throw NotImplementedException("Array of textures"); |
| 246 | } | 246 | } |
| 247 | const Id type{TypeSampledImage(ImageType(*this, desc))}; | 247 | const Id image_type{ImageType(*this, desc)}; |
| 248 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, type)}; | 248 | const Id sampled_type{TypeSampledImage(image_type)}; |
| 249 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, sampled_type)}; | ||
| 249 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | 250 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; |
| 250 | Decorate(id, spv::Decoration::Binding, binding); | 251 | Decorate(id, spv::Decoration::Binding, binding); |
| 251 | Decorate(id, spv::Decoration::DescriptorSet, 0U); | 252 | Decorate(id, spv::Decoration::DescriptorSet, 0U); |
| @@ -254,7 +255,8 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) { | |||
| 254 | // TODO: Pass count info | 255 | // TODO: Pass count info |
| 255 | textures.push_back(TextureDefinition{ | 256 | textures.push_back(TextureDefinition{ |
| 256 | .id{id}, | 257 | .id{id}, |
| 257 | .type{type}, | 258 | .sampled_type{sampled_type}, |
| 259 | .image_type{image_type}, | ||
| 258 | }); | 260 | }); |
| 259 | } | 261 | } |
| 260 | binding += desc.count; | 262 | binding += desc.count; |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index 5ed815c06..0cb411a0e 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h | |||
| @@ -31,7 +31,8 @@ private: | |||
| 31 | 31 | ||
| 32 | struct TextureDefinition { | 32 | struct TextureDefinition { |
| 33 | Id id; | 33 | Id id; |
| 34 | Id type; | 34 | Id sampled_type; |
| 35 | Id image_type; | ||
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| 37 | struct UniformDefinitions { | 38 | struct UniformDefinitions { |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index cee72f50d..4bed16e7b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -126,10 +126,10 @@ Id DefineMain(EmitContext& ctx, IR::Program& program) { | |||
| 126 | return main; | 126 | return main; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | void DefineEntryPoint(Environment& env, EmitContext& ctx, Id main) { | 129 | void DefineEntryPoint(Environment& env, const IR::Program& program, EmitContext& ctx, Id main) { |
| 130 | const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size()); | 130 | const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size()); |
| 131 | spv::ExecutionModel execution_model{}; | 131 | spv::ExecutionModel execution_model{}; |
| 132 | switch (env.ShaderStage()) { | 132 | switch (program.stage) { |
| 133 | case Shader::Stage::Compute: { | 133 | case Shader::Stage::Compute: { |
| 134 | const std::array<u32, 3> workgroup_size{env.WorkgroupSize()}; | 134 | const std::array<u32, 3> workgroup_size{env.WorkgroupSize()}; |
| 135 | execution_model = spv::ExecutionModel::GLCompute; | 135 | execution_model = spv::ExecutionModel::GLCompute; |
| @@ -143,6 +143,9 @@ void DefineEntryPoint(Environment& env, EmitContext& ctx, Id main) { | |||
| 143 | case Shader::Stage::Fragment: | 143 | case Shader::Stage::Fragment: |
| 144 | execution_model = spv::ExecutionModel::Fragment; | 144 | execution_model = spv::ExecutionModel::Fragment; |
| 145 | ctx.AddExecutionMode(main, spv::ExecutionMode::OriginUpperLeft); | 145 | ctx.AddExecutionMode(main, spv::ExecutionMode::OriginUpperLeft); |
| 146 | if (program.info.stores_frag_depth) { | ||
| 147 | ctx.AddExecutionMode(main, spv::ExecutionMode::DepthReplacing); | ||
| 148 | } | ||
| 146 | break; | 149 | break; |
| 147 | default: | 150 | default: |
| 148 | throw NotImplementedException("Stage {}", env.ShaderStage()); | 151 | throw NotImplementedException("Stage {}", env.ShaderStage()); |
| @@ -235,6 +238,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | |||
| 235 | } | 238 | } |
| 236 | // TODO: Track this usage | 239 | // TODO: Track this usage |
| 237 | ctx.AddCapability(spv::Capability::ImageGatherExtended); | 240 | ctx.AddCapability(spv::Capability::ImageGatherExtended); |
| 241 | ctx.AddCapability(spv::Capability::ImageQuery); | ||
| 238 | } | 242 | } |
| 239 | 243 | ||
| 240 | Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) { | 244 | Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) { |
| @@ -267,7 +271,7 @@ std::vector<u32> EmitSPIRV(const Profile& profile, Environment& env, IR::Program | |||
| 267 | u32& binding) { | 271 | u32& binding) { |
| 268 | EmitContext ctx{profile, program, binding}; | 272 | EmitContext ctx{profile, program, binding}; |
| 269 | const Id main{DefineMain(ctx, program)}; | 273 | const Id main{DefineMain(ctx, program)}; |
| 270 | DefineEntryPoint(env, ctx, main); | 274 | DefineEntryPoint(env, program, ctx, main); |
| 271 | if (profile.support_float_controls) { | 275 | if (profile.support_float_controls) { |
| 272 | ctx.AddExtension("SPV_KHR_float_controls"); | 276 | ctx.AddExtension("SPV_KHR_float_controls"); |
| 273 | SetupDenormControl(profile, program, ctx, main); | 277 | SetupDenormControl(profile, program, ctx, main); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 4da1f3707..b82b16e9d 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -343,6 +343,7 @@ Id EmitBindlessImageSampleDrefExplicitLod(EmitContext&); | |||
| 343 | Id EmitBindlessImageGather(EmitContext&); | 343 | Id EmitBindlessImageGather(EmitContext&); |
| 344 | Id EmitBindlessImageGatherDref(EmitContext&); | 344 | Id EmitBindlessImageGatherDref(EmitContext&); |
| 345 | Id EmitBindlessImageFetch(EmitContext&); | 345 | Id EmitBindlessImageFetch(EmitContext&); |
| 346 | Id EmitBindlessImageQueryDimensions(EmitContext&); | ||
| 346 | Id EmitBoundImageSampleImplicitLod(EmitContext&); | 347 | Id EmitBoundImageSampleImplicitLod(EmitContext&); |
| 347 | Id EmitBoundImageSampleExplicitLod(EmitContext&); | 348 | Id EmitBoundImageSampleExplicitLod(EmitContext&); |
| 348 | Id EmitBoundImageSampleDrefImplicitLod(EmitContext&); | 349 | Id EmitBoundImageSampleDrefImplicitLod(EmitContext&); |
| @@ -350,6 +351,7 @@ Id EmitBoundImageSampleDrefExplicitLod(EmitContext&); | |||
| 350 | Id EmitBoundImageGather(EmitContext&); | 351 | Id EmitBoundImageGather(EmitContext&); |
| 351 | Id EmitBoundImageGatherDref(EmitContext&); | 352 | Id EmitBoundImageGatherDref(EmitContext&); |
| 352 | Id EmitBoundImageFetch(EmitContext&); | 353 | Id EmitBoundImageFetch(EmitContext&); |
| 354 | Id EmitBoundImageQueryDimensions(EmitContext&); | ||
| 353 | Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 355 | Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 354 | Id bias_lc, Id offset); | 356 | Id bias_lc, Id offset); |
| 355 | Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 357 | Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| @@ -364,6 +366,7 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, | |||
| 364 | const IR::Value& offset, const IR::Value& offset2, Id dref); | 366 | const IR::Value& offset, const IR::Value& offset2, Id dref); |
| 365 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, | 367 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, |
| 366 | Id lod, Id ms); | 368 | Id lod, Id ms); |
| 369 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod); | ||
| 367 | Id EmitVoteAll(EmitContext& ctx, Id pred); | 370 | Id EmitVoteAll(EmitContext& ctx, Id pred); |
| 368 | Id EmitVoteAny(EmitContext& ctx, Id pred); | 371 | Id EmitVoteAny(EmitContext& ctx, Id pred); |
| 369 | Id EmitVoteEqual(EmitContext& ctx, Id pred); | 372 | Id EmitVoteEqual(EmitContext& ctx, Id pred); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index b6e9d3c0c..3ea0011aa 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |||
| @@ -91,7 +91,15 @@ private: | |||
| 91 | Id Texture(EmitContext& ctx, const IR::Value& index) { | 91 | Id Texture(EmitContext& ctx, const IR::Value& index) { |
| 92 | if (index.IsImmediate()) { | 92 | if (index.IsImmediate()) { |
| 93 | const TextureDefinition def{ctx.textures.at(index.U32())}; | 93 | const TextureDefinition def{ctx.textures.at(index.U32())}; |
| 94 | return ctx.OpLoad(def.type, def.id); | 94 | return ctx.OpLoad(def.sampled_type, def.id); |
| 95 | } | ||
| 96 | throw NotImplementedException("Indirect texture sample"); | ||
| 97 | } | ||
| 98 | |||
| 99 | Id TextureImage(EmitContext& ctx, const IR::Value& index) { | ||
| 100 | if (index.IsImmediate()) { | ||
| 101 | const TextureDefinition def{ctx.textures.at(index.U32())}; | ||
| 102 | return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id)); | ||
| 95 | } | 103 | } |
| 96 | throw NotImplementedException("Indirect texture sample"); | 104 | throw NotImplementedException("Indirect texture sample"); |
| 97 | } | 105 | } |
| @@ -149,6 +157,10 @@ Id EmitBindlessImageFetch(EmitContext&) { | |||
| 149 | throw LogicError("Unreachable instruction"); | 157 | throw LogicError("Unreachable instruction"); |
| 150 | } | 158 | } |
| 151 | 159 | ||
| 160 | Id EmitBindlessImageQueryDimensions(EmitContext&) { | ||
| 161 | throw LogicError("Unreachable instruction"); | ||
| 162 | } | ||
| 163 | |||
| 152 | Id EmitBoundImageSampleImplicitLod(EmitContext&) { | 164 | Id EmitBoundImageSampleImplicitLod(EmitContext&) { |
| 153 | throw LogicError("Unreachable instruction"); | 165 | throw LogicError("Unreachable instruction"); |
| 154 | } | 166 | } |
| @@ -177,6 +189,10 @@ Id EmitBoundImageFetch(EmitContext&) { | |||
| 177 | throw LogicError("Unreachable instruction"); | 189 | throw LogicError("Unreachable instruction"); |
| 178 | } | 190 | } |
| 179 | 191 | ||
| 192 | Id EmitBoundImageQueryDimensions(EmitContext&) { | ||
| 193 | throw LogicError("Unreachable instruction"); | ||
| 194 | } | ||
| 195 | |||
| 180 | Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 196 | Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 181 | Id bias_lc, Id offset) { | 197 | Id bias_lc, Id offset) { |
| 182 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 198 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| @@ -241,4 +257,34 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c | |||
| 241 | Texture(ctx, index), coords, operands.Mask(), operands.Span()); | 257 | Texture(ctx, index), coords, operands.Mask(), operands.Span()); |
| 242 | } | 258 | } |
| 243 | 259 | ||
| 260 | Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) { | ||
| 261 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||
| 262 | const Id image{TextureImage(ctx, index)}; | ||
| 263 | const Id zero{ctx.u32_zero_value}; | ||
| 264 | const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }}; | ||
| 265 | switch (info.type) { | ||
| 266 | case TextureType::Color1D: | ||
| 267 | case TextureType::Shadow1D: | ||
| 268 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod), | ||
| 269 | zero, zero, mips()); | ||
| 270 | case TextureType::ColorArray1D: | ||
| 271 | case TextureType::Color2D: | ||
| 272 | case TextureType::ColorCube: | ||
| 273 | case TextureType::ShadowArray1D: | ||
| 274 | case TextureType::Shadow2D: | ||
| 275 | case TextureType::ShadowCube: | ||
| 276 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod), | ||
| 277 | zero, mips()); | ||
| 278 | case TextureType::ColorArray2D: | ||
| 279 | case TextureType::Color3D: | ||
| 280 | case TextureType::ColorArrayCube: | ||
| 281 | case TextureType::ShadowArray2D: | ||
| 282 | case TextureType::Shadow3D: | ||
| 283 | case TextureType::ShadowArrayCube: | ||
| 284 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod), | ||
| 285 | mips()); | ||
| 286 | } | ||
| 287 | throw LogicError("Unspecified image type {}", info.type.Value()); | ||
| 288 | } | ||
| 289 | |||
| 244 | } // namespace Shader::Backend::SPIRV | 290 | } // namespace Shader::Backend::SPIRV |
diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h index 6dec4b255..0c62c1c54 100644 --- a/src/shader_recompiler/environment.h +++ b/src/shader_recompiler/environment.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/common_types.h" | 5 | #include "common/common_types.h" |
| 6 | #include "shader_recompiler/program_header.h" | 6 | #include "shader_recompiler/program_header.h" |
| 7 | #include "shader_recompiler/shader_info.h" | ||
| 7 | #include "shader_recompiler/stage.h" | 8 | #include "shader_recompiler/stage.h" |
| 8 | 9 | ||
| 9 | namespace Shader { | 10 | namespace Shader { |
| @@ -14,6 +15,8 @@ public: | |||
| 14 | 15 | ||
| 15 | [[nodiscard]] virtual u64 ReadInstruction(u32 address) = 0; | 16 | [[nodiscard]] virtual u64 ReadInstruction(u32 address) = 0; |
| 16 | 17 | ||
| 18 | [[nodiscard]] virtual TextureType ReadTextureType(u32 cbuf_index, u32 cbuf_offset) = 0; | ||
| 19 | |||
| 17 | [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; | 20 | [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; |
| 18 | 21 | ||
| 19 | [[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() const = 0; | 22 | [[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() const = 0; |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 0296f8773..f281c023f 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -1493,6 +1493,12 @@ Value IREmitter::ImageFetch(const Value& handle, const Value& coords, const Valu | |||
| 1493 | return Inst(op, Flags{info}, handle, coords, offset, lod, multisampling); | 1493 | return Inst(op, Flags{info}, handle, coords, offset, lod, multisampling); |
| 1494 | } | 1494 | } |
| 1495 | 1495 | ||
| 1496 | Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod) { | ||
| 1497 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageQueryDimensions | ||
| 1498 | : Opcode::BindlessImageQueryDimensions}; | ||
| 1499 | return Inst(op, handle, lod); | ||
| 1500 | } | ||
| 1501 | |||
| 1496 | U1 IREmitter::VoteAll(const U1& value) { | 1502 | U1 IREmitter::VoteAll(const U1& value) { |
| 1497 | return Inst<U1>(Opcode::VoteAll, value); | 1503 | return Inst<U1>(Opcode::VoteAll, value); |
| 1498 | } | 1504 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 446fd7785..771c186d4 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -239,6 +239,7 @@ public: | |||
| 239 | const F32& dref, const F32& lod, | 239 | const F32& dref, const F32& lod, |
| 240 | const Value& offset, const F32& lod_clamp, | 240 | const Value& offset, const F32& lod_clamp, |
| 241 | TextureInstInfo info); | 241 | TextureInstInfo info); |
| 242 | [[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod); | ||
| 242 | 243 | ||
| 243 | [[nodiscard]] Value ImageGather(const Value& handle, const Value& coords, const Value& offset, | 244 | [[nodiscard]] Value ImageGather(const Value& handle, const Value& coords, const Value& offset, |
| 244 | const Value& offset2, TextureInstInfo info); | 245 | const Value& offset2, TextureInstInfo info); |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index e12b92c47..5d7462d76 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -356,6 +356,7 @@ OPCODE(BindlessImageSampleDrefExplicitLod, F32, U32, | |||
| 356 | OPCODE(BindlessImageGather, F32x4, U32, Opaque, Opaque, Opaque, ) | 356 | OPCODE(BindlessImageGather, F32x4, U32, Opaque, Opaque, Opaque, ) |
| 357 | OPCODE(BindlessImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, ) | 357 | OPCODE(BindlessImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, ) |
| 358 | OPCODE(BindlessImageFetch, F32x4, U32, Opaque, U32, U32, ) | 358 | OPCODE(BindlessImageFetch, F32x4, U32, Opaque, U32, U32, ) |
| 359 | OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, ) | ||
| 359 | 360 | ||
| 360 | OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 361 | OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) |
| 361 | OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 362 | OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) |
| @@ -364,6 +365,7 @@ OPCODE(BoundImageSampleDrefExplicitLod, F32, U32, | |||
| 364 | OPCODE(BoundImageGather, F32x4, U32, Opaque, Opaque, Opaque, ) | 365 | OPCODE(BoundImageGather, F32x4, U32, Opaque, Opaque, Opaque, ) |
| 365 | OPCODE(BoundImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, ) | 366 | OPCODE(BoundImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, ) |
| 366 | OPCODE(BoundImageFetch, F32x4, U32, Opaque, U32, U32, ) | 367 | OPCODE(BoundImageFetch, F32x4, U32, Opaque, U32, U32, ) |
| 368 | OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, ) | ||
| 367 | 369 | ||
| 368 | OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 370 | OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) |
| 369 | OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 371 | OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) |
| @@ -372,6 +374,7 @@ OPCODE(ImageSampleDrefExplicitLod, F32, U32, | |||
| 372 | OPCODE(ImageGather, F32x4, U32, Opaque, Opaque, Opaque, ) | 374 | OPCODE(ImageGather, F32x4, U32, Opaque, Opaque, Opaque, ) |
| 373 | OPCODE(ImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, ) | 375 | OPCODE(ImageGatherDref, F32x4, U32, Opaque, Opaque, Opaque, F32, ) |
| 374 | OPCODE(ImageFetch, F32x4, U32, Opaque, U32, U32, ) | 376 | OPCODE(ImageFetch, F32x4, U32, Opaque, U32, U32, ) |
| 377 | OPCODE(ImageQueryDimensions, U32x4, U32, U32, ) | ||
| 375 | 378 | ||
| 376 | // Warp operations | 379 | // Warp operations |
| 377 | OPCODE(VoteAll, U1, U1, ) | 380 | OPCODE(VoteAll, U1, U1, ) |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp index 788765c21..96ee2e741 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -373,14 +373,6 @@ void TranslatorVisitor::TXD_b(u64) { | |||
| 373 | ThrowNotImplemented(Opcode::TXD_b); | 373 | ThrowNotImplemented(Opcode::TXD_b); |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | void TranslatorVisitor::TXQ(u64) { | ||
| 377 | ThrowNotImplemented(Opcode::TXQ); | ||
| 378 | } | ||
| 379 | |||
| 380 | void TranslatorVisitor::TXQ_b(u64) { | ||
| 381 | ThrowNotImplemented(Opcode::TXQ_b); | ||
| 382 | } | ||
| 383 | |||
| 384 | void TranslatorVisitor::VABSDIFF(u64) { | 376 | void TranslatorVisitor::VABSDIFF(u64) { |
| 385 | ThrowNotImplemented(Opcode::VABSDIFF); | 377 | ThrowNotImplemented(Opcode::VABSDIFF); |
| 386 | } | 378 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_query.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_query.cpp new file mode 100644 index 000000000..e8ea8faeb --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_query.cpp | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <optional> | ||
| 6 | |||
| 7 | #include "common/bit_field.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "shader_recompiler/frontend/ir/modifiers.h" | ||
| 10 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 11 | |||
| 12 | namespace Shader::Maxwell { | ||
| 13 | namespace { | ||
| 14 | enum class Mode : u64 { | ||
| 15 | Dimension = 1, | ||
| 16 | TextureType = 2, | ||
| 17 | SamplePos = 5, | ||
| 18 | }; | ||
| 19 | |||
| 20 | IR::Value Query(TranslatorVisitor& v, const IR::U32& handle, Mode mode, IR::Reg src_reg) { | ||
| 21 | switch (mode) { | ||
| 22 | case Mode::Dimension: { | ||
| 23 | const IR::U32 lod{v.X(src_reg)}; | ||
| 24 | return v.ir.ImageQueryDimension(handle, lod); | ||
| 25 | } | ||
| 26 | case Mode::TextureType: | ||
| 27 | case Mode::SamplePos: | ||
| 28 | default: | ||
| 29 | throw NotImplementedException("Mode {}", mode); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | void Impl(TranslatorVisitor& v, u64 insn, std::optional<u32> cbuf_offset) { | ||
| 34 | union { | ||
| 35 | u64 raw; | ||
| 36 | BitField<49, 1, u64> nodep; | ||
| 37 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 38 | BitField<8, 8, IR::Reg> src_reg; | ||
| 39 | BitField<22, 3, Mode> mode; | ||
| 40 | BitField<31, 4, u64> mask; | ||
| 41 | } const txq{insn}; | ||
| 42 | |||
| 43 | IR::Reg src_reg{txq.src_reg}; | ||
| 44 | IR::U32 handle; | ||
| 45 | if (cbuf_offset) { | ||
| 46 | handle = v.ir.Imm32(*cbuf_offset); | ||
| 47 | } else { | ||
| 48 | handle = v.X(src_reg); | ||
| 49 | ++src_reg; | ||
| 50 | } | ||
| 51 | const IR::Value query{Query(v, handle, txq.mode, src_reg)}; | ||
| 52 | IR::Reg dest_reg{txq.dest_reg}; | ||
| 53 | for (int element = 0; element < 4; ++element) { | ||
| 54 | if (((txq.mask >> element) & 1) == 0) { | ||
| 55 | continue; | ||
| 56 | } | ||
| 57 | v.X(dest_reg, IR::U32{v.ir.CompositeExtract(query, element)}); | ||
| 58 | ++dest_reg; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } // Anonymous namespace | ||
| 62 | |||
| 63 | void TranslatorVisitor::TXQ(u64 insn) { | ||
| 64 | union { | ||
| 65 | u64 raw; | ||
| 66 | BitField<36, 13, u64> cbuf_offset; | ||
| 67 | } const txq{insn}; | ||
| 68 | |||
| 69 | Impl(*this, insn, static_cast<u32>(txq.cbuf_offset)); | ||
| 70 | } | ||
| 71 | |||
| 72 | void TranslatorVisitor::TXQ_b(u64 insn) { | ||
| 73 | Impl(*this, insn, std::nullopt); | ||
| 74 | } | ||
| 75 | |||
| 76 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 6fe06fda8..80ca8db26 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -365,7 +365,8 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 365 | case IR::Opcode::ImageSampleDrefImplicitLod: | 365 | case IR::Opcode::ImageSampleDrefImplicitLod: |
| 366 | case IR::Opcode::ImageSampleDrefExplicitLod: | 366 | case IR::Opcode::ImageSampleDrefExplicitLod: |
| 367 | case IR::Opcode::ImageGather: | 367 | case IR::Opcode::ImageGather: |
| 368 | case IR::Opcode::ImageGatherDref: { | 368 | case IR::Opcode::ImageGatherDref: |
| 369 | case IR::Opcode::ImageQueryDimensions: { | ||
| 369 | const TextureType type{inst.Flags<IR::TextureInstInfo>().type}; | 370 | const TextureType type{inst.Flags<IR::TextureInstInfo>().type}; |
| 370 | info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D || | 371 | info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D || |
| 371 | type == TextureType::Shadow1D || type == TextureType::ShadowArray1D; | 372 | type == TextureType::Shadow1D || type == TextureType::ShadowArray1D; |
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 0167dd06e..dfacf848f 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -54,6 +54,9 @@ IR::Opcode IndexedInstruction(const IR::Inst& inst) { | |||
| 54 | case IR::Opcode::BindlessImageFetch: | 54 | case IR::Opcode::BindlessImageFetch: |
| 55 | case IR::Opcode::BoundImageFetch: | 55 | case IR::Opcode::BoundImageFetch: |
| 56 | return IR::Opcode::ImageFetch; | 56 | return IR::Opcode::ImageFetch; |
| 57 | case IR::Opcode::BoundImageQueryDimensions: | ||
| 58 | case IR::Opcode::BindlessImageQueryDimensions: | ||
| 59 | return IR::Opcode::ImageQueryDimensions; | ||
| 57 | default: | 60 | default: |
| 58 | return IR::Opcode::Void; | 61 | return IR::Opcode::Void; |
| 59 | } | 62 | } |
| @@ -68,6 +71,7 @@ bool IsBindless(const IR::Inst& inst) { | |||
| 68 | case IR::Opcode::BindlessImageGather: | 71 | case IR::Opcode::BindlessImageGather: |
| 69 | case IR::Opcode::BindlessImageGatherDref: | 72 | case IR::Opcode::BindlessImageGatherDref: |
| 70 | case IR::Opcode::BindlessImageFetch: | 73 | case IR::Opcode::BindlessImageFetch: |
| 74 | case IR::Opcode::BindlessImageQueryDimensions: | ||
| 71 | return true; | 75 | return true; |
| 72 | case IR::Opcode::BoundImageSampleImplicitLod: | 76 | case IR::Opcode::BoundImageSampleImplicitLod: |
| 73 | case IR::Opcode::BoundImageSampleExplicitLod: | 77 | case IR::Opcode::BoundImageSampleExplicitLod: |
| @@ -76,6 +80,7 @@ bool IsBindless(const IR::Inst& inst) { | |||
| 76 | case IR::Opcode::BoundImageGather: | 80 | case IR::Opcode::BoundImageGather: |
| 77 | case IR::Opcode::BoundImageGatherDref: | 81 | case IR::Opcode::BoundImageGatherDref: |
| 78 | case IR::Opcode::BoundImageFetch: | 82 | case IR::Opcode::BoundImageFetch: |
| 83 | case IR::Opcode::BoundImageQueryDimensions: | ||
| 79 | return false; | 84 | return false; |
| 80 | default: | 85 | default: |
| 81 | throw InvalidArgument("Invalid opcode {}", inst.Opcode()); | 86 | throw InvalidArgument("Invalid opcode {}", inst.Opcode()); |
| @@ -198,13 +203,20 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 198 | for (TextureInst& texture_inst : to_replace) { | 203 | for (TextureInst& texture_inst : to_replace) { |
| 199 | // TODO: Handle arrays | 204 | // TODO: Handle arrays |
| 200 | IR::Inst* const inst{texture_inst.inst}; | 205 | IR::Inst* const inst{texture_inst.inst}; |
| 206 | inst->ReplaceOpcode(IndexedInstruction(*inst)); | ||
| 207 | |||
| 208 | const auto& cbuf{texture_inst.cbuf}; | ||
| 209 | auto flags{inst->Flags<IR::TextureInstInfo>()}; | ||
| 210 | if (inst->Opcode() == IR::Opcode::ImageQueryDimensions) { | ||
| 211 | flags.type.Assign(env.ReadTextureType(cbuf.index, cbuf.offset)); | ||
| 212 | inst->SetFlags(flags); | ||
| 213 | } | ||
| 201 | const u32 index{descriptors.Add(TextureDescriptor{ | 214 | const u32 index{descriptors.Add(TextureDescriptor{ |
| 202 | .type{inst->Flags<IR::TextureInstInfo>().type}, | 215 | .type{flags.type}, |
| 203 | .cbuf_index{texture_inst.cbuf.index}, | 216 | .cbuf_index{cbuf.index}, |
| 204 | .cbuf_offset{texture_inst.cbuf.offset}, | 217 | .cbuf_offset{cbuf.offset}, |
| 205 | .count{1}, | 218 | .count{1}, |
| 206 | })}; | 219 | })}; |
| 207 | inst->ReplaceOpcode(IndexedInstruction(*inst)); | ||
| 208 | inst->SetArg(0, IR::Value{index}); | 220 | inst->SetArg(0, IR::Value{index}); |
| 209 | } | 221 | } |
| 210 | } | 222 | } |