diff options
Diffstat (limited to 'src/shader_recompiler')
23 files changed, 597 insertions, 137 deletions
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 6b5df23e2..8e1d37373 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt | |||
| @@ -133,6 +133,7 @@ add_library(shader_recompiler STATIC | |||
| 133 | frontend/maxwell/translate/impl/predicate_set_predicate.cpp | 133 | frontend/maxwell/translate/impl/predicate_set_predicate.cpp |
| 134 | frontend/maxwell/translate/impl/predicate_set_register.cpp | 134 | frontend/maxwell/translate/impl/predicate_set_register.cpp |
| 135 | frontend/maxwell/translate/impl/select_source_with_predicate.cpp | 135 | frontend/maxwell/translate/impl/select_source_with_predicate.cpp |
| 136 | frontend/maxwell/translate/impl/surface_load_store.cpp | ||
| 136 | frontend/maxwell/translate/impl/texture_fetch.cpp | 137 | frontend/maxwell/translate/impl/texture_fetch.cpp |
| 137 | frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp | 138 | frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp |
| 138 | frontend/maxwell/translate/impl/texture_gather_swizzled.cpp | 139 | frontend/maxwell/translate/impl/texture_gather_swizzled.cpp |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp index 0c114402b..32f8c4508 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/emit_context.cpp | |||
| @@ -18,41 +18,70 @@ namespace { | |||
| 18 | Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { | 18 | Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { |
| 19 | const spv::ImageFormat format{spv::ImageFormat::Unknown}; | 19 | const spv::ImageFormat format{spv::ImageFormat::Unknown}; |
| 20 | const Id type{ctx.F32[1]}; | 20 | const Id type{ctx.F32[1]}; |
| 21 | const bool depth{desc.is_depth}; | ||
| 21 | switch (desc.type) { | 22 | switch (desc.type) { |
| 22 | case TextureType::Color1D: | 23 | case TextureType::Color1D: |
| 23 | return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 1, format); | 24 | return ctx.TypeImage(type, spv::Dim::Dim1D, depth, false, false, 1, format); |
| 24 | case TextureType::ColorArray1D: | 25 | case TextureType::ColorArray1D: |
| 25 | return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 1, format); | 26 | return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format); |
| 26 | case TextureType::Color2D: | 27 | case TextureType::Color2D: |
| 27 | return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 1, format); | 28 | return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, false, 1, format); |
| 28 | case TextureType::ColorArray2D: | 29 | case TextureType::ColorArray2D: |
| 29 | return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 1, format); | 30 | return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, false, 1, format); |
| 30 | case TextureType::Color3D: | 31 | case TextureType::Color3D: |
| 31 | return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 1, format); | 32 | return ctx.TypeImage(type, spv::Dim::Dim3D, depth, false, false, 1, format); |
| 32 | case TextureType::ColorCube: | 33 | case TextureType::ColorCube: |
| 33 | return ctx.TypeImage(type, spv::Dim::Cube, false, false, false, 1, format); | 34 | return ctx.TypeImage(type, spv::Dim::Cube, depth, false, false, 1, format); |
| 34 | case TextureType::ColorArrayCube: | 35 | case TextureType::ColorArrayCube: |
| 35 | return ctx.TypeImage(type, spv::Dim::Cube, false, true, false, 1, format); | 36 | return ctx.TypeImage(type, spv::Dim::Cube, depth, true, false, 1, format); |
| 36 | case TextureType::Shadow1D: | ||
| 37 | return ctx.TypeImage(type, spv::Dim::Dim1D, true, false, false, 1, format); | ||
| 38 | case TextureType::ShadowArray1D: | ||
| 39 | return ctx.TypeImage(type, spv::Dim::Dim1D, true, true, false, 1, format); | ||
| 40 | case TextureType::Shadow2D: | ||
| 41 | return ctx.TypeImage(type, spv::Dim::Dim2D, true, false, false, 1, format); | ||
| 42 | case TextureType::ShadowArray2D: | ||
| 43 | return ctx.TypeImage(type, spv::Dim::Dim2D, true, true, false, 1, format); | ||
| 44 | case TextureType::Shadow3D: | ||
| 45 | return ctx.TypeImage(type, spv::Dim::Dim3D, true, false, false, 1, format); | ||
| 46 | case TextureType::ShadowCube: | ||
| 47 | return ctx.TypeImage(type, spv::Dim::Cube, true, false, false, 1, format); | ||
| 48 | case TextureType::ShadowArrayCube: | ||
| 49 | return ctx.TypeImage(type, spv::Dim::Cube, true, true, false, 1, format); | ||
| 50 | case TextureType::Buffer: | 37 | case TextureType::Buffer: |
| 51 | break; | 38 | break; |
| 52 | } | 39 | } |
| 53 | throw InvalidArgument("Invalid texture type {}", desc.type); | 40 | throw InvalidArgument("Invalid texture type {}", desc.type); |
| 54 | } | 41 | } |
| 55 | 42 | ||
| 43 | Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { | ||
| 44 | const spv::ImageFormat format{[&] { | ||
| 45 | switch (desc.format) { | ||
| 46 | case ImageFormat::Typeless: | ||
| 47 | return spv::ImageFormat::Unknown; | ||
| 48 | case ImageFormat::R8_UINT: | ||
| 49 | return spv::ImageFormat::R8ui; | ||
| 50 | case ImageFormat::R8_SINT: | ||
| 51 | return spv::ImageFormat::R8i; | ||
| 52 | case ImageFormat::R16_UINT: | ||
| 53 | return spv::ImageFormat::R16ui; | ||
| 54 | case ImageFormat::R16_SINT: | ||
| 55 | return spv::ImageFormat::R16i; | ||
| 56 | case ImageFormat::R32_UINT: | ||
| 57 | return spv::ImageFormat::R32ui; | ||
| 58 | case ImageFormat::R32G32_UINT: | ||
| 59 | return spv::ImageFormat::Rg32ui; | ||
| 60 | case ImageFormat::R32G32B32A32_UINT: | ||
| 61 | return spv::ImageFormat::Rgba32ui; | ||
| 62 | } | ||
| 63 | throw InvalidArgument("Invalid image format {}", desc.format); | ||
| 64 | }()}; | ||
| 65 | const Id type{ctx.U32[1]}; | ||
| 66 | switch (desc.type) { | ||
| 67 | case TextureType::Color1D: | ||
| 68 | return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 2, format); | ||
| 69 | case TextureType::ColorArray1D: | ||
| 70 | return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 2, format); | ||
| 71 | case TextureType::Color2D: | ||
| 72 | return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 2, format); | ||
| 73 | case TextureType::ColorArray2D: | ||
| 74 | return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 2, format); | ||
| 75 | case TextureType::Color3D: | ||
| 76 | return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 2, format); | ||
| 77 | case TextureType::Buffer: | ||
| 78 | throw NotImplementedException("Image buffer"); | ||
| 79 | default: | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | throw InvalidArgument("Invalid texture type {}", desc.type); | ||
| 83 | } | ||
| 84 | |||
| 56 | Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, | 85 | Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, |
| 57 | spv::StorageClass storage_class) { | 86 | spv::StorageClass storage_class) { |
| 58 | const Id pointer_type{ctx.TypePointer(storage_class, type)}; | 87 | const Id pointer_type{ctx.TypePointer(storage_class, type)}; |
| @@ -134,6 +163,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin | |||
| 134 | DefineStorageBuffers(program.info, binding); | 163 | DefineStorageBuffers(program.info, binding); |
| 135 | DefineTextureBuffers(program.info, binding); | 164 | DefineTextureBuffers(program.info, binding); |
| 136 | DefineTextures(program.info, binding); | 165 | DefineTextures(program.info, binding); |
| 166 | DefineImages(program.info, binding); | ||
| 137 | DefineAttributeMemAccess(program.info); | 167 | DefineAttributeMemAccess(program.info); |
| 138 | DefineLabels(program); | 168 | DefineLabels(program); |
| 139 | } | 169 | } |
| @@ -572,6 +602,31 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) { | |||
| 572 | } | 602 | } |
| 573 | } | 603 | } |
| 574 | 604 | ||
| 605 | void EmitContext::DefineImages(const Info& info, u32& binding) { | ||
| 606 | images.reserve(info.image_descriptors.size()); | ||
| 607 | for (const ImageDescriptor& desc : info.image_descriptors) { | ||
| 608 | if (desc.count != 1) { | ||
| 609 | throw NotImplementedException("Array of textures"); | ||
| 610 | } | ||
| 611 | const Id image_type{ImageType(*this, desc)}; | ||
| 612 | const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; | ||
| 613 | const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; | ||
| 614 | Decorate(id, spv::Decoration::Binding, binding); | ||
| 615 | Decorate(id, spv::Decoration::DescriptorSet, 0U); | ||
| 616 | Name(id, fmt::format("img{}_{:02x}", desc.cbuf_index, desc.cbuf_offset)); | ||
| 617 | for (u32 index = 0; index < desc.count; ++index) { | ||
| 618 | images.push_back(ImageDefinition{ | ||
| 619 | .id{id}, | ||
| 620 | .image_type{image_type}, | ||
| 621 | }); | ||
| 622 | } | ||
| 623 | if (profile.supported_spirv >= 0x00010400) { | ||
| 624 | interfaces.push_back(id); | ||
| 625 | } | ||
| 626 | binding += desc.count; | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 575 | void EmitContext::DefineLabels(IR::Program& program) { | 630 | void EmitContext::DefineLabels(IR::Program& program) { |
| 576 | for (IR::Block* const block : program.blocks) { | 631 | for (IR::Block* const block : program.blocks) { |
| 577 | block->SetDefinition(OpLabel()); | 632 | block->SetDefinition(OpLabel()); |
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h index f1ac4430c..e70f3458c 100644 --- a/src/shader_recompiler/backend/spirv/emit_context.h +++ b/src/shader_recompiler/backend/spirv/emit_context.h | |||
| @@ -35,6 +35,11 @@ struct TextureDefinition { | |||
| 35 | Id image_type; | 35 | Id image_type; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | struct ImageDefinition { | ||
| 39 | Id id; | ||
| 40 | Id image_type; | ||
| 41 | }; | ||
| 42 | |||
| 38 | struct UniformDefinitions { | 43 | struct UniformDefinitions { |
| 39 | Id U8{}; | 44 | Id U8{}; |
| 40 | Id S8{}; | 45 | Id S8{}; |
| @@ -95,8 +100,9 @@ public: | |||
| 95 | 100 | ||
| 96 | std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; | 101 | std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; |
| 97 | std::array<Id, Info::MAX_SSBOS> ssbos{}; | 102 | std::array<Id, Info::MAX_SSBOS> ssbos{}; |
| 98 | std::vector<TextureDefinition> textures; | ||
| 99 | std::vector<Id> texture_buffers; | 103 | std::vector<Id> texture_buffers; |
| 104 | std::vector<TextureDefinition> textures; | ||
| 105 | std::vector<ImageDefinition> images; | ||
| 100 | 106 | ||
| 101 | Id workgroup_id{}; | 107 | Id workgroup_id{}; |
| 102 | Id local_invocation_id{}; | 108 | Id local_invocation_id{}; |
| @@ -156,6 +162,7 @@ private: | |||
| 156 | void DefineStorageBuffers(const Info& info, u32& binding); | 162 | void DefineStorageBuffers(const Info& info, u32& binding); |
| 157 | void DefineTextureBuffers(const Info& info, u32& binding); | 163 | void DefineTextureBuffers(const Info& info, u32& binding); |
| 158 | void DefineTextures(const Info& info, u32& binding); | 164 | void DefineTextures(const Info& info, u32& binding); |
| 165 | void DefineImages(const Info& info, u32& binding); | ||
| 159 | void DefineAttributeMemAccess(const Info& info); | 166 | void DefineAttributeMemAccess(const Info& info); |
| 160 | void DefineLabels(IR::Program& program); | 167 | void DefineLabels(IR::Program& program); |
| 161 | 168 | ||
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 355cf0ca8..ecd0fac5c 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -253,6 +253,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct | |||
| 253 | ctx.AddCapability(spv::Capability::ImageGatherExtended); | 253 | ctx.AddCapability(spv::Capability::ImageGatherExtended); |
| 254 | ctx.AddCapability(spv::Capability::ImageQuery); | 254 | ctx.AddCapability(spv::Capability::ImageQuery); |
| 255 | ctx.AddCapability(spv::Capability::SampledBuffer); | 255 | ctx.AddCapability(spv::Capability::SampledBuffer); |
| 256 | ctx.AddCapability(spv::Capability::StorageImageReadWithoutFormat); | ||
| 256 | } | 257 | } |
| 257 | 258 | ||
| 258 | Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) { | 259 | Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) { |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.h b/src/shader_recompiler/backend/spirv/emit_spirv.h index 08460c94e..a39b16f1e 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv.h | |||
| @@ -369,6 +369,8 @@ Id EmitBindlessImageFetch(EmitContext&); | |||
| 369 | Id EmitBindlessImageQueryDimensions(EmitContext&); | 369 | Id EmitBindlessImageQueryDimensions(EmitContext&); |
| 370 | Id EmitBindlessImageQueryLod(EmitContext&); | 370 | Id EmitBindlessImageQueryLod(EmitContext&); |
| 371 | Id EmitBindlessImageGradient(EmitContext&); | 371 | Id EmitBindlessImageGradient(EmitContext&); |
| 372 | Id EmitBindlessImageRead(EmitContext&); | ||
| 373 | Id EmitBindlessImageWrite(EmitContext&); | ||
| 372 | Id EmitBoundImageSampleImplicitLod(EmitContext&); | 374 | Id EmitBoundImageSampleImplicitLod(EmitContext&); |
| 373 | Id EmitBoundImageSampleExplicitLod(EmitContext&); | 375 | Id EmitBoundImageSampleExplicitLod(EmitContext&); |
| 374 | Id EmitBoundImageSampleDrefImplicitLod(EmitContext&); | 376 | Id EmitBoundImageSampleDrefImplicitLod(EmitContext&); |
| @@ -379,6 +381,8 @@ Id EmitBoundImageFetch(EmitContext&); | |||
| 379 | Id EmitBoundImageQueryDimensions(EmitContext&); | 381 | Id EmitBoundImageQueryDimensions(EmitContext&); |
| 380 | Id EmitBoundImageQueryLod(EmitContext&); | 382 | Id EmitBoundImageQueryLod(EmitContext&); |
| 381 | Id EmitBoundImageGradient(EmitContext&); | 383 | Id EmitBoundImageGradient(EmitContext&); |
| 384 | Id EmitBoundImageRead(EmitContext&); | ||
| 385 | Id EmitBoundImageWrite(EmitContext&); | ||
| 382 | Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 386 | Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 383 | Id bias_lc, Id offset); | 387 | Id bias_lc, Id offset); |
| 384 | Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 388 | Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| @@ -397,6 +401,8 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i | |||
| 397 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); | 401 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); |
| 398 | Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 402 | Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 399 | Id derivates, Id offset, Id lod_clamp); | 403 | Id derivates, Id offset, Id lod_clamp); |
| 404 | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); | ||
| 405 | void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); | ||
| 400 | Id EmitVoteAll(EmitContext& ctx, Id pred); | 406 | Id EmitVoteAll(EmitContext& ctx, Id pred); |
| 401 | Id EmitVoteAny(EmitContext& ctx, Id pred); | 407 | Id EmitVoteAny(EmitContext& ctx, Id pred); |
| 402 | Id EmitVoteEqual(EmitContext& ctx, Id pred); | 408 | 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 6a89c0f79..dd261fd47 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |||
| @@ -144,6 +144,18 @@ Id TextureImage(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo in | |||
| 144 | } | 144 | } |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { | ||
| 148 | if (!index.IsImmediate()) { | ||
| 149 | throw NotImplementedException("Indirect image indexing"); | ||
| 150 | } | ||
| 151 | if (info.type == TextureType::Buffer) { | ||
| 152 | throw NotImplementedException("Image buffer"); | ||
| 153 | } else { | ||
| 154 | const ImageDefinition def{ctx.images.at(index.U32())}; | ||
| 155 | return ctx.OpLoad(def.image_type, def.id); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 147 | Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { | 159 | Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { |
| 148 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 160 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 149 | if (info.relaxed_precision != 0) { | 161 | if (info.relaxed_precision != 0) { |
| @@ -209,6 +221,14 @@ Id EmitBindlessImageGradient(EmitContext&) { | |||
| 209 | throw LogicError("Unreachable instruction"); | 221 | throw LogicError("Unreachable instruction"); |
| 210 | } | 222 | } |
| 211 | 223 | ||
| 224 | Id EmitBindlessImageRead(EmitContext&) { | ||
| 225 | throw LogicError("Unreachable instruction"); | ||
| 226 | } | ||
| 227 | |||
| 228 | Id EmitBindlessImageWrite(EmitContext&) { | ||
| 229 | throw LogicError("Unreachable instruction"); | ||
| 230 | } | ||
| 231 | |||
| 212 | Id EmitBoundImageSampleImplicitLod(EmitContext&) { | 232 | Id EmitBoundImageSampleImplicitLod(EmitContext&) { |
| 213 | throw LogicError("Unreachable instruction"); | 233 | throw LogicError("Unreachable instruction"); |
| 214 | } | 234 | } |
| @@ -249,6 +269,14 @@ Id EmitBoundImageGradient(EmitContext&) { | |||
| 249 | throw LogicError("Unreachable instruction"); | 269 | throw LogicError("Unreachable instruction"); |
| 250 | } | 270 | } |
| 251 | 271 | ||
| 272 | Id EmitBoundImageRead(EmitContext&) { | ||
| 273 | throw LogicError("Unreachable instruction"); | ||
| 274 | } | ||
| 275 | |||
| 276 | Id EmitBoundImageWrite(EmitContext&) { | ||
| 277 | throw LogicError("Unreachable instruction"); | ||
| 278 | } | ||
| 279 | |||
| 252 | Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 280 | Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 253 | Id bias_lc, Id offset) { | 281 | Id bias_lc, Id offset) { |
| 254 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 282 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| @@ -322,23 +350,16 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i | |||
| 322 | const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }}; | 350 | const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }}; |
| 323 | switch (info.type) { | 351 | switch (info.type) { |
| 324 | case TextureType::Color1D: | 352 | case TextureType::Color1D: |
| 325 | case TextureType::Shadow1D: | ||
| 326 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod), | 353 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[1], image, lod), |
| 327 | zero, zero, mips()); | 354 | zero, zero, mips()); |
| 328 | case TextureType::ColorArray1D: | 355 | case TextureType::ColorArray1D: |
| 329 | case TextureType::Color2D: | 356 | case TextureType::Color2D: |
| 330 | case TextureType::ColorCube: | 357 | case TextureType::ColorCube: |
| 331 | case TextureType::ShadowArray1D: | ||
| 332 | case TextureType::Shadow2D: | ||
| 333 | case TextureType::ShadowCube: | ||
| 334 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod), | 358 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod), |
| 335 | zero, mips()); | 359 | zero, mips()); |
| 336 | case TextureType::ColorArray2D: | 360 | case TextureType::ColorArray2D: |
| 337 | case TextureType::Color3D: | 361 | case TextureType::Color3D: |
| 338 | case TextureType::ColorArrayCube: | 362 | case TextureType::ColorArrayCube: |
| 339 | case TextureType::ShadowArray2D: | ||
| 340 | case TextureType::Shadow3D: | ||
| 341 | case TextureType::ShadowArrayCube: | ||
| 342 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod), | 363 | return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod), |
| 343 | mips()); | 364 | mips()); |
| 344 | case TextureType::Buffer: | 365 | case TextureType::Buffer: |
| @@ -365,4 +386,15 @@ Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I | |||
| 365 | coords, operands.Mask(), operands.Span()); | 386 | coords, operands.Mask(), operands.Span()); |
| 366 | } | 387 | } |
| 367 | 388 | ||
| 389 | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) { | ||
| 390 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||
| 391 | return Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, ctx.U32[4], | ||
| 392 | Image(ctx, index, info), coords, std::nullopt, std::span<const Id>{}); | ||
| 393 | } | ||
| 394 | |||
| 395 | void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { | ||
| 396 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | ||
| 397 | ctx.OpImageWrite(Image(ctx, index, info), coords, color); | ||
| 398 | } | ||
| 399 | |||
| 368 | } // namespace Shader::Backend::SPIRV | 400 | } // namespace Shader::Backend::SPIRV |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index a2104bdb3..17be0c639 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -1620,6 +1620,17 @@ Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const V | |||
| 1620 | return Inst(op, Flags{info}, handle, coords, derivates, offset, lod_clamp); | 1620 | return Inst(op, Flags{info}, handle, coords, derivates, offset, lod_clamp); |
| 1621 | } | 1621 | } |
| 1622 | 1622 | ||
| 1623 | Value IREmitter::ImageRead(const Value& handle, const Value& coords, TextureInstInfo info) { | ||
| 1624 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageRead : Opcode::BindlessImageRead}; | ||
| 1625 | return Inst(op, Flags{info}, handle, coords); | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | void IREmitter::ImageWrite(const Value& handle, const Value& coords, const Value& color, | ||
| 1629 | TextureInstInfo info) { | ||
| 1630 | const Opcode op{handle.IsImmediate() ? Opcode::BoundImageWrite : Opcode::BindlessImageWrite}; | ||
| 1631 | Inst(op, Flags{info}, handle, coords, color); | ||
| 1632 | } | ||
| 1633 | |||
| 1623 | U1 IREmitter::VoteAll(const U1& value) { | 1634 | U1 IREmitter::VoteAll(const U1& value) { |
| 1624 | return Inst<U1>(Opcode::VoteAll, value); | 1635 | return Inst<U1>(Opcode::VoteAll, value); |
| 1625 | } | 1636 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 2cab1dc5d..ec60070ef 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -265,20 +265,19 @@ public: | |||
| 265 | 265 | ||
| 266 | [[nodiscard]] Value ImageQueryLod(const Value& handle, const Value& coords, | 266 | [[nodiscard]] Value ImageQueryLod(const Value& handle, const Value& coords, |
| 267 | TextureInstInfo info); | 267 | TextureInstInfo info); |
| 268 | |||
| 269 | [[nodiscard]] Value ImageGather(const Value& handle, const Value& coords, const Value& offset, | 268 | [[nodiscard]] Value ImageGather(const Value& handle, const Value& coords, const Value& offset, |
| 270 | const Value& offset2, TextureInstInfo info); | 269 | const Value& offset2, TextureInstInfo info); |
| 271 | |||
| 272 | [[nodiscard]] Value ImageGatherDref(const Value& handle, const Value& coords, | 270 | [[nodiscard]] Value ImageGatherDref(const Value& handle, const Value& coords, |
| 273 | const Value& offset, const Value& offset2, const F32& dref, | 271 | const Value& offset, const Value& offset2, const F32& dref, |
| 274 | TextureInstInfo info); | 272 | TextureInstInfo info); |
| 275 | |||
| 276 | [[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset, | 273 | [[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset, |
| 277 | const U32& lod, const U32& multisampling, TextureInstInfo info); | 274 | const U32& lod, const U32& multisampling, TextureInstInfo info); |
| 278 | |||
| 279 | [[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords, | 275 | [[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords, |
| 280 | const Value& derivates, const Value& offset, | 276 | const Value& derivates, const Value& offset, |
| 281 | const F32& lod_clamp, TextureInstInfo info); | 277 | const F32& lod_clamp, TextureInstInfo info); |
| 278 | [[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info); | ||
| 279 | [[nodiscard]] void ImageWrite(const Value& handle, const Value& coords, const Value& color, | ||
| 280 | TextureInstInfo info); | ||
| 282 | 281 | ||
| 283 | [[nodiscard]] U1 VoteAll(const U1& value); | 282 | [[nodiscard]] U1 VoteAll(const U1& value); |
| 284 | [[nodiscard]] U1 VoteAny(const U1& value); | 283 | [[nodiscard]] U1 VoteAny(const U1& value); |
diff --git a/src/shader_recompiler/frontend/ir/modifiers.h b/src/shader_recompiler/frontend/ir/modifiers.h index 461671326..447e9703c 100644 --- a/src/shader_recompiler/frontend/ir/modifiers.h +++ b/src/shader_recompiler/frontend/ir/modifiers.h | |||
| @@ -43,11 +43,13 @@ static_assert(sizeof(FpControl) <= sizeof(u32)); | |||
| 43 | union TextureInstInfo { | 43 | union TextureInstInfo { |
| 44 | u32 raw; | 44 | u32 raw; |
| 45 | BitField<0, 8, TextureType> type; | 45 | BitField<0, 8, TextureType> type; |
| 46 | BitField<8, 1, u32> has_bias; | 46 | BitField<8, 1, u32> is_depth; |
| 47 | BitField<9, 1, u32> has_lod_clamp; | 47 | BitField<9, 1, u32> has_bias; |
| 48 | BitField<10, 1, u32> relaxed_precision; | 48 | BitField<10, 1, u32> has_lod_clamp; |
| 49 | BitField<11, 2, u32> gather_component; | 49 | BitField<11, 1, u32> relaxed_precision; |
| 50 | BitField<13, 2, u32> num_derivates; | 50 | BitField<12, 2, u32> gather_component; |
| 51 | BitField<14, 2, u32> num_derivates; | ||
| 52 | BitField<16, 3, ImageFormat> image_format; | ||
| 51 | }; | 53 | }; |
| 52 | static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); | 54 | static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); |
| 53 | 55 | ||
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 1697de965..82c5b37ba 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -389,6 +389,8 @@ OPCODE(BindlessImageFetch, F32x4, U32, | |||
| 389 | OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, ) | 389 | OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, ) |
| 390 | OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, ) | 390 | OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, ) |
| 391 | OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) | 391 | OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) |
| 392 | OPCODE(BindlessImageRead, U32x4, U32, Opaque, ) | ||
| 393 | OPCODE(BindlessImageWrite, Void, U32, Opaque, U32x4, ) | ||
| 392 | 394 | ||
| 393 | OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 395 | OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) |
| 394 | OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 396 | OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) |
| @@ -400,6 +402,8 @@ OPCODE(BoundImageFetch, F32x4, U32, | |||
| 400 | OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, ) | 402 | OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, ) |
| 401 | OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, ) | 403 | OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, ) |
| 402 | OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) | 404 | OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) |
| 405 | OPCODE(BoundImageRead, U32x4, U32, Opaque, ) | ||
| 406 | OPCODE(BoundImageWrite, Void, U32, Opaque, U32x4, ) | ||
| 403 | 407 | ||
| 404 | OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 408 | OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) |
| 405 | OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) | 409 | OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) |
| @@ -411,6 +415,8 @@ OPCODE(ImageFetch, F32x4, U32, | |||
| 411 | OPCODE(ImageQueryDimensions, U32x4, U32, U32, ) | 415 | OPCODE(ImageQueryDimensions, U32x4, U32, U32, ) |
| 412 | OPCODE(ImageQueryLod, F32x4, U32, Opaque, ) | 416 | OPCODE(ImageQueryLod, F32x4, U32, Opaque, ) |
| 413 | OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) | 417 | OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) |
| 418 | OPCODE(ImageRead, U32x4, U32, Opaque, ) | ||
| 419 | OPCODE(ImageWrite, Void, U32, Opaque, U32x4, ) | ||
| 414 | 420 | ||
| 415 | // Warp operations | 421 | // Warp operations |
| 416 | OPCODE(VoteAll, U1, U1, ) | 422 | 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 c23901052..327941223 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp | |||
| @@ -281,18 +281,10 @@ void TranslatorVisitor::SUATOM_cas(u64) { | |||
| 281 | ThrowNotImplemented(Opcode::SUATOM_cas); | 281 | ThrowNotImplemented(Opcode::SUATOM_cas); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | void TranslatorVisitor::SULD(u64) { | ||
| 285 | ThrowNotImplemented(Opcode::SULD); | ||
| 286 | } | ||
| 287 | |||
| 288 | void TranslatorVisitor::SURED(u64) { | 284 | void TranslatorVisitor::SURED(u64) { |
| 289 | ThrowNotImplemented(Opcode::SURED); | 285 | ThrowNotImplemented(Opcode::SURED); |
| 290 | } | 286 | } |
| 291 | 287 | ||
| 292 | void TranslatorVisitor::SUST(u64) { | ||
| 293 | ThrowNotImplemented(Opcode::SUST); | ||
| 294 | } | ||
| 295 | |||
| 296 | void TranslatorVisitor::SYNC(u64) { | 288 | void TranslatorVisitor::SYNC(u64) { |
| 297 | ThrowNotImplemented(Opcode::SYNC); | 289 | ThrowNotImplemented(Opcode::SYNC); |
| 298 | } | 290 | } |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/surface_load_store.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/surface_load_store.cpp new file mode 100644 index 000000000..9a2d16a6e --- /dev/null +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/surface_load_store.cpp | |||
| @@ -0,0 +1,280 @@ | |||
| 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 <array> | ||
| 6 | #include <bit> | ||
| 7 | |||
| 8 | #include "common/bit_field.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "shader_recompiler/frontend/ir/modifiers.h" | ||
| 11 | #include "shader_recompiler/frontend/maxwell/translate/impl/impl.h" | ||
| 12 | |||
| 13 | namespace Shader::Maxwell { | ||
| 14 | namespace { | ||
| 15 | enum class Type : u64 { | ||
| 16 | _1D, | ||
| 17 | BUFFER_1D, | ||
| 18 | ARRAY_1D, | ||
| 19 | _2D, | ||
| 20 | ARRAY_2D, | ||
| 21 | _3D, | ||
| 22 | }; | ||
| 23 | |||
| 24 | constexpr unsigned R = 1 << 0; | ||
| 25 | constexpr unsigned G = 1 << 1; | ||
| 26 | constexpr unsigned B = 1 << 2; | ||
| 27 | constexpr unsigned A = 1 << 3; | ||
| 28 | |||
| 29 | constexpr std::array MASK{ | ||
| 30 | 0U, // | ||
| 31 | R, // | ||
| 32 | G, // | ||
| 33 | R | G, // | ||
| 34 | B, // | ||
| 35 | R | B, // | ||
| 36 | G | B, // | ||
| 37 | R | G | B, // | ||
| 38 | A, // | ||
| 39 | R | A, // | ||
| 40 | G | A, // | ||
| 41 | R | G | A, // | ||
| 42 | B | A, // | ||
| 43 | R | B | A, // | ||
| 44 | G | B | A, // | ||
| 45 | R | G | B | A, // | ||
| 46 | }; | ||
| 47 | |||
| 48 | enum class Size : u64 { | ||
| 49 | U8, | ||
| 50 | S8, | ||
| 51 | U16, | ||
| 52 | S16, | ||
| 53 | B32, | ||
| 54 | B64, | ||
| 55 | B128, | ||
| 56 | }; | ||
| 57 | |||
| 58 | enum class Clamp : u64 { | ||
| 59 | IGN, | ||
| 60 | Default, | ||
| 61 | TRAP, | ||
| 62 | }; | ||
| 63 | |||
| 64 | enum class LoadCache : u64 { | ||
| 65 | Default, | ||
| 66 | CG, | ||
| 67 | CI, | ||
| 68 | CV, | ||
| 69 | }; | ||
| 70 | |||
| 71 | enum class StoreCache : u64 { | ||
| 72 | Default, | ||
| 73 | CG, | ||
| 74 | CS, | ||
| 75 | WT, | ||
| 76 | }; | ||
| 77 | |||
| 78 | ImageFormat Format(Size size) { | ||
| 79 | switch (size) { | ||
| 80 | case Size::U8: | ||
| 81 | return ImageFormat::R8_UINT; | ||
| 82 | case Size::S8: | ||
| 83 | return ImageFormat::R8_SINT; | ||
| 84 | case Size::U16: | ||
| 85 | return ImageFormat::R16_UINT; | ||
| 86 | case Size::S16: | ||
| 87 | return ImageFormat::R16_SINT; | ||
| 88 | case Size::B32: | ||
| 89 | return ImageFormat::R32_UINT; | ||
| 90 | case Size::B64: | ||
| 91 | return ImageFormat::R32G32_UINT; | ||
| 92 | case Size::B128: | ||
| 93 | return ImageFormat::R32G32B32A32_UINT; | ||
| 94 | } | ||
| 95 | throw NotImplementedException("Invalid size {}", size); | ||
| 96 | } | ||
| 97 | |||
| 98 | int SizeInRegs(Size size) { | ||
| 99 | switch (size) { | ||
| 100 | case Size::U8: | ||
| 101 | case Size::S8: | ||
| 102 | case Size::U16: | ||
| 103 | case Size::S16: | ||
| 104 | case Size::B32: | ||
| 105 | return 1; | ||
| 106 | case Size::B64: | ||
| 107 | return 2; | ||
| 108 | case Size::B128: | ||
| 109 | return 4; | ||
| 110 | } | ||
| 111 | throw NotImplementedException("Invalid size {}", size); | ||
| 112 | } | ||
| 113 | |||
| 114 | TextureType GetType(Type type) { | ||
| 115 | switch (type) { | ||
| 116 | case Type::_1D: | ||
| 117 | return TextureType::Color1D; | ||
| 118 | case Type::BUFFER_1D: | ||
| 119 | return TextureType::Buffer; | ||
| 120 | case Type::ARRAY_1D: | ||
| 121 | return TextureType::ColorArray1D; | ||
| 122 | case Type::_2D: | ||
| 123 | return TextureType::Color2D; | ||
| 124 | case Type::ARRAY_2D: | ||
| 125 | return TextureType::ColorArray2D; | ||
| 126 | case Type::_3D: | ||
| 127 | return TextureType::Color3D; | ||
| 128 | } | ||
| 129 | throw NotImplementedException("Invalid type {}", type); | ||
| 130 | } | ||
| 131 | |||
| 132 | IR::Value MakeCoords(TranslatorVisitor& v, IR::Reg reg, Type type) { | ||
| 133 | const auto array{[&](int index) { | ||
| 134 | return v.ir.BitFieldExtract(v.X(reg + index), v.ir.Imm32(0), v.ir.Imm32(16)); | ||
| 135 | }}; | ||
| 136 | switch (type) { | ||
| 137 | case Type::_1D: | ||
| 138 | case Type::BUFFER_1D: | ||
| 139 | return v.X(reg); | ||
| 140 | case Type::ARRAY_1D: | ||
| 141 | return v.ir.CompositeConstruct(v.X(reg), array(1)); | ||
| 142 | case Type::_2D: | ||
| 143 | return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1)); | ||
| 144 | case Type::ARRAY_2D: | ||
| 145 | return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), array(2)); | ||
| 146 | case Type::_3D: | ||
| 147 | return v.ir.CompositeConstruct(v.X(reg), v.X(reg + 1), v.X(reg + 3)); | ||
| 148 | } | ||
| 149 | throw NotImplementedException("Invalid type {}", type); | ||
| 150 | } | ||
| 151 | |||
| 152 | unsigned SwizzleMask(u64 swizzle) { | ||
| 153 | if (swizzle == 0 || swizzle >= MASK.size()) { | ||
| 154 | throw NotImplementedException("Invalid swizzle {}", swizzle); | ||
| 155 | } | ||
| 156 | return MASK[swizzle]; | ||
| 157 | } | ||
| 158 | |||
| 159 | IR::Value MakeColor(IR::IREmitter& ir, IR::Reg reg, int num_regs) { | ||
| 160 | std::array<IR::U32, 4> colors; | ||
| 161 | for (int i = 0; i < num_regs; ++i) { | ||
| 162 | colors[i] = ir.GetReg(reg + i); | ||
| 163 | } | ||
| 164 | for (int i = num_regs; i < 4; ++i) { | ||
| 165 | colors[i] = ir.Imm32(0); | ||
| 166 | } | ||
| 167 | return ir.CompositeConstruct(colors[0], colors[1], colors[2], colors[3]); | ||
| 168 | } | ||
| 169 | } // Anonymous namespace | ||
| 170 | |||
| 171 | void TranslatorVisitor::SULD(u64 insn) { | ||
| 172 | union { | ||
| 173 | u64 raw; | ||
| 174 | BitField<51, 1, u64> is_bound; | ||
| 175 | BitField<52, 1, u64> d; | ||
| 176 | BitField<23, 1, u64> ba; | ||
| 177 | BitField<33, 3, Type> type; | ||
| 178 | BitField<24, 2, LoadCache> cache; | ||
| 179 | BitField<20, 3, Size> size; // .D | ||
| 180 | BitField<20, 4, u64> swizzle; // .P | ||
| 181 | BitField<49, 2, Clamp> clamp; | ||
| 182 | BitField<0, 8, IR::Reg> dest_reg; | ||
| 183 | BitField<8, 8, IR::Reg> coord_reg; | ||
| 184 | BitField<36, 13, u64> bound_offset; // is_bound | ||
| 185 | BitField<39, 8, IR::Reg> bindless_reg; // !is_bound | ||
| 186 | } const suld{insn}; | ||
| 187 | |||
| 188 | if (suld.clamp != Clamp::IGN) { | ||
| 189 | throw NotImplementedException("Clamp {}", suld.clamp.Value()); | ||
| 190 | } | ||
| 191 | if (suld.cache != LoadCache::Default) { | ||
| 192 | throw NotImplementedException("Cache {}", suld.cache.Value()); | ||
| 193 | } | ||
| 194 | const bool is_typed{suld.d != 0}; | ||
| 195 | if (is_typed && suld.ba != 0) { | ||
| 196 | throw NotImplementedException("BA"); | ||
| 197 | } | ||
| 198 | |||
| 199 | const ImageFormat format{is_typed ? Format(suld.size) : ImageFormat::Typeless}; | ||
| 200 | const TextureType type{GetType(suld.type)}; | ||
| 201 | const IR::Value coords{MakeCoords(*this, suld.coord_reg, suld.type)}; | ||
| 202 | const IR::U32 handle{suld.is_bound != 0 ? ir.Imm32(static_cast<u32>(suld.bound_offset * 4)) | ||
| 203 | : X(suld.bindless_reg)}; | ||
| 204 | IR::TextureInstInfo info{}; | ||
| 205 | info.type.Assign(type); | ||
| 206 | info.image_format.Assign(format); | ||
| 207 | |||
| 208 | const IR::Value result{ir.ImageRead(handle, coords, info)}; | ||
| 209 | IR::Reg dest_reg{suld.dest_reg}; | ||
| 210 | if (is_typed) { | ||
| 211 | const int num_regs{SizeInRegs(suld.size)}; | ||
| 212 | for (int i = 0; i < num_regs; ++i) { | ||
| 213 | X(dest_reg + i, IR::U32{ir.CompositeExtract(result, i)}); | ||
| 214 | } | ||
| 215 | } else { | ||
| 216 | const unsigned mask{SwizzleMask(suld.swizzle)}; | ||
| 217 | const int bits{std::popcount(mask)}; | ||
| 218 | if (!IR::IsAligned(dest_reg, bits == 3 ? 4 : bits)) { | ||
| 219 | throw NotImplementedException("Unaligned destination register"); | ||
| 220 | } | ||
| 221 | for (unsigned component = 0; component < 4; ++component) { | ||
| 222 | if (((mask >> component) & 1) == 0) { | ||
| 223 | continue; | ||
| 224 | } | ||
| 225 | X(dest_reg, IR::U32{ir.CompositeExtract(result, component)}); | ||
| 226 | ++dest_reg; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | void TranslatorVisitor::SUST(u64 insn) { | ||
| 232 | union { | ||
| 233 | u64 raw; | ||
| 234 | BitField<51, 1, u64> is_bound; | ||
| 235 | BitField<52, 1, u64> d; | ||
| 236 | BitField<23, 1, u64> ba; | ||
| 237 | BitField<33, 3, Type> type; | ||
| 238 | BitField<24, 2, StoreCache> cache; | ||
| 239 | BitField<20, 3, Size> size; // .D | ||
| 240 | BitField<20, 4, u64> swizzle; // .P | ||
| 241 | BitField<49, 2, Clamp> clamp; | ||
| 242 | BitField<0, 8, IR::Reg> data_reg; | ||
| 243 | BitField<8, 8, IR::Reg> coord_reg; | ||
| 244 | BitField<36, 13, u64> bound_offset; // is_bound | ||
| 245 | BitField<39, 8, IR::Reg> bindless_reg; // !is_bound | ||
| 246 | } const sust{insn}; | ||
| 247 | |||
| 248 | if (sust.clamp != Clamp::IGN) { | ||
| 249 | throw NotImplementedException("Clamp {}", sust.clamp.Value()); | ||
| 250 | } | ||
| 251 | if (sust.cache != StoreCache::Default) { | ||
| 252 | throw NotImplementedException("Cache {}", sust.cache.Value()); | ||
| 253 | } | ||
| 254 | const bool is_typed{sust.d != 0}; | ||
| 255 | if (is_typed && sust.ba != 0) { | ||
| 256 | throw NotImplementedException("BA"); | ||
| 257 | } | ||
| 258 | const ImageFormat format{is_typed ? Format(sust.size) : ImageFormat::Typeless}; | ||
| 259 | const TextureType type{GetType(sust.type)}; | ||
| 260 | const IR::Value coords{MakeCoords(*this, sust.coord_reg, sust.type)}; | ||
| 261 | const IR::U32 handle{sust.is_bound != 0 ? ir.Imm32(static_cast<u32>(sust.bound_offset * 4)) | ||
| 262 | : X(sust.bindless_reg)}; | ||
| 263 | IR::TextureInstInfo info{}; | ||
| 264 | info.type.Assign(type); | ||
| 265 | info.image_format.Assign(format); | ||
| 266 | |||
| 267 | IR::Value color; | ||
| 268 | if (is_typed) { | ||
| 269 | color = MakeColor(ir, sust.data_reg, SizeInRegs(sust.size)); | ||
| 270 | } else { | ||
| 271 | const unsigned mask{SwizzleMask(sust.swizzle)}; | ||
| 272 | if (mask != 0xf) { | ||
| 273 | throw NotImplementedException("Non-full mask"); | ||
| 274 | } | ||
| 275 | color = MakeColor(ir, sust.data_reg, 4); | ||
| 276 | } | ||
| 277 | ir.ImageWrite(handle, coords, color, info); | ||
| 278 | } | ||
| 279 | |||
| 280 | } // namespace Shader::Maxwell | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp index 95d416586..9671d115e 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp | |||
| @@ -33,24 +33,24 @@ enum class TextureType : u64 { | |||
| 33 | ARRAY_CUBE, | 33 | ARRAY_CUBE, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | Shader::TextureType GetType(TextureType type, bool dc) { | 36 | Shader::TextureType GetType(TextureType type) { |
| 37 | switch (type) { | 37 | switch (type) { |
| 38 | case TextureType::_1D: | 38 | case TextureType::_1D: |
| 39 | return dc ? Shader::TextureType::Shadow1D : Shader::TextureType::Color1D; | 39 | return Shader::TextureType::Color1D; |
| 40 | case TextureType::ARRAY_1D: | 40 | case TextureType::ARRAY_1D: |
| 41 | return dc ? Shader::TextureType::ShadowArray1D : Shader::TextureType::ColorArray1D; | 41 | return Shader::TextureType::ColorArray1D; |
| 42 | case TextureType::_2D: | 42 | case TextureType::_2D: |
| 43 | return dc ? Shader::TextureType::Shadow2D : Shader::TextureType::Color2D; | 43 | return Shader::TextureType::Color2D; |
| 44 | case TextureType::ARRAY_2D: | 44 | case TextureType::ARRAY_2D: |
| 45 | return dc ? Shader::TextureType::ShadowArray2D : Shader::TextureType::ColorArray2D; | 45 | return Shader::TextureType::ColorArray2D; |
| 46 | case TextureType::_3D: | 46 | case TextureType::_3D: |
| 47 | return dc ? Shader::TextureType::Shadow3D : Shader::TextureType::Color3D; | 47 | return Shader::TextureType::Color3D; |
| 48 | case TextureType::ARRAY_3D: | 48 | case TextureType::ARRAY_3D: |
| 49 | throw NotImplementedException("3D array texture type"); | 49 | throw NotImplementedException("3D array texture type"); |
| 50 | case TextureType::CUBE: | 50 | case TextureType::CUBE: |
| 51 | return dc ? Shader::TextureType::ShadowCube : Shader::TextureType::ColorCube; | 51 | return Shader::TextureType::ColorCube; |
| 52 | case TextureType::ARRAY_CUBE: | 52 | case TextureType::ARRAY_CUBE: |
| 53 | return dc ? Shader::TextureType::ShadowArrayCube : Shader::TextureType::ColorArrayCube; | 53 | return Shader::TextureType::ColorArrayCube; |
| 54 | } | 54 | } |
| 55 | throw NotImplementedException("Invalid texture type {}", type); | 55 | throw NotImplementedException("Invalid texture type {}", type); |
| 56 | } | 56 | } |
| @@ -169,7 +169,8 @@ void Impl(TranslatorVisitor& v, u64 insn, bool aoffi, Blod blod, bool lc, | |||
| 169 | dref = v.F(meta_reg++); | 169 | dref = v.F(meta_reg++); |
| 170 | } | 170 | } |
| 171 | IR::TextureInstInfo info{}; | 171 | IR::TextureInstInfo info{}; |
| 172 | info.type.Assign(GetType(tex.type, tex.dc != 0)); | 172 | info.type.Assign(GetType(tex.type)); |
| 173 | info.is_depth.Assign(tex.dc != 0 ? 1 : 0); | ||
| 173 | info.has_bias.Assign(blod == Blod::LB || blod == Blod::LBA ? 1 : 0); | 174 | info.has_bias.Assign(blod == Blod::LB || blod == Blod::LBA ? 1 : 0); |
| 174 | info.has_lod_clamp.Assign(lc ? 1 : 0); | 175 | info.has_lod_clamp.Assign(lc ? 1 : 0); |
| 175 | 176 | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp index fe2c7db85..3500a4559 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp | |||
| @@ -95,18 +95,21 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) { | |||
| 95 | {}, info); | 95 | {}, info); |
| 96 | case 4: // 2D.DC | 96 | case 4: // 2D.DC |
| 97 | CheckAlignment(reg_a, 2); | 97 | CheckAlignment(reg_a, 2); |
| 98 | info.type.Assign(TextureType::Shadow2D); | 98 | info.type.Assign(TextureType::Color2D); |
| 99 | info.is_depth.Assign(1); | ||
| 99 | return v.ir.ImageSampleDrefImplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), | 100 | return v.ir.ImageSampleDrefImplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), |
| 100 | {}, {}, {}, info); | 101 | {}, {}, {}, info); |
| 101 | case 5: // 2D.LL.DC | 102 | case 5: // 2D.LL.DC |
| 102 | CheckAlignment(reg_a, 2); | 103 | CheckAlignment(reg_a, 2); |
| 103 | CheckAlignment(reg_b, 2); | 104 | CheckAlignment(reg_b, 2); |
| 104 | info.type.Assign(TextureType::Shadow2D); | 105 | info.type.Assign(TextureType::Color2D); |
| 106 | info.is_depth.Assign(1); | ||
| 105 | return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), | 107 | return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), |
| 106 | v.F(reg_b + 1), v.F(reg_b), {}, {}, info); | 108 | v.F(reg_b + 1), v.F(reg_b), {}, {}, info); |
| 107 | case 6: // 2D.LZ.DC | 109 | case 6: // 2D.LZ.DC |
| 108 | CheckAlignment(reg_a, 2); | 110 | CheckAlignment(reg_a, 2); |
| 109 | info.type.Assign(TextureType::Shadow2D); | 111 | info.type.Assign(TextureType::Color2D); |
| 112 | info.is_depth.Assign(1); | ||
| 110 | return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), | 113 | return v.ir.ImageSampleDrefExplicitLod(handle, Composite(v, reg_a, reg_a + 1), v.F(reg_b), |
| 111 | zero, {}, {}, info); | 114 | zero, {}, {}, info); |
| 112 | case 7: // ARRAY_2D | 115 | case 7: // ARRAY_2D |
| @@ -124,7 +127,8 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) { | |||
| 124 | case 9: // ARRAY_2D.LZ.DC | 127 | case 9: // ARRAY_2D.LZ.DC |
| 125 | CheckAlignment(reg_a, 2); | 128 | CheckAlignment(reg_a, 2); |
| 126 | CheckAlignment(reg_b, 2); | 129 | CheckAlignment(reg_b, 2); |
| 127 | info.type.Assign(TextureType::ShadowArray2D); | 130 | info.type.Assign(TextureType::ColorArray2D); |
| 131 | info.is_depth.Assign(1); | ||
| 128 | return v.ir.ImageSampleDrefExplicitLod( | 132 | return v.ir.ImageSampleDrefExplicitLod( |
| 129 | handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))), | 133 | handle, v.ir.CompositeConstruct(v.F(reg_a + 1), v.F(reg_b), ReadArray(v, v.X(reg_a))), |
| 130 | v.F(reg_b + 1), zero, {}, {}, info); | 134 | v.F(reg_b + 1), zero, {}, {}, info); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather.cpp index b2f9cda46..218cbc1a8 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather.cpp | |||
| @@ -37,24 +37,24 @@ enum class ComponentType : u64 { | |||
| 37 | A = 3, | 37 | A = 3, |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | Shader::TextureType GetType(TextureType type, bool dc) { | 40 | Shader::TextureType GetType(TextureType type) { |
| 41 | switch (type) { | 41 | switch (type) { |
| 42 | case TextureType::_1D: | 42 | case TextureType::_1D: |
| 43 | return dc ? Shader::TextureType::Shadow1D : Shader::TextureType::Color1D; | 43 | return Shader::TextureType::Color1D; |
| 44 | case TextureType::ARRAY_1D: | 44 | case TextureType::ARRAY_1D: |
| 45 | return dc ? Shader::TextureType::ShadowArray1D : Shader::TextureType::ColorArray1D; | 45 | return Shader::TextureType::ColorArray1D; |
| 46 | case TextureType::_2D: | 46 | case TextureType::_2D: |
| 47 | return dc ? Shader::TextureType::Shadow2D : Shader::TextureType::Color2D; | 47 | return Shader::TextureType::Color2D; |
| 48 | case TextureType::ARRAY_2D: | 48 | case TextureType::ARRAY_2D: |
| 49 | return dc ? Shader::TextureType::ShadowArray2D : Shader::TextureType::ColorArray2D; | 49 | return Shader::TextureType::ColorArray2D; |
| 50 | case TextureType::_3D: | 50 | case TextureType::_3D: |
| 51 | return dc ? Shader::TextureType::Shadow3D : Shader::TextureType::Color3D; | 51 | return Shader::TextureType::Color3D; |
| 52 | case TextureType::ARRAY_3D: | 52 | case TextureType::ARRAY_3D: |
| 53 | throw NotImplementedException("3D array texture type"); | 53 | throw NotImplementedException("3D array texture type"); |
| 54 | case TextureType::CUBE: | 54 | case TextureType::CUBE: |
| 55 | return dc ? Shader::TextureType::ShadowCube : Shader::TextureType::ColorCube; | 55 | return Shader::TextureType::ColorCube; |
| 56 | case TextureType::ARRAY_CUBE: | 56 | case TextureType::ARRAY_CUBE: |
| 57 | return dc ? Shader::TextureType::ShadowArrayCube : Shader::TextureType::ColorArrayCube; | 57 | return Shader::TextureType::ColorArrayCube; |
| 58 | } | 58 | } |
| 59 | throw NotImplementedException("Invalid texture type {}", type); | 59 | throw NotImplementedException("Invalid texture type {}", type); |
| 60 | } | 60 | } |
| @@ -163,7 +163,8 @@ void Impl(TranslatorVisitor& v, u64 insn, ComponentType component_type, OffsetTy | |||
| 163 | dref = v.F(meta_reg++); | 163 | dref = v.F(meta_reg++); |
| 164 | } | 164 | } |
| 165 | IR::TextureInstInfo info{}; | 165 | IR::TextureInstInfo info{}; |
| 166 | info.type.Assign(GetType(tld4.type, tld4.dc != 0)); | 166 | info.type.Assign(GetType(tld4.type)); |
| 167 | info.is_depth.Assign(tld4.dc != 0 ? 1 : 0); | ||
| 167 | info.gather_component.Assign(static_cast<u32>(component_type)); | 168 | info.gather_component.Assign(static_cast<u32>(component_type)); |
| 168 | const IR::Value sample{[&] { | 169 | const IR::Value sample{[&] { |
| 169 | if (tld4.dc == 0) { | 170 | if (tld4.dc == 0) { |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather_swizzled.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather_swizzled.cpp index 2ba9c1018..34efa2d50 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather_swizzled.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather_swizzled.cpp | |||
| @@ -59,7 +59,8 @@ IR::Value Sample(TranslatorVisitor& v, u64 insn) { | |||
| 59 | info.relaxed_precision.Assign(1); | 59 | info.relaxed_precision.Assign(1); |
| 60 | } | 60 | } |
| 61 | info.gather_component.Assign(static_cast<u32>(tld4s.component_type.Value())); | 61 | info.gather_component.Assign(static_cast<u32>(tld4s.component_type.Value())); |
| 62 | info.type.Assign(tld4s.dc != 0 ? Shader::TextureType::Shadow2D : Shader::TextureType::Color2D); | 62 | info.type.Assign(Shader::TextureType::Color2D); |
| 63 | info.is_depth.Assign(tld4s.dc != 0 ? 1 : 0); | ||
| 63 | IR::Value coords; | 64 | IR::Value coords; |
| 64 | if (tld4s.aoffi != 0) { | 65 | if (tld4s.aoffi != 0) { |
| 65 | CheckAlignment(reg_a, 2); | 66 | CheckAlignment(reg_a, 2); |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp index c66468a48..c3fe3ffda 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp | |||
| @@ -23,24 +23,24 @@ enum class TextureType : u64 { | |||
| 23 | ARRAY_CUBE, | 23 | ARRAY_CUBE, |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | Shader::TextureType GetType(TextureType type, bool dc) { | 26 | Shader::TextureType GetType(TextureType type) { |
| 27 | switch (type) { | 27 | switch (type) { |
| 28 | case TextureType::_1D: | 28 | case TextureType::_1D: |
| 29 | return dc ? Shader::TextureType::Shadow1D : Shader::TextureType::Color1D; | 29 | return Shader::TextureType::Color1D; |
| 30 | case TextureType::ARRAY_1D: | 30 | case TextureType::ARRAY_1D: |
| 31 | return dc ? Shader::TextureType::ShadowArray1D : Shader::TextureType::ColorArray1D; | 31 | return Shader::TextureType::ColorArray1D; |
| 32 | case TextureType::_2D: | 32 | case TextureType::_2D: |
| 33 | return dc ? Shader::TextureType::Shadow2D : Shader::TextureType::Color2D; | 33 | return Shader::TextureType::Color2D; |
| 34 | case TextureType::ARRAY_2D: | 34 | case TextureType::ARRAY_2D: |
| 35 | return dc ? Shader::TextureType::ShadowArray2D : Shader::TextureType::ColorArray2D; | 35 | return Shader::TextureType::ColorArray2D; |
| 36 | case TextureType::_3D: | 36 | case TextureType::_3D: |
| 37 | return dc ? Shader::TextureType::Shadow3D : Shader::TextureType::Color3D; | 37 | return Shader::TextureType::Color3D; |
| 38 | case TextureType::ARRAY_3D: | 38 | case TextureType::ARRAY_3D: |
| 39 | throw NotImplementedException("3D array texture type"); | 39 | throw NotImplementedException("3D array texture type"); |
| 40 | case TextureType::CUBE: | 40 | case TextureType::CUBE: |
| 41 | return dc ? Shader::TextureType::ShadowCube : Shader::TextureType::ColorCube; | 41 | return Shader::TextureType::ColorCube; |
| 42 | case TextureType::ARRAY_CUBE: | 42 | case TextureType::ARRAY_CUBE: |
| 43 | return dc ? Shader::TextureType::ShadowArrayCube : Shader::TextureType::ColorArrayCube; | 43 | return Shader::TextureType::ColorArrayCube; |
| 44 | } | 44 | } |
| 45 | throw NotImplementedException("Invalid texture type {}", type); | 45 | throw NotImplementedException("Invalid texture type {}", type); |
| 46 | } | 46 | } |
| @@ -152,7 +152,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) { | |||
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | IR::TextureInstInfo info{}; | 154 | IR::TextureInstInfo info{}; |
| 155 | info.type.Assign(GetType(txd.type, false)); | 155 | info.type.Assign(GetType(txd.type)); |
| 156 | info.num_derivates.Assign(num_derivates); | 156 | info.num_derivates.Assign(num_derivates); |
| 157 | info.has_lod_clamp.Assign(has_lod_clamp ? 1 : 0); | 157 | info.has_lod_clamp.Assign(has_lod_clamp ? 1 : 0); |
| 158 | const IR::Value sample{v.ir.ImageGradient(handle, coords, derivates, offset, lod_clamp, info)}; | 158 | const IR::Value sample{v.ir.ImageGradient(handle, coords, derivates, offset, lod_clamp, info)}; |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp index 987b7ec34..983058303 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp | |||
| @@ -23,24 +23,24 @@ enum class TextureType : u64 { | |||
| 23 | ARRAY_CUBE, | 23 | ARRAY_CUBE, |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | Shader::TextureType GetType(TextureType type, bool dc) { | 26 | Shader::TextureType GetType(TextureType type) { |
| 27 | switch (type) { | 27 | switch (type) { |
| 28 | case TextureType::_1D: | 28 | case TextureType::_1D: |
| 29 | return dc ? Shader::TextureType::Shadow1D : Shader::TextureType::Color1D; | 29 | return Shader::TextureType::Color1D; |
| 30 | case TextureType::ARRAY_1D: | 30 | case TextureType::ARRAY_1D: |
| 31 | return dc ? Shader::TextureType::ShadowArray1D : Shader::TextureType::ColorArray1D; | 31 | return Shader::TextureType::ColorArray1D; |
| 32 | case TextureType::_2D: | 32 | case TextureType::_2D: |
| 33 | return dc ? Shader::TextureType::Shadow2D : Shader::TextureType::Color2D; | 33 | return Shader::TextureType::Color2D; |
| 34 | case TextureType::ARRAY_2D: | 34 | case TextureType::ARRAY_2D: |
| 35 | return dc ? Shader::TextureType::ShadowArray2D : Shader::TextureType::ColorArray2D; | 35 | return Shader::TextureType::ColorArray2D; |
| 36 | case TextureType::_3D: | 36 | case TextureType::_3D: |
| 37 | return dc ? Shader::TextureType::Shadow3D : Shader::TextureType::Color3D; | 37 | return Shader::TextureType::Color3D; |
| 38 | case TextureType::ARRAY_3D: | 38 | case TextureType::ARRAY_3D: |
| 39 | throw NotImplementedException("3D array texture type"); | 39 | throw NotImplementedException("3D array texture type"); |
| 40 | case TextureType::CUBE: | 40 | case TextureType::CUBE: |
| 41 | return dc ? Shader::TextureType::ShadowCube : Shader::TextureType::ColorCube; | 41 | return Shader::TextureType::ColorCube; |
| 42 | case TextureType::ARRAY_CUBE: | 42 | case TextureType::ARRAY_CUBE: |
| 43 | return dc ? Shader::TextureType::ShadowArrayCube : Shader::TextureType::ColorArrayCube; | 43 | return Shader::TextureType::ColorArrayCube; |
| 44 | } | 44 | } |
| 45 | throw NotImplementedException("Invalid texture type {}", type); | 45 | throw NotImplementedException("Invalid texture type {}", type); |
| 46 | } | 46 | } |
| @@ -137,7 +137,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) { | |||
| 137 | throw NotImplementedException("TLD.CL - CLAMP is not implmented"); | 137 | throw NotImplementedException("TLD.CL - CLAMP is not implmented"); |
| 138 | } | 138 | } |
| 139 | IR::TextureInstInfo info{}; | 139 | IR::TextureInstInfo info{}; |
| 140 | info.type.Assign(GetType(tld.type, false)); | 140 | info.type.Assign(GetType(tld.type)); |
| 141 | const IR::Value sample{v.ir.ImageFetch(handle, coords, offset, lod, multisample, info)}; | 141 | const IR::Value sample{v.ir.ImageFetch(handle, coords, offset, lod, multisample, info)}; |
| 142 | 142 | ||
| 143 | IR::Reg dest_reg{tld.dest_reg}; | 143 | IR::Reg dest_reg{tld.dest_reg}; |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load_swizzled.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load_swizzled.cpp index 0863bdfcd..5dd7e31b2 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load_swizzled.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_load_swizzled.cpp | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <utility> | 5 | #include <array> |
| 6 | 6 | ||
| 7 | #include "common/bit_field.h" | 7 | #include "common/bit_field.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp index b6efc04f0..2277d24ff 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp | |||
| @@ -23,24 +23,24 @@ enum class TextureType : u64 { | |||
| 23 | ARRAY_CUBE, | 23 | ARRAY_CUBE, |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | Shader::TextureType GetType(TextureType type, bool dc) { | 26 | Shader::TextureType GetType(TextureType type) { |
| 27 | switch (type) { | 27 | switch (type) { |
| 28 | case TextureType::_1D: | 28 | case TextureType::_1D: |
| 29 | return dc ? Shader::TextureType::Shadow1D : Shader::TextureType::Color1D; | 29 | return Shader::TextureType::Color1D; |
| 30 | case TextureType::ARRAY_1D: | 30 | case TextureType::ARRAY_1D: |
| 31 | return dc ? Shader::TextureType::ShadowArray1D : Shader::TextureType::ColorArray1D; | 31 | return Shader::TextureType::ColorArray1D; |
| 32 | case TextureType::_2D: | 32 | case TextureType::_2D: |
| 33 | return dc ? Shader::TextureType::Shadow2D : Shader::TextureType::Color2D; | 33 | return Shader::TextureType::Color2D; |
| 34 | case TextureType::ARRAY_2D: | 34 | case TextureType::ARRAY_2D: |
| 35 | return dc ? Shader::TextureType::ShadowArray2D : Shader::TextureType::ColorArray2D; | 35 | return Shader::TextureType::ColorArray2D; |
| 36 | case TextureType::_3D: | 36 | case TextureType::_3D: |
| 37 | return dc ? Shader::TextureType::Shadow3D : Shader::TextureType::Color3D; | 37 | return Shader::TextureType::Color3D; |
| 38 | case TextureType::ARRAY_3D: | 38 | case TextureType::ARRAY_3D: |
| 39 | throw NotImplementedException("3D array texture type"); | 39 | throw NotImplementedException("3D array texture type"); |
| 40 | case TextureType::CUBE: | 40 | case TextureType::CUBE: |
| 41 | return dc ? Shader::TextureType::ShadowCube : Shader::TextureType::ColorCube; | 41 | return Shader::TextureType::ColorCube; |
| 42 | case TextureType::ARRAY_CUBE: | 42 | case TextureType::ARRAY_CUBE: |
| 43 | return dc ? Shader::TextureType::ShadowArrayCube : Shader::TextureType::ColorArrayCube; | 43 | return Shader::TextureType::ColorArrayCube; |
| 44 | } | 44 | } |
| 45 | throw NotImplementedException("Invalid texture type {}", type); | 45 | throw NotImplementedException("Invalid texture type {}", type); |
| 46 | } | 46 | } |
| @@ -97,7 +97,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) { | |||
| 97 | handle = v.ir.Imm32(static_cast<u32>(tmml.cbuf_offset.Value() * 4)); | 97 | handle = v.ir.Imm32(static_cast<u32>(tmml.cbuf_offset.Value() * 4)); |
| 98 | } | 98 | } |
| 99 | IR::TextureInstInfo info{}; | 99 | IR::TextureInstInfo info{}; |
| 100 | info.type.Assign(GetType(tmml.type, false)); | 100 | info.type.Assign(GetType(tmml.type)); |
| 101 | const IR::Value sample{v.ir.ImageQueryLod(handle, coords, info)}; | 101 | const IR::Value sample{v.ir.ImageQueryLod(handle, coords, info)}; |
| 102 | 102 | ||
| 103 | IR::Reg dest_reg{tmml.dest_reg}; | 103 | IR::Reg dest_reg{tmml.dest_reg}; |
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 edbfcd308..bc23b0211 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -416,8 +416,7 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 416 | case IR::Opcode::ImageQueryLod: | 416 | case IR::Opcode::ImageQueryLod: |
| 417 | case IR::Opcode::ImageGradient: { | 417 | case IR::Opcode::ImageGradient: { |
| 418 | const TextureType type{inst.Flags<IR::TextureInstInfo>().type}; | 418 | const TextureType type{inst.Flags<IR::TextureInstInfo>().type}; |
| 419 | info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D || | 419 | info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D; |
| 420 | type == TextureType::Shadow1D || type == TextureType::ShadowArray1D; | ||
| 421 | info.uses_sparse_residency |= | 420 | info.uses_sparse_residency |= |
| 422 | inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp) != nullptr; | 421 | inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp) != nullptr; |
| 423 | break; | 422 | break; |
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index c8aee3d3d..a7b1fcfad 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -61,6 +61,12 @@ IR::Opcode IndexedInstruction(const IR::Inst& inst) { | |||
| 61 | case IR::Opcode::BoundImageGradient: | 61 | case IR::Opcode::BoundImageGradient: |
| 62 | case IR::Opcode::BindlessImageGradient: | 62 | case IR::Opcode::BindlessImageGradient: |
| 63 | return IR::Opcode::ImageGradient; | 63 | return IR::Opcode::ImageGradient; |
| 64 | case IR::Opcode::BoundImageRead: | ||
| 65 | case IR::Opcode::BindlessImageRead: | ||
| 66 | return IR::Opcode::ImageRead; | ||
| 67 | case IR::Opcode::BoundImageWrite: | ||
| 68 | case IR::Opcode::BindlessImageWrite: | ||
| 69 | return IR::Opcode::ImageWrite; | ||
| 64 | default: | 70 | default: |
| 65 | return IR::Opcode::Void; | 71 | return IR::Opcode::Void; |
| 66 | } | 72 | } |
| @@ -78,6 +84,8 @@ bool IsBindless(const IR::Inst& inst) { | |||
| 78 | case IR::Opcode::BindlessImageQueryDimensions: | 84 | case IR::Opcode::BindlessImageQueryDimensions: |
| 79 | case IR::Opcode::BindlessImageQueryLod: | 85 | case IR::Opcode::BindlessImageQueryLod: |
| 80 | case IR::Opcode::BindlessImageGradient: | 86 | case IR::Opcode::BindlessImageGradient: |
| 87 | case IR::Opcode::BindlessImageRead: | ||
| 88 | case IR::Opcode::BindlessImageWrite: | ||
| 81 | return true; | 89 | return true; |
| 82 | case IR::Opcode::BoundImageSampleImplicitLod: | 90 | case IR::Opcode::BoundImageSampleImplicitLod: |
| 83 | case IR::Opcode::BoundImageSampleExplicitLod: | 91 | case IR::Opcode::BoundImageSampleExplicitLod: |
| @@ -89,6 +97,8 @@ bool IsBindless(const IR::Inst& inst) { | |||
| 89 | case IR::Opcode::BoundImageQueryDimensions: | 97 | case IR::Opcode::BoundImageQueryDimensions: |
| 90 | case IR::Opcode::BoundImageQueryLod: | 98 | case IR::Opcode::BoundImageQueryLod: |
| 91 | case IR::Opcode::BoundImageGradient: | 99 | case IR::Opcode::BoundImageGradient: |
| 100 | case IR::Opcode::BoundImageRead: | ||
| 101 | case IR::Opcode::BoundImageWrite: | ||
| 92 | return false; | 102 | return false; |
| 93 | default: | 103 | default: |
| 94 | throw InvalidArgument("Invalid opcode {}", inst.GetOpcode()); | 104 | throw InvalidArgument("Invalid opcode {}", inst.GetOpcode()); |
| @@ -147,10 +157,18 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { | |||
| 147 | 157 | ||
| 148 | class Descriptors { | 158 | class Descriptors { |
| 149 | public: | 159 | public: |
| 150 | explicit Descriptors(TextureDescriptors& texture_descriptors_, | 160 | explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, |
| 151 | TextureBufferDescriptors& texture_buffer_descriptors_) | 161 | TextureDescriptors& texture_descriptors_, |
| 152 | : texture_descriptors{texture_descriptors_}, texture_buffer_descriptors{ | 162 | ImageDescriptors& image_descriptors_) |
| 153 | texture_buffer_descriptors_} {} | 163 | : texture_buffer_descriptors{texture_buffer_descriptors_}, |
| 164 | texture_descriptors{texture_descriptors_}, image_descriptors{image_descriptors_} {} | ||
| 165 | |||
| 166 | u32 Add(const TextureBufferDescriptor& desc) { | ||
| 167 | return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) { | ||
| 168 | return desc.cbuf_index == existing.cbuf_index && | ||
| 169 | desc.cbuf_offset == existing.cbuf_offset; | ||
| 170 | }); | ||
| 171 | } | ||
| 154 | 172 | ||
| 155 | u32 Add(const TextureDescriptor& desc) { | 173 | u32 Add(const TextureDescriptor& desc) { |
| 156 | return Add(texture_descriptors, desc, [&desc](const auto& existing) { | 174 | return Add(texture_descriptors, desc, [&desc](const auto& existing) { |
| @@ -159,11 +177,14 @@ public: | |||
| 159 | }); | 177 | }); |
| 160 | } | 178 | } |
| 161 | 179 | ||
| 162 | u32 Add(const TextureBufferDescriptor& desc) { | 180 | u32 Add(const ImageDescriptor& desc) { |
| 163 | return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) { | 181 | const u32 index{Add(image_descriptors, desc, [&desc](const auto& existing) { |
| 164 | return desc.cbuf_index == existing.cbuf_index && | 182 | return desc.type == existing.type && desc.format == existing.format && |
| 183 | desc.cbuf_index == existing.cbuf_index && | ||
| 165 | desc.cbuf_offset == existing.cbuf_offset; | 184 | desc.cbuf_offset == existing.cbuf_offset; |
| 166 | }); | 185 | })}; |
| 186 | image_descriptors[index].is_written |= desc.is_written; | ||
| 187 | return index; | ||
| 167 | } | 188 | } |
| 168 | 189 | ||
| 169 | private: | 190 | private: |
| @@ -178,8 +199,9 @@ private: | |||
| 178 | return static_cast<u32>(descriptors.size()) - 1; | 199 | return static_cast<u32>(descriptors.size()) - 1; |
| 179 | } | 200 | } |
| 180 | 201 | ||
| 181 | TextureDescriptors& texture_descriptors; | ||
| 182 | TextureBufferDescriptors& texture_buffer_descriptors; | 202 | TextureBufferDescriptors& texture_buffer_descriptors; |
| 203 | TextureDescriptors& texture_descriptors; | ||
| 204 | ImageDescriptors& image_descriptors; | ||
| 183 | }; | 205 | }; |
| 184 | } // Anonymous namespace | 206 | } // Anonymous namespace |
| 185 | 207 | ||
| @@ -201,8 +223,9 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 201 | return lhs.cbuf.index < rhs.cbuf.index; | 223 | return lhs.cbuf.index < rhs.cbuf.index; |
| 202 | }); | 224 | }); |
| 203 | Descriptors descriptors{ | 225 | Descriptors descriptors{ |
| 204 | program.info.texture_descriptors, | ||
| 205 | program.info.texture_buffer_descriptors, | 226 | program.info.texture_buffer_descriptors, |
| 227 | program.info.texture_descriptors, | ||
| 228 | program.info.image_descriptors, | ||
| 206 | }; | 229 | }; |
| 207 | for (TextureInst& texture_inst : to_replace) { | 230 | for (TextureInst& texture_inst : to_replace) { |
| 208 | // TODO: Handle arrays | 231 | // TODO: Handle arrays |
| @@ -233,19 +256,41 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 233 | break; | 256 | break; |
| 234 | } | 257 | } |
| 235 | u32 index; | 258 | u32 index; |
| 236 | if (flags.type == TextureType::Buffer) { | 259 | switch (inst->GetOpcode()) { |
| 237 | index = descriptors.Add(TextureBufferDescriptor{ | 260 | case IR::Opcode::ImageRead: |
| 238 | .cbuf_index = cbuf.index, | 261 | case IR::Opcode::ImageWrite: { |
| 239 | .cbuf_offset = cbuf.offset, | 262 | const bool is_written{inst->GetOpcode() == IR::Opcode::ImageWrite}; |
| 240 | .count = 1, | 263 | if (flags.type == TextureType::Buffer) { |
| 241 | }); | 264 | throw NotImplementedException("Image buffer"); |
| 242 | } else { | 265 | } else { |
| 243 | index = descriptors.Add(TextureDescriptor{ | 266 | index = descriptors.Add(ImageDescriptor{ |
| 244 | .type = flags.type, | 267 | .type = flags.type, |
| 245 | .cbuf_index = cbuf.index, | 268 | .format = flags.image_format, |
| 246 | .cbuf_offset = cbuf.offset, | 269 | .is_written = is_written, |
| 247 | .count = 1, | 270 | .cbuf_index = cbuf.index, |
| 248 | }); | 271 | .cbuf_offset = cbuf.offset, |
| 272 | .count = 1, | ||
| 273 | }); | ||
| 274 | } | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | default: | ||
| 278 | if (flags.type == TextureType::Buffer) { | ||
| 279 | index = descriptors.Add(TextureBufferDescriptor{ | ||
| 280 | .cbuf_index = cbuf.index, | ||
| 281 | .cbuf_offset = cbuf.offset, | ||
| 282 | .count = 1, | ||
| 283 | }); | ||
| 284 | } else { | ||
| 285 | index = descriptors.Add(TextureDescriptor{ | ||
| 286 | .type = flags.type, | ||
| 287 | .is_depth = flags.is_depth != 0, | ||
| 288 | .cbuf_index = cbuf.index, | ||
| 289 | .cbuf_offset = cbuf.offset, | ||
| 290 | .count = 1, | ||
| 291 | }); | ||
| 292 | } | ||
| 293 | break; | ||
| 249 | } | 294 | } |
| 250 | inst->SetArg(0, IR::Value{index}); | 295 | inst->SetArg(0, IR::Value{index}); |
| 251 | } | 296 | } |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index 4cc731198..253b6eacf 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -22,15 +22,20 @@ enum class TextureType : u32 { | |||
| 22 | Color3D, | 22 | Color3D, |
| 23 | ColorCube, | 23 | ColorCube, |
| 24 | ColorArrayCube, | 24 | ColorArrayCube, |
| 25 | Shadow1D, | ||
| 26 | ShadowArray1D, | ||
| 27 | Shadow2D, | ||
| 28 | ShadowArray2D, | ||
| 29 | Shadow3D, | ||
| 30 | ShadowCube, | ||
| 31 | ShadowArrayCube, | ||
| 32 | Buffer, | 25 | Buffer, |
| 33 | }; | 26 | }; |
| 27 | constexpr u32 NUM_TEXTURE_TYPES = 8; | ||
| 28 | |||
| 29 | enum class ImageFormat : u32 { | ||
| 30 | Typeless, | ||
| 31 | R8_UINT, | ||
| 32 | R8_SINT, | ||
| 33 | R16_UINT, | ||
| 34 | R16_SINT, | ||
| 35 | R32_UINT, | ||
| 36 | R32G32_UINT, | ||
| 37 | R32G32B32A32_UINT, | ||
| 38 | }; | ||
| 34 | 39 | ||
| 35 | enum class Interpolation { | 40 | enum class Interpolation { |
| 36 | Smooth, | 41 | Smooth, |
| @@ -43,32 +48,43 @@ struct InputVarying { | |||
| 43 | bool used{false}; | 48 | bool used{false}; |
| 44 | }; | 49 | }; |
| 45 | 50 | ||
| 46 | struct TextureDescriptor { | 51 | struct ConstantBufferDescriptor { |
| 47 | TextureType type; | 52 | u32 index; |
| 53 | u32 count; | ||
| 54 | }; | ||
| 55 | |||
| 56 | struct StorageBufferDescriptor { | ||
| 48 | u32 cbuf_index; | 57 | u32 cbuf_index; |
| 49 | u32 cbuf_offset; | 58 | u32 cbuf_offset; |
| 50 | u32 count; | 59 | u32 count; |
| 60 | bool is_written; | ||
| 51 | }; | 61 | }; |
| 52 | using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>; | ||
| 53 | 62 | ||
| 54 | struct TextureBufferDescriptor { | 63 | struct TextureBufferDescriptor { |
| 55 | u32 cbuf_index; | 64 | u32 cbuf_index; |
| 56 | u32 cbuf_offset; | 65 | u32 cbuf_offset; |
| 57 | u32 count; | 66 | u32 count; |
| 58 | }; | 67 | }; |
| 59 | using TextureBufferDescriptors = boost::container::small_vector<TextureBufferDescriptor, 2>; | 68 | using TextureBufferDescriptors = boost::container::small_vector<TextureBufferDescriptor, 6>; |
| 60 | 69 | ||
| 61 | struct ConstantBufferDescriptor { | 70 | struct TextureDescriptor { |
| 62 | u32 index; | 71 | TextureType type; |
| 72 | bool is_depth; | ||
| 73 | u32 cbuf_index; | ||
| 74 | u32 cbuf_offset; | ||
| 63 | u32 count; | 75 | u32 count; |
| 64 | }; | 76 | }; |
| 77 | using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>; | ||
| 65 | 78 | ||
| 66 | struct StorageBufferDescriptor { | 79 | struct ImageDescriptor { |
| 80 | TextureType type; | ||
| 81 | ImageFormat format; | ||
| 82 | bool is_written; | ||
| 67 | u32 cbuf_index; | 83 | u32 cbuf_index; |
| 68 | u32 cbuf_offset; | 84 | u32 cbuf_offset; |
| 69 | u32 count; | 85 | u32 count; |
| 70 | bool is_written; | ||
| 71 | }; | 86 | }; |
| 87 | using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>; | ||
| 72 | 88 | ||
| 73 | struct Info { | 89 | struct Info { |
| 74 | static constexpr size_t MAX_CBUFS{18}; | 90 | static constexpr size_t MAX_CBUFS{18}; |
| @@ -121,6 +137,7 @@ struct Info { | |||
| 121 | boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; | 137 | boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; |
| 122 | TextureBufferDescriptors texture_buffer_descriptors; | 138 | TextureBufferDescriptors texture_buffer_descriptors; |
| 123 | TextureDescriptors texture_descriptors; | 139 | TextureDescriptors texture_descriptors; |
| 140 | ImageDescriptors image_descriptors; | ||
| 124 | }; | 141 | }; |
| 125 | 142 | ||
| 126 | } // namespace Shader | 143 | } // namespace Shader |