diff options
Diffstat (limited to 'src')
15 files changed, 264 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 | } |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 504b8c9d6..30d424346 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include "video_core/memory_manager.h" | 25 | #include "video_core/memory_manager.h" |
| 26 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" | 26 | #include "video_core/renderer_vulkan/fixed_pipeline_state.h" |
| 27 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" | 27 | #include "video_core/renderer_vulkan/maxwell_to_vk.h" |
| 28 | #include "video_core/renderer_vulkan/pipeline_helper.h" | ||
| 28 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" | 29 | #include "video_core/renderer_vulkan/vk_compute_pipeline.h" |
| 29 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" | 30 | #include "video_core/renderer_vulkan/vk_descriptor_pool.h" |
| 30 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" | 31 | #include "video_core/renderer_vulkan/vk_pipeline_cache.h" |
| @@ -45,6 +46,10 @@ auto MakeSpan(Container& container) { | |||
| 45 | return std::span(container.data(), container.size()); | 46 | return std::span(container.data(), container.size()); |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 49 | u64 MakeCbufKey(u32 index, u32 offset) { | ||
| 50 | return (static_cast<u64>(index) << 32) | static_cast<u64>(offset); | ||
| 51 | } | ||
| 52 | |||
| 48 | class GenericEnvironment : public Shader::Environment { | 53 | class GenericEnvironment : public Shader::Environment { |
| 49 | public: | 54 | public: |
| 50 | explicit GenericEnvironment() = default; | 55 | explicit GenericEnvironment() = default; |
| @@ -101,15 +106,21 @@ public: | |||
| 101 | const auto data{std::make_unique<char[]>(code_size)}; | 106 | const auto data{std::make_unique<char[]>(code_size)}; |
| 102 | gpu_memory->ReadBlock(program_base + read_lowest, data.get(), code_size); | 107 | gpu_memory->ReadBlock(program_base + read_lowest, data.get(), code_size); |
| 103 | 108 | ||
| 109 | const u64 num_texture_types{static_cast<u64>(texture_types.size())}; | ||
| 104 | const u32 texture_bound{TextureBoundBuffer()}; | 110 | const u32 texture_bound{TextureBoundBuffer()}; |
| 105 | 111 | ||
| 106 | file.write(reinterpret_cast<const char*>(&code_size), sizeof(code_size)) | 112 | file.write(reinterpret_cast<const char*>(&code_size), sizeof(code_size)) |
| 113 | .write(reinterpret_cast<const char*>(&num_texture_types), sizeof(num_texture_types)) | ||
| 107 | .write(reinterpret_cast<const char*>(&texture_bound), sizeof(texture_bound)) | 114 | .write(reinterpret_cast<const char*>(&texture_bound), sizeof(texture_bound)) |
| 108 | .write(reinterpret_cast<const char*>(&start_address), sizeof(start_address)) | 115 | .write(reinterpret_cast<const char*>(&start_address), sizeof(start_address)) |
| 109 | .write(reinterpret_cast<const char*>(&read_lowest), sizeof(read_lowest)) | 116 | .write(reinterpret_cast<const char*>(&read_lowest), sizeof(read_lowest)) |
| 110 | .write(reinterpret_cast<const char*>(&read_highest), sizeof(read_highest)) | 117 | .write(reinterpret_cast<const char*>(&read_highest), sizeof(read_highest)) |
| 111 | .write(reinterpret_cast<const char*>(&stage), sizeof(stage)) | 118 | .write(reinterpret_cast<const char*>(&stage), sizeof(stage)) |
| 112 | .write(data.get(), code_size); | 119 | .write(data.get(), code_size); |
| 120 | for (const auto [key, type] : texture_types) { | ||
| 121 | file.write(reinterpret_cast<const char*>(&key), sizeof(key)) | ||
| 122 | .write(reinterpret_cast<const char*>(&type), sizeof(type)); | ||
| 123 | } | ||
| 113 | if (stage == Shader::Stage::Compute) { | 124 | if (stage == Shader::Stage::Compute) { |
| 114 | const std::array<u32, 3> workgroup_size{WorkgroupSize()}; | 125 | const std::array<u32, 3> workgroup_size{WorkgroupSize()}; |
| 115 | file.write(reinterpret_cast<const char*>(&workgroup_size), sizeof(workgroup_size)); | 126 | file.write(reinterpret_cast<const char*>(&workgroup_size), sizeof(workgroup_size)); |
| @@ -147,10 +158,47 @@ protected: | |||
| 147 | return std::nullopt; | 158 | return std::nullopt; |
| 148 | } | 159 | } |
| 149 | 160 | ||
| 161 | Shader::TextureType ReadTextureTypeImpl(GPUVAddr tic_addr, u32 tic_limit, bool via_header_index, | ||
| 162 | GPUVAddr cbuf_addr, u32 cbuf_size, u32 cbuf_index, | ||
| 163 | u32 cbuf_offset) { | ||
| 164 | const u32 raw{cbuf_offset < cbuf_size ? gpu_memory->Read<u32>(cbuf_addr + cbuf_offset) : 0}; | ||
| 165 | const TextureHandle handle{raw, via_header_index}; | ||
| 166 | const GPUVAddr descriptor_addr{tic_addr + handle.image * sizeof(Tegra::Texture::TICEntry)}; | ||
| 167 | Tegra::Texture::TICEntry entry; | ||
| 168 | gpu_memory->ReadBlock(descriptor_addr, &entry, sizeof(entry)); | ||
| 169 | |||
| 170 | const Shader::TextureType result{[&] { | ||
| 171 | switch (entry.texture_type) { | ||
| 172 | case Tegra::Texture::TextureType::Texture1D: | ||
| 173 | return Shader::TextureType::Color1D; | ||
| 174 | case Tegra::Texture::TextureType::Texture2D: | ||
| 175 | case Tegra::Texture::TextureType::Texture2DNoMipmap: | ||
| 176 | return Shader::TextureType::Color2D; | ||
| 177 | case Tegra::Texture::TextureType::Texture3D: | ||
| 178 | return Shader::TextureType::Color3D; | ||
| 179 | case Tegra::Texture::TextureType::TextureCubemap: | ||
| 180 | return Shader::TextureType::ColorCube; | ||
| 181 | case Tegra::Texture::TextureType::Texture1DArray: | ||
| 182 | return Shader::TextureType::ColorArray1D; | ||
| 183 | case Tegra::Texture::TextureType::Texture2DArray: | ||
| 184 | return Shader::TextureType::ColorArray2D; | ||
| 185 | case Tegra::Texture::TextureType::Texture1DBuffer: | ||
| 186 | throw Shader::NotImplementedException("Texture buffer"); | ||
| 187 | case Tegra::Texture::TextureType::TextureCubeArray: | ||
| 188 | return Shader::TextureType::ColorArrayCube; | ||
| 189 | default: | ||
| 190 | throw Shader::NotImplementedException("Unknown texture type"); | ||
| 191 | } | ||
| 192 | }()}; | ||
| 193 | texture_types.emplace(MakeCbufKey(cbuf_index, cbuf_offset), result); | ||
| 194 | return result; | ||
| 195 | } | ||
| 196 | |||
| 150 | Tegra::MemoryManager* gpu_memory{}; | 197 | Tegra::MemoryManager* gpu_memory{}; |
| 151 | GPUVAddr program_base{}; | 198 | GPUVAddr program_base{}; |
| 152 | 199 | ||
| 153 | std::vector<u64> code; | 200 | std::vector<u64> code; |
| 201 | std::unordered_map<u64, Shader::TextureType> texture_types; | ||
| 154 | 202 | ||
| 155 | u32 read_lowest = std::numeric_limits<u32>::max(); | 203 | u32 read_lowest = std::numeric_limits<u32>::max(); |
| 156 | u32 read_highest = 0; | 204 | u32 read_highest = 0; |
| @@ -176,29 +224,45 @@ public: | |||
| 176 | switch (program) { | 224 | switch (program) { |
| 177 | case Maxwell::ShaderProgram::VertexA: | 225 | case Maxwell::ShaderProgram::VertexA: |
| 178 | stage = Shader::Stage::VertexA; | 226 | stage = Shader::Stage::VertexA; |
| 227 | stage_index = 0; | ||
| 179 | break; | 228 | break; |
| 180 | case Maxwell::ShaderProgram::VertexB: | 229 | case Maxwell::ShaderProgram::VertexB: |
| 181 | stage = Shader::Stage::VertexB; | 230 | stage = Shader::Stage::VertexB; |
| 231 | stage_index = 0; | ||
| 182 | break; | 232 | break; |
| 183 | case Maxwell::ShaderProgram::TesselationControl: | 233 | case Maxwell::ShaderProgram::TesselationControl: |
| 184 | stage = Shader::Stage::TessellationControl; | 234 | stage = Shader::Stage::TessellationControl; |
| 235 | stage_index = 1; | ||
| 185 | break; | 236 | break; |
| 186 | case Maxwell::ShaderProgram::TesselationEval: | 237 | case Maxwell::ShaderProgram::TesselationEval: |
| 187 | stage = Shader::Stage::TessellationEval; | 238 | stage = Shader::Stage::TessellationEval; |
| 239 | stage_index = 2; | ||
| 188 | break; | 240 | break; |
| 189 | case Maxwell::ShaderProgram::Geometry: | 241 | case Maxwell::ShaderProgram::Geometry: |
| 190 | stage = Shader::Stage::Geometry; | 242 | stage = Shader::Stage::Geometry; |
| 243 | stage_index = 3; | ||
| 191 | break; | 244 | break; |
| 192 | case Maxwell::ShaderProgram::Fragment: | 245 | case Maxwell::ShaderProgram::Fragment: |
| 193 | stage = Shader::Stage::Fragment; | 246 | stage = Shader::Stage::Fragment; |
| 247 | stage_index = 4; | ||
| 194 | break; | 248 | break; |
| 195 | default: | 249 | default: |
| 196 | UNREACHABLE_MSG("Invalid program={}", program); | 250 | UNREACHABLE_MSG("Invalid program={}", program); |
| 251 | break; | ||
| 197 | } | 252 | } |
| 198 | } | 253 | } |
| 199 | 254 | ||
| 200 | ~GraphicsEnvironment() override = default; | 255 | ~GraphicsEnvironment() override = default; |
| 201 | 256 | ||
| 257 | Shader::TextureType ReadTextureType(u32 cbuf_index, u32 cbuf_offset) override { | ||
| 258 | const auto& regs{maxwell3d->regs}; | ||
| 259 | const auto& cbuf{maxwell3d->state.shader_stages[stage_index].const_buffers[cbuf_index]}; | ||
| 260 | ASSERT(cbuf.enabled); | ||
| 261 | const bool via_header_index{regs.sampler_index == Maxwell::SamplerIndex::ViaHeaderIndex}; | ||
| 262 | return ReadTextureTypeImpl(regs.tic.Address(), regs.tic.limit, via_header_index, | ||
| 263 | cbuf.address, cbuf.size, cbuf_index, cbuf_offset); | ||
| 264 | } | ||
| 265 | |||
| 202 | u32 TextureBoundBuffer() const override { | 266 | u32 TextureBoundBuffer() const override { |
| 203 | return maxwell3d->regs.tex_cb_index; | 267 | return maxwell3d->regs.tex_cb_index; |
| 204 | } | 268 | } |
| @@ -209,6 +273,7 @@ public: | |||
| 209 | 273 | ||
| 210 | private: | 274 | private: |
| 211 | Tegra::Engines::Maxwell3D* maxwell3d{}; | 275 | Tegra::Engines::Maxwell3D* maxwell3d{}; |
| 276 | size_t stage_index{}; | ||
| 212 | }; | 277 | }; |
| 213 | 278 | ||
| 214 | class ComputeEnvironment final : public GenericEnvironment { | 279 | class ComputeEnvironment final : public GenericEnvironment { |
| @@ -224,6 +289,15 @@ public: | |||
| 224 | 289 | ||
| 225 | ~ComputeEnvironment() override = default; | 290 | ~ComputeEnvironment() override = default; |
| 226 | 291 | ||
| 292 | Shader::TextureType ReadTextureType(u32 cbuf_index, u32 cbuf_offset) override { | ||
| 293 | const auto& regs{kepler_compute->regs}; | ||
| 294 | const auto& qmd{kepler_compute->launch_description}; | ||
| 295 | ASSERT(((qmd.const_buffer_enable_mask.Value() >> cbuf_index) & 1) != 0); | ||
| 296 | const auto& cbuf{qmd.const_buffer_config[cbuf_index]}; | ||
| 297 | return ReadTextureTypeImpl(regs.tic.Address(), regs.tic.limit, qmd.linked_tsc != 0, | ||
| 298 | cbuf.Address(), cbuf.size, cbuf_index, cbuf_offset); | ||
| 299 | } | ||
| 300 | |||
| 227 | u32 TextureBoundBuffer() const override { | 301 | u32 TextureBoundBuffer() const override { |
| 228 | return kepler_compute->regs.tex_cb_index; | 302 | return kepler_compute->regs.tex_cb_index; |
| 229 | } | 303 | } |
| @@ -278,7 +352,9 @@ class FileEnvironment final : public Shader::Environment { | |||
| 278 | public: | 352 | public: |
| 279 | void Deserialize(std::ifstream& file) { | 353 | void Deserialize(std::ifstream& file) { |
| 280 | u64 code_size{}; | 354 | u64 code_size{}; |
| 355 | u64 num_texture_types{}; | ||
| 281 | file.read(reinterpret_cast<char*>(&code_size), sizeof(code_size)) | 356 | file.read(reinterpret_cast<char*>(&code_size), sizeof(code_size)) |
| 357 | .read(reinterpret_cast<char*>(&num_texture_types), sizeof(num_texture_types)) | ||
| 282 | .read(reinterpret_cast<char*>(&texture_bound), sizeof(texture_bound)) | 358 | .read(reinterpret_cast<char*>(&texture_bound), sizeof(texture_bound)) |
| 283 | .read(reinterpret_cast<char*>(&start_address), sizeof(start_address)) | 359 | .read(reinterpret_cast<char*>(&start_address), sizeof(start_address)) |
| 284 | .read(reinterpret_cast<char*>(&read_lowest), sizeof(read_lowest)) | 360 | .read(reinterpret_cast<char*>(&read_lowest), sizeof(read_lowest)) |
| @@ -286,6 +362,13 @@ public: | |||
| 286 | .read(reinterpret_cast<char*>(&stage), sizeof(stage)); | 362 | .read(reinterpret_cast<char*>(&stage), sizeof(stage)); |
| 287 | code = std::make_unique<u64[]>(Common::DivCeil(code_size, sizeof(u64))); | 363 | code = std::make_unique<u64[]>(Common::DivCeil(code_size, sizeof(u64))); |
| 288 | file.read(reinterpret_cast<char*>(code.get()), code_size); | 364 | file.read(reinterpret_cast<char*>(code.get()), code_size); |
| 365 | for (size_t i = 0; i < num_texture_types; ++i) { | ||
| 366 | u64 key; | ||
| 367 | Shader::TextureType type; | ||
| 368 | file.read(reinterpret_cast<char*>(&key), sizeof(key)) | ||
| 369 | .read(reinterpret_cast<char*>(&type), sizeof(type)); | ||
| 370 | texture_types.emplace(key, type); | ||
| 371 | } | ||
| 289 | if (stage == Shader::Stage::Compute) { | 372 | if (stage == Shader::Stage::Compute) { |
| 290 | file.read(reinterpret_cast<char*>(&workgroup_size), sizeof(workgroup_size)); | 373 | file.read(reinterpret_cast<char*>(&workgroup_size), sizeof(workgroup_size)); |
| 291 | } else { | 374 | } else { |
| @@ -300,6 +383,14 @@ public: | |||
| 300 | return code[(address - read_lowest) / sizeof(u64)]; | 383 | return code[(address - read_lowest) / sizeof(u64)]; |
| 301 | } | 384 | } |
| 302 | 385 | ||
| 386 | Shader::TextureType ReadTextureType(u32 cbuf_index, u32 cbuf_offset) override { | ||
| 387 | const auto it{texture_types.find(MakeCbufKey(cbuf_index, cbuf_offset))}; | ||
| 388 | if (it == texture_types.end()) { | ||
| 389 | throw Shader::LogicError("Uncached read texture type"); | ||
| 390 | } | ||
| 391 | return it->second; | ||
| 392 | } | ||
| 393 | |||
| 303 | u32 TextureBoundBuffer() const override { | 394 | u32 TextureBoundBuffer() const override { |
| 304 | return texture_bound; | 395 | return texture_bound; |
| 305 | } | 396 | } |
| @@ -310,6 +401,7 @@ public: | |||
| 310 | 401 | ||
| 311 | private: | 402 | private: |
| 312 | std::unique_ptr<u64[]> code; | 403 | std::unique_ptr<u64[]> code; |
| 404 | std::unordered_map<u64, Shader::TextureType> texture_types; | ||
| 313 | std::array<u32, 3> workgroup_size{}; | 405 | std::array<u32, 3> workgroup_size{}; |
| 314 | u32 texture_bound{}; | 406 | u32 texture_bound{}; |
| 315 | u32 read_lowest{}; | 407 | u32 read_lowest{}; |