summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.cpp29
-rw-r--r--src/shader_recompiler/backend/spirv/emit_context.h5
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp1
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp24
-rw-r--r--src/shader_recompiler/ir_opt/texture_pass.cpp80
-rw-r--r--src/shader_recompiler/shader_info.h9
-rw-r--r--src/video_core/renderer_vulkan/pipeline_helper.h10
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp2
10 files changed, 154 insertions, 35 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_context.cpp b/src/shader_recompiler/backend/spirv/emit_context.cpp
index 2d39ea373..d01633628 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_context.cpp
@@ -46,6 +46,8 @@ Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
46 return ctx.TypeImage(type, spv::Dim::Cube, true, false, false, 1, format); 46 return ctx.TypeImage(type, spv::Dim::Cube, true, false, false, 1, format);
47 case TextureType::ShadowArrayCube: 47 case TextureType::ShadowArrayCube:
48 return ctx.TypeImage(type, spv::Dim::Cube, true, true, false, 1, format); 48 return ctx.TypeImage(type, spv::Dim::Cube, true, true, false, 1, format);
49 case TextureType::Buffer:
50 break;
49 } 51 }
50 throw InvalidArgument("Invalid texture type {}", desc.type); 52 throw InvalidArgument("Invalid texture type {}", desc.type);
51} 53}
@@ -129,6 +131,7 @@ EmitContext::EmitContext(const Profile& profile_, IR::Program& program, u32& bin
129 DefineConstantBuffers(program.info, binding); 131 DefineConstantBuffers(program.info, binding);
130 DefineStorageBuffers(program.info, binding); 132 DefineStorageBuffers(program.info, binding);
131 DefineTextures(program.info, binding); 133 DefineTextures(program.info, binding);
134 DefineTextureBuffers(program.info, binding);
132 DefineAttributeMemAccess(program.info); 135 DefineAttributeMemAccess(program.info);
133 DefineLabels(program); 136 DefineLabels(program);
134} 137}
@@ -541,6 +544,32 @@ void EmitContext::DefineTextures(const Info& info, u32& binding) {
541 } 544 }
542} 545}
543 546
547void EmitContext::DefineTextureBuffers(const Info& info, u32& binding) {
548 if (info.texture_buffer_descriptors.empty()) {
549 return;
550 }
551 const spv::ImageFormat format{spv::ImageFormat::Unknown};
552 image_buffer_type = TypeImage(F32[1], spv::Dim::Buffer, 0U, false, false, 1, format);
553 sampled_texture_buffer_type = TypeSampledImage(image_buffer_type);
554
555 const Id type{TypePointer(spv::StorageClass::UniformConstant, sampled_texture_buffer_type)};
556 texture_buffers.reserve(info.texture_buffer_descriptors.size());
557 for (const TextureBufferDescriptor& desc : info.texture_buffer_descriptors) {
558 if (desc.count != 1) {
559 throw NotImplementedException("Array of texture buffers");
560 }
561 const Id id{AddGlobalVariable(type, spv::StorageClass::UniformConstant)};
562 Decorate(id, spv::Decoration::Binding, binding);
563 Decorate(id, spv::Decoration::DescriptorSet, 0U);
564 Name(id, fmt::format("texbuf{}_{:02x}", desc.cbuf_index, desc.cbuf_offset));
565 texture_buffers.insert(texture_buffers.end(), desc.count, id);
566 if (profile.supported_spirv >= 0x00010400) {
567 interfaces.push_back(id);
568 }
569 binding += desc.count;
570 }
571}
572
544void EmitContext::DefineLabels(IR::Program& program) { 573void EmitContext::DefineLabels(IR::Program& program) {
545 for (IR::Block* const block : program.blocks) { 574 for (IR::Block* const block : program.blocks) {
546 block->SetDefinition(OpLabel()); 575 block->SetDefinition(OpLabel());
diff --git a/src/shader_recompiler/backend/spirv/emit_context.h b/src/shader_recompiler/backend/spirv/emit_context.h
index 7a2ac0511..2a10e94e5 100644
--- a/src/shader_recompiler/backend/spirv/emit_context.h
+++ b/src/shader_recompiler/backend/spirv/emit_context.h
@@ -90,9 +90,13 @@ public:
90 90
91 Id storage_u32{}; 91 Id storage_u32{};
92 92
93 Id image_buffer_type{};
94 Id sampled_texture_buffer_type{};
95
93 std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{}; 96 std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{};
94 std::array<Id, Info::MAX_SSBOS> ssbos{}; 97 std::array<Id, Info::MAX_SSBOS> ssbos{};
95 std::vector<TextureDefinition> textures; 98 std::vector<TextureDefinition> textures;
99 std::vector<Id> texture_buffers;
96 100
97 Id workgroup_id{}; 101 Id workgroup_id{};
98 Id local_invocation_id{}; 102 Id local_invocation_id{};
@@ -151,6 +155,7 @@ private:
151 void DefineConstantBuffers(const Info& info, u32& binding); 155 void DefineConstantBuffers(const Info& info, u32& binding);
152 void DefineStorageBuffers(const Info& info, u32& binding); 156 void DefineStorageBuffers(const Info& info, u32& binding);
153 void DefineTextures(const Info& info, u32& binding); 157 void DefineTextures(const Info& info, u32& binding);
158 void DefineTextureBuffers(const Info& info, u32& binding);
154 void DefineAttributeMemAccess(const Info& info); 159 void DefineAttributeMemAccess(const Info& info);
155 void DefineLabels(IR::Program& program); 160 void DefineLabels(IR::Program& program);
156 161
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 191380db0..32512a0e5 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -249,6 +249,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
249 // TODO: Track this usage 249 // TODO: Track this usage
250 ctx.AddCapability(spv::Capability::ImageGatherExtended); 250 ctx.AddCapability(spv::Capability::ImageGatherExtended);
251 ctx.AddCapability(spv::Capability::ImageQuery); 251 ctx.AddCapability(spv::Capability::ImageQuery);
252 ctx.AddCapability(spv::Capability::SampledBuffer);
252} 253}
253 254
254Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) { 255Id PhiArgDef(EmitContext& ctx, IR::Inst* inst, size_t index) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index fc40615af..525f67c6e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -128,12 +128,18 @@ Id Texture(EmitContext& ctx, const IR::Value& index) {
128 throw NotImplementedException("Indirect texture sample"); 128 throw NotImplementedException("Indirect texture sample");
129} 129}
130 130
131Id TextureImage(EmitContext& ctx, const IR::Value& index) { 131Id TextureImage(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) {
132 if (index.IsImmediate()) { 132 if (!index.IsImmediate()) {
133 throw NotImplementedException("Indirect texture sample");
134 }
135 if (info.type == TextureType::Buffer) {
136 const Id sampler_id{ctx.texture_buffers.at(index.U32())};
137 const Id id{ctx.OpLoad(ctx.sampled_texture_buffer_type, sampler_id)};
138 return ctx.OpImage(ctx.image_buffer_type, id);
139 } else {
133 const TextureDefinition def{ctx.textures.at(index.U32())}; 140 const TextureDefinition def{ctx.textures.at(index.U32())};
134 return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id)); 141 return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id));
135 } 142 }
136 throw NotImplementedException("Indirect texture sample");
137} 143}
138 144
139Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) { 145Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
@@ -297,17 +303,22 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
297 ctx.F32[4], Texture(ctx, index), coords, dref, operands.Mask(), operands.Span()); 303 ctx.F32[4], Texture(ctx, index), coords, dref, operands.Mask(), operands.Span());
298} 304}
299 305
306#pragma optimize("", off)
307
300Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, 308Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
301 Id lod, Id ms) { 309 Id lod, Id ms) {
302 const auto info{inst->Flags<IR::TextureInstInfo>()}; 310 const auto info{inst->Flags<IR::TextureInstInfo>()};
311 if (info.type == TextureType::Buffer) {
312 lod = Id{};
313 }
303 const ImageOperands operands(offset, lod, ms); 314 const ImageOperands operands(offset, lod, ms);
304 return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], 315 return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
305 TextureImage(ctx, index), coords, operands.Mask(), operands.Span()); 316 TextureImage(ctx, index, info), coords, operands.Mask(), operands.Span());
306} 317}
307 318
308Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) { 319Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod) {
309 const auto info{inst->Flags<IR::TextureInstInfo>()}; 320 const auto info{inst->Flags<IR::TextureInstInfo>()};
310 const Id image{TextureImage(ctx, index)}; 321 const Id image{TextureImage(ctx, index, info)};
311 const Id zero{ctx.u32_zero_value}; 322 const Id zero{ctx.u32_zero_value};
312 const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }}; 323 const auto mips{[&] { return ctx.OpImageQueryLevels(ctx.U32[1], image); }};
313 switch (info.type) { 324 switch (info.type) {
@@ -331,6 +342,9 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
331 case TextureType::ShadowArrayCube: 342 case TextureType::ShadowArrayCube:
332 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod), 343 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[3], image, lod),
333 mips()); 344 mips());
345 case TextureType::Buffer:
346 return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySize(ctx.U32[1], image), zero,
347 zero, mips());
334 } 348 }
335 throw LogicError("Unspecified image type {}", info.type.Value()); 349 throw LogicError("Unspecified image type {}", info.type.Value());
336} 350}
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp
index bcb94ce4d..290ce4179 100644
--- a/src/shader_recompiler/ir_opt/texture_pass.cpp
+++ b/src/shader_recompiler/ir_opt/texture_pass.cpp
@@ -147,24 +147,39 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
147 147
148class Descriptors { 148class Descriptors {
149public: 149public:
150 explicit Descriptors(TextureDescriptors& descriptors_) : descriptors{descriptors_} {} 150 explicit Descriptors(TextureDescriptors& texture_descriptors_,
151 TextureBufferDescriptors& texture_buffer_descriptors_)
152 : texture_descriptors{texture_descriptors_}, texture_buffer_descriptors{
153 texture_buffer_descriptors_} {}
154
155 u32 Add(const TextureDescriptor& desc) {
156 return Add(texture_descriptors, desc, [&desc](const auto& existing) {
157 return desc.cbuf_index == existing.cbuf_index &&
158 desc.cbuf_offset == existing.cbuf_offset && desc.type == existing.type;
159 });
160 }
161
162 u32 Add(const TextureBufferDescriptor& desc) {
163 return Add(texture_buffer_descriptors, desc, [&desc](const auto& existing) {
164 return desc.cbuf_index == existing.cbuf_index &&
165 desc.cbuf_offset == existing.cbuf_offset;
166 });
167 }
151 168
152 u32 Add(const TextureDescriptor& descriptor) { 169private:
170 template <typename Descriptors, typename Descriptor, typename Func>
171 static u32 Add(Descriptors& descriptors, const Descriptor& desc, Func&& pred) {
153 // TODO: Handle arrays 172 // TODO: Handle arrays
154 auto it{std::ranges::find_if(descriptors, [&descriptor](const TextureDescriptor& existing) { 173 const auto it{std::ranges::find_if(descriptors, pred)};
155 return descriptor.cbuf_index == existing.cbuf_index &&
156 descriptor.cbuf_offset == existing.cbuf_offset &&
157 descriptor.type == existing.type;
158 })};
159 if (it != descriptors.end()) { 174 if (it != descriptors.end()) {
160 return static_cast<u32>(std::distance(descriptors.begin(), it)); 175 return static_cast<u32>(std::distance(descriptors.begin(), it));
161 } 176 }
162 descriptors.push_back(descriptor); 177 descriptors.push_back(desc);
163 return static_cast<u32>(descriptors.size()) - 1; 178 return static_cast<u32>(descriptors.size()) - 1;
164 } 179 }
165 180
166private: 181 TextureDescriptors& texture_descriptors;
167 TextureDescriptors& descriptors; 182 TextureBufferDescriptors& texture_buffer_descriptors;
168}; 183};
169} // Anonymous namespace 184} // Anonymous namespace
170 185
@@ -185,7 +200,10 @@ void TexturePass(Environment& env, IR::Program& program) {
185 std::stable_sort(to_replace.begin(), to_replace.end(), [](const auto& lhs, const auto& rhs) { 200 std::stable_sort(to_replace.begin(), to_replace.end(), [](const auto& lhs, const auto& rhs) {
186 return lhs.cbuf.index < rhs.cbuf.index; 201 return lhs.cbuf.index < rhs.cbuf.index;
187 }); 202 });
188 Descriptors descriptors{program.info.texture_descriptors}; 203 Descriptors descriptors{
204 program.info.texture_descriptors,
205 program.info.texture_buffer_descriptors,
206 };
189 for (TextureInst& texture_inst : to_replace) { 207 for (TextureInst& texture_inst : to_replace) {
190 // TODO: Handle arrays 208 // TODO: Handle arrays
191 IR::Inst* const inst{texture_inst.inst}; 209 IR::Inst* const inst{texture_inst.inst};
@@ -193,16 +211,42 @@ void TexturePass(Environment& env, IR::Program& program) {
193 211
194 const auto& cbuf{texture_inst.cbuf}; 212 const auto& cbuf{texture_inst.cbuf};
195 auto flags{inst->Flags<IR::TextureInstInfo>()}; 213 auto flags{inst->Flags<IR::TextureInstInfo>()};
196 if (inst->Opcode() == IR::Opcode::ImageQueryDimensions) { 214 switch (inst->Opcode()) {
215 case IR::Opcode::ImageQueryDimensions:
197 flags.type.Assign(env.ReadTextureType(cbuf.index, cbuf.offset)); 216 flags.type.Assign(env.ReadTextureType(cbuf.index, cbuf.offset));
198 inst->SetFlags(flags); 217 inst->SetFlags(flags);
218 break;
219 case IR::Opcode::ImageFetch:
220 if (flags.type != TextureType::Color1D) {
221 break;
222 }
223 if (env.ReadTextureType(cbuf.index, cbuf.offset) == TextureType::Buffer) {
224 // Replace with the bound texture type only when it's a texture buffer
225 // If the instruction is 1D and the bound type is 2D, don't change the code and let
226 // the rasterizer robustness handle it
227 // This happens on Fire Emblem: Three Houses
228 flags.type.Assign(TextureType::Buffer);
229 }
230 inst->SetFlags(flags);
231 break;
232 default:
233 break;
234 }
235 u32 index;
236 if (flags.type == TextureType::Buffer) {
237 index = descriptors.Add(TextureBufferDescriptor{
238 .cbuf_index{cbuf.index},
239 .cbuf_offset{cbuf.offset},
240 .count{1},
241 });
242 } else {
243 index = descriptors.Add(TextureDescriptor{
244 .type{flags.type},
245 .cbuf_index{cbuf.index},
246 .cbuf_offset{cbuf.offset},
247 .count{1},
248 });
199 } 249 }
200 const u32 index{descriptors.Add(TextureDescriptor{
201 .type{flags.type},
202 .cbuf_index{cbuf.index},
203 .cbuf_offset{cbuf.offset},
204 .count{1},
205 })};
206 inst->SetArg(0, IR::Value{index}); 250 inst->SetArg(0, IR::Value{index});
207 } 251 }
208} 252}
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h
index 41bb5b9a1..e6f0de8d8 100644
--- a/src/shader_recompiler/shader_info.h
+++ b/src/shader_recompiler/shader_info.h
@@ -29,6 +29,7 @@ enum class TextureType : u32 {
29 Shadow3D, 29 Shadow3D,
30 ShadowCube, 30 ShadowCube,
31 ShadowArrayCube, 31 ShadowArrayCube,
32 Buffer,
32}; 33};
33 34
34enum class Interpolation { 35enum class Interpolation {
@@ -50,6 +51,13 @@ struct TextureDescriptor {
50}; 51};
51using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>; 52using TextureDescriptors = boost::container::small_vector<TextureDescriptor, 12>;
52 53
54struct TextureBufferDescriptor {
55 u32 cbuf_index;
56 u32 cbuf_offset;
57 u32 count;
58};
59using TextureBufferDescriptors = boost::container::small_vector<TextureBufferDescriptor, 2>;
60
53struct ConstantBufferDescriptor { 61struct ConstantBufferDescriptor {
54 u32 index; 62 u32 index;
55 u32 count; 63 u32 count;
@@ -112,6 +120,7 @@ struct Info {
112 constant_buffer_descriptors; 120 constant_buffer_descriptors;
113 boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; 121 boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors;
114 TextureDescriptors texture_descriptors; 122 TextureDescriptors texture_descriptors;
123 TextureBufferDescriptors texture_buffer_descriptors;
115}; 124};
116 125
117} // namespace Shader 126} // namespace Shader
diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h
index eebe5d569..decf0d32c 100644
--- a/src/video_core/renderer_vulkan/pipeline_helper.h
+++ b/src/video_core/renderer_vulkan/pipeline_helper.h
@@ -93,6 +93,9 @@ public:
93 for ([[maybe_unused]] const auto& desc : info.texture_descriptors) { 93 for ([[maybe_unused]] const auto& desc : info.texture_descriptors) {
94 Add(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stage); 94 Add(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stage);
95 } 95 }
96 for (const auto& desc : info.texture_buffer_descriptors) {
97 Add(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, stage);
98 }
96 } 99 }
97 100
98private: 101private:
@@ -146,6 +149,8 @@ inline VideoCommon::ImageViewType CastType(Shader::TextureType type) {
146 case Shader::TextureType::ColorArrayCube: 149 case Shader::TextureType::ColorArrayCube:
147 case Shader::TextureType::ShadowArrayCube: 150 case Shader::TextureType::ShadowArrayCube:
148 return VideoCommon::ImageViewType::CubeArray; 151 return VideoCommon::ImageViewType::CubeArray;
152 case Shader::TextureType::Buffer:
153 break;
149 } 154 }
150 UNREACHABLE_MSG("Invalid texture type {}", type); 155 UNREACHABLE_MSG("Invalid texture type {}", type);
151 return {}; 156 return {};
@@ -161,6 +166,11 @@ inline void PushImageDescriptors(const Shader::Info& info, const VkSampler* samp
161 update_descriptor_queue.AddSampledImage(vk_image_view, sampler); 166 update_descriptor_queue.AddSampledImage(vk_image_view, sampler);
162 ++index; 167 ++index;
163 } 168 }
169 for (const auto& desc : info.texture_buffer_descriptors) {
170 ImageView& image_view{texture_cache.GetImageView(image_view_ids[index])};
171 update_descriptor_queue.AddTexelBuffer(image_view.BufferView());
172 ++index;
173 }
164} 174}
165 175
166} // namespace Vulkan 176} // 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 0bb5b852d..9922cbd0f 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -93,20 +93,23 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute,
93 const auto& launch_desc{kepler_compute.launch_description}; 93 const auto& launch_desc{kepler_compute.launch_description};
94 const auto& cbufs{launch_desc.const_buffer_config}; 94 const auto& cbufs{launch_desc.const_buffer_config};
95 const bool via_header_index{launch_desc.linked_tsc}; 95 const bool via_header_index{launch_desc.linked_tsc};
96 for (const auto& desc : info.texture_descriptors) { 96 const auto read_handle{[&](u32 cbuf_index, u32 cbuf_offset) {
97 const u32 cbuf_index{desc.cbuf_index};
98 const u32 cbuf_offset{desc.cbuf_offset};
99 ASSERT(((launch_desc.const_buffer_enable_mask >> cbuf_index) & 1) != 0); 97 ASSERT(((launch_desc.const_buffer_enable_mask >> cbuf_index) & 1) != 0);
100
101 const GPUVAddr addr{cbufs[cbuf_index].Address() + cbuf_offset}; 98 const GPUVAddr addr{cbufs[cbuf_index].Address() + cbuf_offset};
102 const u32 raw_handle{gpu_memory.Read<u32>(addr)}; 99 const u32 raw_handle{gpu_memory.Read<u32>(addr)};
103 100 return TextureHandle(raw_handle, via_header_index);
104 const TextureHandle handle(raw_handle, via_header_index); 101 }};
102 for (const auto& desc : info.texture_descriptors) {
103 const TextureHandle handle{read_handle(desc.cbuf_index, desc.cbuf_offset)};
105 image_view_indices.push_back(handle.image); 104 image_view_indices.push_back(handle.image);
106 105
107 Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler); 106 Sampler* const sampler = texture_cache.GetComputeSampler(handle.sampler);
108 samplers.push_back(sampler->Handle()); 107 samplers.push_back(sampler->Handle());
109 } 108 }
109 for (const auto& desc : info.texture_buffer_descriptors) {
110 const TextureHandle handle{read_handle(desc.cbuf_index, desc.cbuf_offset)};
111 image_view_indices.push_back(handle.image);
112 }
110 const std::span indices_span(image_view_indices.data(), image_view_indices.size()); 113 const std::span indices_span(image_view_indices.data(), image_view_indices.size());
111 texture_cache.FillComputeImageViews(indices_span, image_view_ids); 114 texture_cache.FillComputeImageViews(indices_span, image_view_ids);
112 115
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index a0ef0e98b..afdd8b371 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -169,19 +169,23 @@ void GraphicsPipeline::Configure(bool is_indexed) {
169 ++index; 169 ++index;
170 } 170 }
171 const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers}; 171 const auto& cbufs{maxwell3d.state.shader_stages[stage].const_buffers};
172 for (const auto& desc : info.texture_descriptors) { 172 const auto read_handle{[&](u32 cbuf_index, u32 cbuf_offset) {
173 const u32 cbuf_index{desc.cbuf_index};
174 const u32 cbuf_offset{desc.cbuf_offset};
175 ASSERT(cbufs[cbuf_index].enabled); 173 ASSERT(cbufs[cbuf_index].enabled);
176 const GPUVAddr addr{cbufs[cbuf_index].address + cbuf_offset}; 174 const GPUVAddr addr{cbufs[cbuf_index].address + cbuf_offset};
177 const u32 raw_handle{gpu_memory.Read<u32>(addr)}; 175 const u32 raw_handle{gpu_memory.Read<u32>(addr)};
178 176 return TextureHandle(raw_handle, via_header_index);
179 const TextureHandle handle(raw_handle, via_header_index); 177 }};
178 for (const auto& desc : info.texture_descriptors) {
179 const TextureHandle handle{read_handle(desc.cbuf_index, desc.cbuf_offset)};
180 image_view_indices.push_back(handle.image); 180 image_view_indices.push_back(handle.image);
181 181
182 Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.sampler)}; 182 Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.sampler)};
183 samplers.push_back(sampler->Handle()); 183 samplers.push_back(sampler->Handle());
184 } 184 }
185 for (const auto& desc : info.texture_buffer_descriptors) {
186 const TextureHandle handle{read_handle(desc.cbuf_index, desc.cbuf_offset)};
187 image_view_indices.push_back(handle.image);
188 }
185 } 189 }
186 const std::span indices_span(image_view_indices.data(), image_view_indices.size()); 190 const std::span indices_span(image_view_indices.data(), image_view_indices.size());
187 buffer_cache.UpdateGraphicsBuffers(is_indexed); 191 buffer_cache.UpdateGraphicsBuffers(is_indexed);
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 25f592b8a..23bf84a92 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -212,7 +212,7 @@ protected:
212 case Tegra::Texture::TextureType::Texture2DArray: 212 case Tegra::Texture::TextureType::Texture2DArray:
213 return Shader::TextureType::ColorArray2D; 213 return Shader::TextureType::ColorArray2D;
214 case Tegra::Texture::TextureType::Texture1DBuffer: 214 case Tegra::Texture::TextureType::Texture1DBuffer:
215 throw Shader::NotImplementedException("Texture buffer"); 215 return Shader::TextureType::Buffer;
216 case Tegra::Texture::TextureType::TextureCubeArray: 216 case Tegra::Texture::TextureType::TextureCubeArray:
217 return Shader::TextureType::ColorArrayCube; 217 return Shader::TextureType::ColorArrayCube;
218 default: 218 default: