summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/CMakeLists.txt1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp97
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h9
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.h6
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp46
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp11
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h7
-rw-r--r--src/shader_recompiler/frontend/ir/modifiers.h12
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc6
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp8
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/surface_load_store.cpp280
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch.cpp19
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_fetch_swizzled.cpp12
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather.cpp19
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_gather_swizzled.cpp3
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp18
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_load.cpp18
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_load_swizzled.cpp2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_mipmap_level.cpp18
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp3
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp91
-rw-r--r--src/shader_recompiler/shader_info.h47
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp4
-rw-r--r--src/video_core/renderer_vulkan/pipeline_helper.h43
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp112
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h23
-rw-r--r--src/video_core/texture_cache/texture_cache.h8
31 files changed, 732 insertions, 202 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 {
18Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) { 18Id 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
43Id 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
56Id DefineVariable(EmitContext& ctx, Id type, std::optional<spv::BuiltIn> builtin, 85Id 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
605void 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
575void EmitContext::DefineLabels(IR::Program& program) { 630void 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
38struct ImageDefinition {
39 Id id;
40 Id image_type;
41};
42
38struct UniformDefinitions { 43struct 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
258Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) { 259Id 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&);
369Id EmitBindlessImageQueryDimensions(EmitContext&); 369Id EmitBindlessImageQueryDimensions(EmitContext&);
370Id EmitBindlessImageQueryLod(EmitContext&); 370Id EmitBindlessImageQueryLod(EmitContext&);
371Id EmitBindlessImageGradient(EmitContext&); 371Id EmitBindlessImageGradient(EmitContext&);
372Id EmitBindlessImageRead(EmitContext&);
373Id EmitBindlessImageWrite(EmitContext&);
372Id EmitBoundImageSampleImplicitLod(EmitContext&); 374Id EmitBoundImageSampleImplicitLod(EmitContext&);
373Id EmitBoundImageSampleExplicitLod(EmitContext&); 375Id EmitBoundImageSampleExplicitLod(EmitContext&);
374Id EmitBoundImageSampleDrefImplicitLod(EmitContext&); 376Id EmitBoundImageSampleDrefImplicitLod(EmitContext&);
@@ -379,6 +381,8 @@ Id EmitBoundImageFetch(EmitContext&);
379Id EmitBoundImageQueryDimensions(EmitContext&); 381Id EmitBoundImageQueryDimensions(EmitContext&);
380Id EmitBoundImageQueryLod(EmitContext&); 382Id EmitBoundImageQueryLod(EmitContext&);
381Id EmitBoundImageGradient(EmitContext&); 383Id EmitBoundImageGradient(EmitContext&);
384Id EmitBoundImageRead(EmitContext&);
385Id EmitBoundImageWrite(EmitContext&);
382Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 386Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
383 Id bias_lc, Id offset); 387 Id bias_lc, Id offset);
384Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 388Id 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
397Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); 401Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
398Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 402Id 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);
404Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
405void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
400Id EmitVoteAll(EmitContext& ctx, Id pred); 406Id EmitVoteAll(EmitContext& ctx, Id pred);
401Id EmitVoteAny(EmitContext& ctx, Id pred); 407Id EmitVoteAny(EmitContext& ctx, Id pred);
402Id EmitVoteEqual(EmitContext& ctx, Id pred); 408Id 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
147Id 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
147Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { 159Id 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
224Id EmitBindlessImageRead(EmitContext&) {
225 throw LogicError("Unreachable instruction");
226}
227
228Id EmitBindlessImageWrite(EmitContext&) {
229 throw LogicError("Unreachable instruction");
230}
231
212Id EmitBoundImageSampleImplicitLod(EmitContext&) { 232Id 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
272Id EmitBoundImageRead(EmitContext&) {
273 throw LogicError("Unreachable instruction");
274}
275
276Id EmitBoundImageWrite(EmitContext&) {
277 throw LogicError("Unreachable instruction");
278}
279
252Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 280Id 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
389Id 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
395void 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
1623Value 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
1628void 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
1623U1 IREmitter::VoteAll(const U1& value) { 1634U1 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));
43union TextureInstInfo { 43union 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};
52static_assert(sizeof(TextureInstInfo) <= sizeof(u32)); 54static_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,
389OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, ) 389OPCODE(BindlessImageQueryDimensions, U32x4, U32, U32, )
390OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, ) 390OPCODE(BindlessImageQueryLod, F32x4, U32, Opaque, )
391OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) 391OPCODE(BindlessImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
392OPCODE(BindlessImageRead, U32x4, U32, Opaque, )
393OPCODE(BindlessImageWrite, Void, U32, Opaque, U32x4, )
392 394
393OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 395OPCODE(BoundImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
394OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 396OPCODE(BoundImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
@@ -400,6 +402,8 @@ OPCODE(BoundImageFetch, F32x4, U32,
400OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, ) 402OPCODE(BoundImageQueryDimensions, U32x4, U32, U32, )
401OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, ) 403OPCODE(BoundImageQueryLod, F32x4, U32, Opaque, )
402OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) 404OPCODE(BoundImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
405OPCODE(BoundImageRead, U32x4, U32, Opaque, )
406OPCODE(BoundImageWrite, Void, U32, Opaque, U32x4, )
403 407
404OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 408OPCODE(ImageSampleImplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
405OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, ) 409OPCODE(ImageSampleExplicitLod, F32x4, U32, Opaque, Opaque, Opaque, )
@@ -411,6 +415,8 @@ OPCODE(ImageFetch, F32x4, U32,
411OPCODE(ImageQueryDimensions, U32x4, U32, U32, ) 415OPCODE(ImageQueryDimensions, U32x4, U32, U32, )
412OPCODE(ImageQueryLod, F32x4, U32, Opaque, ) 416OPCODE(ImageQueryLod, F32x4, U32, Opaque, )
413OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, ) 417OPCODE(ImageGradient, F32x4, U32, Opaque, Opaque, Opaque, Opaque, )
418OPCODE(ImageRead, U32x4, U32, Opaque, )
419OPCODE(ImageWrite, Void, U32, Opaque, U32x4, )
414 420
415// Warp operations 421// Warp operations
416OPCODE(VoteAll, U1, U1, ) 422OPCODE(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
284void TranslatorVisitor::SULD(u64) {
285 ThrowNotImplemented(Opcode::SULD);
286}
287
288void TranslatorVisitor::SURED(u64) { 284void TranslatorVisitor::SURED(u64) {
289 ThrowNotImplemented(Opcode::SURED); 285 ThrowNotImplemented(Opcode::SURED);
290} 286}
291 287
292void TranslatorVisitor::SUST(u64) {
293 ThrowNotImplemented(Opcode::SUST);
294}
295
296void TranslatorVisitor::SYNC(u64) { 288void 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
13namespace Shader::Maxwell {
14namespace {
15enum class Type : u64 {
16 _1D,
17 BUFFER_1D,
18 ARRAY_1D,
19 _2D,
20 ARRAY_2D,
21 _3D,
22};
23
24constexpr unsigned R = 1 << 0;
25constexpr unsigned G = 1 << 1;
26constexpr unsigned B = 1 << 2;
27constexpr unsigned A = 1 << 3;
28
29constexpr 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
48enum class Size : u64 {
49 U8,
50 S8,
51 U16,
52 S16,
53 B32,
54 B64,
55 B128,
56};
57
58enum class Clamp : u64 {
59 IGN,
60 Default,
61 TRAP,
62};
63
64enum class LoadCache : u64 {
65 Default,
66 CG,
67 CI,
68 CV,
69};
70
71enum class StoreCache : u64 {
72 Default,
73 CG,
74 CS,
75 WT,
76};
77
78ImageFormat 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
98int 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
114TextureType 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
132IR::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
152unsigned SwizzleMask(u64 swizzle) {
153 if (swizzle == 0 || swizzle >= MASK.size()) {
154 throw NotImplementedException("Invalid swizzle {}", swizzle);
155 }
156 return MASK[swizzle];
157}
158
159IR::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
171void 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
231void 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
36Shader::TextureType GetType(TextureType type, bool dc) { 36Shader::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
40Shader::TextureType GetType(TextureType type, bool dc) { 40Shader::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
26Shader::TextureType GetType(TextureType type, bool dc) { 26Shader::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
26Shader::TextureType GetType(TextureType type, bool dc) { 26Shader::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
26Shader::TextureType GetType(TextureType type, bool dc) { 26Shader::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
148class Descriptors { 158class Descriptors {
149public: 159public:
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
169private: 190private:
@@ -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};
27constexpr u32 NUM_TEXTURE_TYPES = 8;
28
29enum 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
35enum class Interpolation { 40enum class Interpolation {
36 Smooth, 41 Smooth,
@@ -43,32 +48,43 @@ struct InputVarying {
43 bool used{false}; 48 bool used{false};
44}; 49};
45 50
46struct TextureDescriptor { 51struct ConstantBufferDescriptor {
47 TextureType type; 52 u32 index;
53 u32 count;
54};
55
56struct 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};
52using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>;
53 62
54struct TextureBufferDescriptor { 63struct 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};
59using TextureBufferDescriptors = boost::container::small_vector<TextureBufferDescriptor, 2>; 68using TextureBufferDescriptors = boost::container::small_vector<TextureBufferDescriptor, 6>;
60 69
61struct ConstantBufferDescriptor { 70struct 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};
77using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>;
65 78
66struct StorageBufferDescriptor { 79struct 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};
87using ImageDescriptors = boost::container::small_vector<ImageDescriptor, 4>;
72 88
73struct Info { 89struct 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
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 6c0d5c7f4..39fe9289b 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -361,7 +361,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
361 .operation = operation, 361 .operation = operation,
362 }; 362 };
363 const VkPipelineLayout layout = *one_texture_pipeline_layout; 363 const VkPipelineLayout layout = *one_texture_pipeline_layout;
364 const VkImageView src_view = src_image_view.Handle(ImageViewType::e2D); 364 const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
365 const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler; 365 const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
366 const VkPipeline pipeline = FindOrEmplacePipeline(key); 366 const VkPipeline pipeline = FindOrEmplacePipeline(key);
367 const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); 367 const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
@@ -435,7 +435,7 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
435void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer, 435void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
436 const ImageView& src_image_view) { 436 const ImageView& src_image_view) {
437 const VkPipelineLayout layout = *one_texture_pipeline_layout; 437 const VkPipelineLayout layout = *one_texture_pipeline_layout;
438 const VkImageView src_view = src_image_view.Handle(ImageViewType::e2D); 438 const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
439 const VkSampler sampler = *nearest_sampler; 439 const VkSampler sampler = *nearest_sampler;
440 const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit(); 440 const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
441 const VkExtent2D extent{ 441 const VkExtent2D extent{
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h
index cff93cc60..d2c3f11c1 100644
--- a/src/video_core/renderer_vulkan/pipeline_helper.h
+++ b/src/video_core/renderer_vulkan/pipeline_helper.h
@@ -97,6 +97,9 @@ public:
97 for ([[maybe_unused]] const auto& desc : info.texture_descriptors) { 97 for ([[maybe_unused]] const auto& desc : info.texture_descriptors) {
98 Add(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stage); 98 Add(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stage);
99 } 99 }
100 for (const auto& desc : info.image_descriptors) {
101 Add(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, stage);
102 }
100 } 103 }
101 104
102private: 105private:
@@ -127,36 +130,6 @@ private:
127 size_t offset{}; 130 size_t offset{};
128}; 131};
129 132
130inline VideoCommon::ImageViewType CastType(Shader::TextureType type) {
131 switch (type) {
132 case Shader::TextureType::Color1D:
133 case Shader::TextureType::Shadow1D:
134 return VideoCommon::ImageViewType::e1D;
135 case Shader::TextureType::ColorArray1D:
136 case Shader::TextureType::ShadowArray1D:
137 return VideoCommon::ImageViewType::e1DArray;
138 case Shader::TextureType::Color2D:
139 case Shader::TextureType::Shadow2D:
140 return VideoCommon::ImageViewType::e2D;
141 case Shader::TextureType::ColorArray2D:
142 case Shader::TextureType::ShadowArray2D:
143 return VideoCommon::ImageViewType::e2DArray;
144 case Shader::TextureType::Color3D:
145 case Shader::TextureType::Shadow3D:
146 return VideoCommon::ImageViewType::e3D;
147 case Shader::TextureType::ColorCube:
148 case Shader::TextureType::ShadowCube:
149 return VideoCommon::ImageViewType::Cube;
150 case Shader::TextureType::ColorArrayCube:
151 case Shader::TextureType::ShadowArrayCube:
152 return VideoCommon::ImageViewType::CubeArray;
153 case Shader::TextureType::Buffer:
154 break;
155 }
156 UNREACHABLE_MSG("Invalid texture type {}", type);
157 return {};
158}
159
160inline void PushImageDescriptors(const Shader::Info& info, const VkSampler*& samplers, 133inline void PushImageDescriptors(const Shader::Info& info, const VkSampler*& samplers,
161 const ImageId*& image_view_ids, TextureCache& texture_cache, 134 const ImageId*& image_view_ids, TextureCache& texture_cache,
162 VKUpdateDescriptorQueue& update_descriptor_queue) { 135 VKUpdateDescriptorQueue& update_descriptor_queue) {
@@ -164,9 +137,17 @@ inline void PushImageDescriptors(const Shader::Info& info, const VkSampler*& sam
164 for (const auto& desc : info.texture_descriptors) { 137 for (const auto& desc : info.texture_descriptors) {
165 const VkSampler sampler{*(samplers++)}; 138 const VkSampler sampler{*(samplers++)};
166 ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))}; 139 ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))};
167 const VkImageView vk_image_view{image_view.Handle(CastType(desc.type))}; 140 const VkImageView vk_image_view{image_view.Handle(desc.type)};
168 update_descriptor_queue.AddSampledImage(vk_image_view, sampler); 141 update_descriptor_queue.AddSampledImage(vk_image_view, sampler);
169 } 142 }
143 for (const auto& desc : info.image_descriptors) {
144 ImageView& image_view{texture_cache.GetImageView(*(image_view_ids++))};
145 if (desc.is_written) {
146 texture_cache.MarkModification(image_view.image_id);
147 }
148 const VkImageView vk_image_view{image_view.StorageView(desc.type, desc.format)};
149 update_descriptor_queue.AddImage(vk_image_view);
150 }
170} 151}
171 152
172} // namespace Vulkan 153} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index ac47b1f3c..3d690f335 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -108,6 +108,10 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
108 Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler); 108 Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler);
109 samplers.push_back(sampler->Handle()); 109 samplers.push_back(sampler->Handle());
110 } 110 }
111 for (const auto& desc : info.image_descriptors) {
112 const TextureHandle handle{read_handle(desc.cbuf_index, desc.cbuf_offset)};
113 image_view_indices.push_back(handle.image);
114 }
111 const std::span indices_span(image_view_indices.data(), image_view_indices.size()); 115 const std::span indices_span(image_view_indices.data(), image_view_indices.size());
112 texture_cache.FillComputeImageViews(indices_span, image_view_ids); 116 texture_cache.FillComputeImageViews(indices_span, image_view_ids);
113 117
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 57e2d569c..23c01f24e 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -186,6 +186,10 @@ void GraphicsPipeline::Configure(bool is_indexed) {
186 Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.sampler)}; 186 Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.sampler)};
187 samplers.push_back(sampler->Handle()); 187 samplers.push_back(sampler->Handle());
188 } 188 }
189 for (const auto& desc : info.image_descriptors) {
190 const TextureHandle handle{read_handle(desc.cbuf_index, desc.cbuf_offset)};
191 image_view_indices.push_back(handle.image);
192 }
189 } 193 }
190 const std::span indices_span(image_view_indices.data(), image_view_indices.size()); 194 const std::span indices_span(image_view_indices.data(), image_view_indices.size());
191 texture_cache.FillGraphicsImageViews(indices_span, image_view_ids); 195 texture_cache.FillGraphicsImageViews(indices_span, image_view_ids);
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 0292a1b94..2ba44330f 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -494,7 +494,7 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
494 if (!image_view) { 494 if (!image_view) {
495 return false; 495 return false;
496 } 496 }
497 screen_info.image_view = image_view->Handle(VideoCommon::ImageViewType::e2D); 497 screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D);
498 screen_info.width = image_view->size.width; 498 screen_info.width = image_view->size.width;
499 screen_info.height = image_view->size.height; 499 screen_info.height = image_view->size.height;
500 screen_info.is_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format); 500 screen_info.is_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format);
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 70328680d..8e029bcb3 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -215,6 +215,30 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
215 return VK_COMPONENT_SWIZZLE_ZERO; 215 return VK_COMPONENT_SWIZZLE_ZERO;
216} 216}
217 217
218[[nodiscard]] VkImageViewType ImageViewType(Shader::TextureType type) {
219 switch (type) {
220 case Shader::TextureType::Color1D:
221 return VK_IMAGE_VIEW_TYPE_1D;
222 case Shader::TextureType::Color2D:
223 return VK_IMAGE_VIEW_TYPE_2D;
224 case Shader::TextureType::ColorCube:
225 return VK_IMAGE_VIEW_TYPE_CUBE;
226 case Shader::TextureType::Color3D:
227 return VK_IMAGE_VIEW_TYPE_3D;
228 case Shader::TextureType::ColorArray1D:
229 return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
230 case Shader::TextureType::ColorArray2D:
231 return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
232 case Shader::TextureType::ColorArrayCube:
233 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
234 case Shader::TextureType::Buffer:
235 UNREACHABLE_MSG("Texture buffers can't be image views");
236 return VK_IMAGE_VIEW_TYPE_1D;
237 }
238 UNREACHABLE_MSG("Invalid image view type={}", type);
239 return VK_IMAGE_VIEW_TYPE_2D;
240}
241
218[[nodiscard]] VkImageViewType ImageViewType(VideoCommon::ImageViewType type) { 242[[nodiscard]] VkImageViewType ImageViewType(VideoCommon::ImageViewType type) {
219 switch (type) { 243 switch (type) {
220 case VideoCommon::ImageViewType::e1D: 244 case VideoCommon::ImageViewType::e1D:
@@ -232,7 +256,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
232 case VideoCommon::ImageViewType::CubeArray: 256 case VideoCommon::ImageViewType::CubeArray:
233 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; 257 return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
234 case VideoCommon::ImageViewType::Rect: 258 case VideoCommon::ImageViewType::Rect:
235 LOG_WARNING(Render_Vulkan, "Unnormalized image view type not supported"); 259 UNIMPLEMENTED_MSG("Rect image view");
236 return VK_IMAGE_VIEW_TYPE_2D; 260 return VK_IMAGE_VIEW_TYPE_2D;
237 case VideoCommon::ImageViewType::Buffer: 261 case VideoCommon::ImageViewType::Buffer:
238 UNREACHABLE_MSG("Texture buffers can't be image views"); 262 UNREACHABLE_MSG("Texture buffers can't be image views");
@@ -539,6 +563,28 @@ struct RangedBarrierRange {
539 } 563 }
540}; 564};
541 565
566[[nodiscard]] VkFormat Format(Shader::ImageFormat format) {
567 switch (format) {
568 case Shader::ImageFormat::Typeless:
569 break;
570 case Shader::ImageFormat::R8_SINT:
571 return VK_FORMAT_R8_SINT;
572 case Shader::ImageFormat::R8_UINT:
573 return VK_FORMAT_R8_UINT;
574 case Shader::ImageFormat::R16_UINT:
575 return VK_FORMAT_R16_UINT;
576 case Shader::ImageFormat::R16_SINT:
577 return VK_FORMAT_R16_SINT;
578 case Shader::ImageFormat::R32_UINT:
579 return VK_FORMAT_R32_UINT;
580 case Shader::ImageFormat::R32G32_UINT:
581 return VK_FORMAT_R32G32_UINT;
582 case Shader::ImageFormat::R32G32B32A32_UINT:
583 return VK_FORMAT_R32G32B32A32_UINT;
584 }
585 UNREACHABLE_MSG("Invalid image format={}", format);
586 return VK_FORMAT_R32_UINT;
587}
542} // Anonymous namespace 588} // Anonymous namespace
543 589
544void TextureCacheRuntime::Finish() { 590void TextureCacheRuntime::Finish() {
@@ -577,7 +623,7 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
577 return; 623 return;
578 } 624 }
579 } 625 }
580 ASSERT(src.ImageFormat() == dst.ImageFormat()); 626 ASSERT(src.format == dst.format);
581 ASSERT(!(is_dst_msaa && !is_src_msaa)); 627 ASSERT(!(is_dst_msaa && !is_src_msaa));
582 ASSERT(operation == Fermi2D::Operation::SrcCopy); 628 ASSERT(operation == Fermi2D::Operation::SrcCopy);
583 629
@@ -915,8 +961,9 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm
915ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, 961ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
916 ImageId image_id_, Image& image) 962 ImageId image_id_, Image& image)
917 : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device}, 963 : VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device},
918 image_handle{image.Handle()}, image_format{image.info.format}, samples{ConvertSampleCount( 964 image_handle{image.Handle()}, samples{ConvertSampleCount(image.info.num_samples)} {
919 image.info.num_samples)} { 965 using Shader::TextureType;
966
920 const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); 967 const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
921 std::array<SwizzleSource, 4> swizzle{ 968 std::array<SwizzleSource, 4> swizzle{
922 SwizzleSource::R, 969 SwizzleSource::R,
@@ -954,39 +1001,39 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
954 }, 1001 },
955 .subresourceRange = MakeSubresourceRange(aspect_mask, info.range), 1002 .subresourceRange = MakeSubresourceRange(aspect_mask, info.range),
956 }; 1003 };
957 const auto create = [&](VideoCommon::ImageViewType view_type, std::optional<u32> num_layers) { 1004 const auto create = [&](TextureType tex_type, std::optional<u32> num_layers) {
958 VkImageViewCreateInfo ci{create_info}; 1005 VkImageViewCreateInfo ci{create_info};
959 ci.viewType = ImageViewType(view_type); 1006 ci.viewType = ImageViewType(tex_type);
960 if (num_layers) { 1007 if (num_layers) {
961 ci.subresourceRange.layerCount = *num_layers; 1008 ci.subresourceRange.layerCount = *num_layers;
962 } 1009 }
963 vk::ImageView handle = device->GetLogical().CreateImageView(ci); 1010 vk::ImageView handle = device->GetLogical().CreateImageView(ci);
964 if (device->HasDebuggingToolAttached()) { 1011 if (device->HasDebuggingToolAttached()) {
965 handle.SetObjectNameEXT(VideoCommon::Name(*this, view_type).c_str()); 1012 handle.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
966 } 1013 }
967 image_views[static_cast<size_t>(view_type)] = std::move(handle); 1014 image_views[static_cast<size_t>(tex_type)] = std::move(handle);
968 }; 1015 };
969 switch (info.type) { 1016 switch (info.type) {
970 case VideoCommon::ImageViewType::e1D: 1017 case VideoCommon::ImageViewType::e1D:
971 case VideoCommon::ImageViewType::e1DArray: 1018 case VideoCommon::ImageViewType::e1DArray:
972 create(VideoCommon::ImageViewType::e1D, 1); 1019 create(TextureType::Color1D, 1);
973 create(VideoCommon::ImageViewType::e1DArray, std::nullopt); 1020 create(TextureType::ColorArray1D, std::nullopt);
974 render_target = Handle(VideoCommon::ImageViewType::e1DArray); 1021 render_target = Handle(TextureType::ColorArray1D);
975 break; 1022 break;
976 case VideoCommon::ImageViewType::e2D: 1023 case VideoCommon::ImageViewType::e2D:
977 case VideoCommon::ImageViewType::e2DArray: 1024 case VideoCommon::ImageViewType::e2DArray:
978 create(VideoCommon::ImageViewType::e2D, 1); 1025 create(TextureType::Color2D, 1);
979 create(VideoCommon::ImageViewType::e2DArray, std::nullopt); 1026 create(TextureType::ColorArray2D, std::nullopt);
980 render_target = Handle(VideoCommon::ImageViewType::e2DArray); 1027 render_target = Handle(Shader::TextureType::ColorArray2D);
981 break; 1028 break;
982 case VideoCommon::ImageViewType::e3D: 1029 case VideoCommon::ImageViewType::e3D:
983 create(VideoCommon::ImageViewType::e3D, std::nullopt); 1030 create(TextureType::Color3D, std::nullopt);
984 render_target = Handle(VideoCommon::ImageViewType::e3D); 1031 render_target = Handle(Shader::TextureType::Color3D);
985 break; 1032 break;
986 case VideoCommon::ImageViewType::Cube: 1033 case VideoCommon::ImageViewType::Cube:
987 case VideoCommon::ImageViewType::CubeArray: 1034 case VideoCommon::ImageViewType::CubeArray:
988 create(VideoCommon::ImageViewType::Cube, 6); 1035 create(TextureType::ColorCube, 6);
989 create(VideoCommon::ImageViewType::CubeArray, std::nullopt); 1036 create(TextureType::ColorArrayCube, std::nullopt);
990 break; 1037 break;
991 case VideoCommon::ImageViewType::Rect: 1038 case VideoCommon::ImageViewType::Rect:
992 UNIMPLEMENTED(); 1039 UNIMPLEMENTED();
@@ -1009,7 +1056,8 @@ VkImageView ImageView::DepthView() {
1009 if (depth_view) { 1056 if (depth_view) {
1010 return *depth_view; 1057 return *depth_view;
1011 } 1058 }
1012 depth_view = MakeDepthStencilView(VK_IMAGE_ASPECT_DEPTH_BIT); 1059 const auto& info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
1060 depth_view = MakeView(info.format, VK_IMAGE_ASPECT_DEPTH_BIT);
1013 return *depth_view; 1061 return *depth_view;
1014} 1062}
1015 1063
@@ -1017,18 +1065,38 @@ VkImageView ImageView::StencilView() {
1017 if (stencil_view) { 1065 if (stencil_view) {
1018 return *stencil_view; 1066 return *stencil_view;
1019 } 1067 }
1020 stencil_view = MakeDepthStencilView(VK_IMAGE_ASPECT_STENCIL_BIT); 1068 const auto& info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
1069 stencil_view = MakeView(info.format, VK_IMAGE_ASPECT_STENCIL_BIT);
1021 return *stencil_view; 1070 return *stencil_view;
1022} 1071}
1023 1072
1024vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) { 1073VkImageView ImageView::StorageView(Shader::TextureType texture_type,
1074 Shader::ImageFormat image_format) {
1075 if (image_format == Shader::ImageFormat::Typeless) {
1076 return Handle(texture_type);
1077 }
1078 const bool is_signed{image_format == Shader::ImageFormat::R8_SINT ||
1079 image_format == Shader::ImageFormat::R16_SINT};
1080 if (!storage_views) {
1081 storage_views = std::make_unique<StorageViews>();
1082 }
1083 auto& views{is_signed ? storage_views->signeds : storage_views->unsigneds};
1084 auto& view{views[static_cast<size_t>(texture_type)]};
1085 if (view) {
1086 return *view;
1087 }
1088 view = MakeView(Format(image_format), VK_IMAGE_ASPECT_COLOR_BIT);
1089 return *view;
1090}
1091
1092vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) {
1025 return device->GetLogical().CreateImageView({ 1093 return device->GetLogical().CreateImageView({
1026 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 1094 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1027 .pNext = nullptr, 1095 .pNext = nullptr,
1028 .flags = 0, 1096 .flags = 0,
1029 .image = image_handle, 1097 .image = image_handle,
1030 .viewType = ImageViewType(type), 1098 .viewType = ImageViewType(type),
1031 .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format).format, 1099 .format = vk_format,
1032 .components{ 1100 .components{
1033 .r = VK_COMPONENT_SWIZZLE_IDENTITY, 1101 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
1034 .g = VK_COMPONENT_SWIZZLE_IDENTITY, 1102 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 498e76a1c..0b73d55f8 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -7,6 +7,7 @@
7#include <compare> 7#include <compare>
8#include <span> 8#include <span>
9 9
10#include "shader_recompiler/shader_info.h"
10#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 11#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
11#include "video_core/texture_cache/texture_cache.h" 12#include "video_core/texture_cache/texture_cache.h"
12#include "video_core/vulkan_common/vulkan_memory_allocator.h" 13#include "video_core/vulkan_common/vulkan_memory_allocator.h"
@@ -133,8 +134,11 @@ public:
133 134
134 [[nodiscard]] VkImageView StencilView(); 135 [[nodiscard]] VkImageView StencilView();
135 136
136 [[nodiscard]] VkImageView Handle(VideoCommon::ImageViewType query_type) const noexcept { 137 [[nodiscard]] VkImageView StorageView(Shader::TextureType texture_type,
137 return *image_views[static_cast<size_t>(query_type)]; 138 Shader::ImageFormat image_format);
139
140 [[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept {
141 return *image_views[static_cast<size_t>(texture_type)];
138 } 142 }
139 143
140 [[nodiscard]] VkImage ImageHandle() const noexcept { 144 [[nodiscard]] VkImage ImageHandle() const noexcept {
@@ -145,10 +149,6 @@ public:
145 return render_target; 149 return render_target;
146 } 150 }
147 151
148 [[nodiscard]] PixelFormat ImageFormat() const noexcept {
149 return image_format;
150 }
151
152 [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept { 152 [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept {
153 return samples; 153 return samples;
154 } 154 }
@@ -162,15 +162,20 @@ public:
162 } 162 }
163 163
164private: 164private:
165 [[nodiscard]] vk::ImageView MakeDepthStencilView(VkImageAspectFlags aspect_mask); 165 struct StorageViews {
166 std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> signeds;
167 std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> unsigneds;
168 };
169
170 [[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask);
166 171
167 const Device* device = nullptr; 172 const Device* device = nullptr;
168 std::array<vk::ImageView, VideoCommon::NUM_IMAGE_VIEW_TYPES> image_views; 173 std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> image_views;
174 std::unique_ptr<StorageViews> storage_views;
169 vk::ImageView depth_view; 175 vk::ImageView depth_view;
170 vk::ImageView stencil_view; 176 vk::ImageView stencil_view;
171 VkImage image_handle = VK_NULL_HANDLE; 177 VkImage image_handle = VK_NULL_HANDLE;
172 VkImageView render_target = VK_NULL_HANDLE; 178 VkImageView render_target = VK_NULL_HANDLE;
173 PixelFormat image_format = PixelFormat::Invalid;
174 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; 179 VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
175 GPUVAddr gpu_addr = 0; 180 GPUVAddr gpu_addr = 0;
176 u32 buffer_size = 0; 181 u32 buffer_size = 0;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 5e8d99482..255b07cf8 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -117,6 +117,9 @@ public:
117 /// Return a reference to the given image view id 117 /// Return a reference to the given image view id
118 [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept; 118 [[nodiscard]] ImageView& GetImageView(ImageViewId id) noexcept;
119 119
120 /// Mark an image as modified from the GPU
121 void MarkModification(ImageId id) noexcept;
122
120 /// Fill image_view_ids with the graphics images in indices 123 /// Fill image_view_ids with the graphics images in indices
121 void FillGraphicsImageViews(std::span<const u32> indices, 124 void FillGraphicsImageViews(std::span<const u32> indices,
122 std::span<ImageViewId> image_view_ids); 125 std::span<ImageViewId> image_view_ids);
@@ -527,6 +530,11 @@ typename P::ImageView& TextureCache<P>::GetImageView(ImageViewId id) noexcept {
527} 530}
528 531
529template <class P> 532template <class P>
533void TextureCache<P>::MarkModification(ImageId id) noexcept {
534 MarkModification(slot_images[id]);
535}
536
537template <class P>
530void TextureCache<P>::FillGraphicsImageViews(std::span<const u32> indices, 538void TextureCache<P>::FillGraphicsImageViews(std::span<const u32> indices,
531 std::span<ImageViewId> image_view_ids) { 539 std::span<ImageViewId> image_view_ids) {
532 FillImageViews(graphics_image_table, graphics_image_view_ids, indices, image_view_ids); 540 FillImageViews(graphics_image_table, graphics_image_view_ids, indices, image_view_ids);