diff --git a/src/xenia/gpu/shader_translator.cc b/src/xenia/gpu/shader_translator.cc index 928d365b4..4634ef34d 100644 --- a/src/xenia/gpu/shader_translator.cc +++ b/src/xenia/gpu/shader_translator.cc @@ -54,7 +54,9 @@ void ShaderTranslator::Reset() { register_count_ = 64; total_attrib_count_ = 0; vertex_bindings_.clear(); + unique_vertex_bindings_ = 0; texture_bindings_.clear(); + unique_texture_bindings_ = 0; std::memset(&constant_register_map_, 0, sizeof(constant_register_map_)); for (size_t i = 0; i < xe::countof(writes_color_targets_); ++i) { writes_color_targets_[i] = false; @@ -300,7 +302,7 @@ void ShaderTranslator::GatherVertexBindingInformation( if (!attrib) { assert_not_zero(fetch_instr.attributes.stride); VertexBinding vertex_binding; - vertex_binding.binding_index = static_cast(vertex_bindings_.size()); + vertex_binding.binding_index = int(vertex_bindings_.size()); vertex_binding.fetch_constant = op.fetch_constant_index(); vertex_binding.stride_words = fetch_instr.attributes.stride; vertex_binding.attributes.push_back({}); @@ -328,9 +330,23 @@ void ShaderTranslator::GatherTextureBindingInformation( break; } Shader::TextureBinding binding; - binding.binding_index = texture_bindings_.size(); + binding.binding_index = -1; ParseTextureFetchInstruction(op, &binding.fetch_instr); binding.fetch_constant = binding.fetch_instr.operands[1].storage_index; + + // Check and see if this fetch constant was previously used... + for (auto& tex_binding : texture_bindings_) { + if (tex_binding.fetch_constant == binding.fetch_constant) { + binding.binding_index = tex_binding.binding_index; + break; + } + } + + if (binding.binding_index == -1) { + // Assign a unique binding index. + binding.binding_index = unique_texture_bindings_++; + } + texture_bindings_.emplace_back(std::move(binding)); } diff --git a/src/xenia/gpu/shader_translator.h b/src/xenia/gpu/shader_translator.h index a1d9213ca..267104470 100644 --- a/src/xenia/gpu/shader_translator.h +++ b/src/xenia/gpu/shader_translator.h @@ -212,6 +212,9 @@ class ShaderTranslator { int total_attrib_count_ = 0; std::vector vertex_bindings_; std::vector texture_bindings_; + uint32_t unique_vertex_bindings_ = 0; + uint32_t unique_texture_bindings_ = 0; + Shader::ConstantRegisterMap constant_register_map_ = {0}; bool writes_color_targets_[4] = {false, false, false, false}; diff --git a/src/xenia/gpu/spirv_shader_translator.cc b/src/xenia/gpu/spirv_shader_translator.cc index 155363535..4d01dc570 100644 --- a/src/xenia/gpu/spirv_shader_translator.cc +++ b/src/xenia/gpu/spirv_shader_translator.cc @@ -189,32 +189,42 @@ void SpirvShaderTranslator::StartTranslation() { push_consts_ = b.createVariable(spv::StorageClass::StorageClassPushConstant, push_constants_type, "push_consts"); - image_2d_type_ = - b.makeImageType(float_type_, spv::Dim::Dim2D, false, false, false, 1, - spv::ImageFormat::ImageFormatUnknown); - image_3d_type_ = - b.makeImageType(float_type_, spv::Dim::Dim3D, false, false, false, 1, - spv::ImageFormat::ImageFormatUnknown); - image_cube_type_ = - b.makeImageType(float_type_, spv::Dim::DimCube, false, false, false, 1, - spv::ImageFormat::ImageFormatUnknown); + if (!texture_bindings().empty()) { + image_2d_type_ = + b.makeImageType(float_type_, spv::Dim::Dim2D, false, false, false, 1, + spv::ImageFormat::ImageFormatUnknown); + image_3d_type_ = + b.makeImageType(float_type_, spv::Dim::Dim3D, false, false, false, 1, + spv::ImageFormat::ImageFormatUnknown); + image_cube_type_ = + b.makeImageType(float_type_, spv::Dim::DimCube, false, false, false, 1, + spv::ImageFormat::ImageFormatUnknown); - // Texture bindings - Id tex_t[] = {b.makeSampledImageType(image_2d_type_), - b.makeSampledImageType(image_3d_type_), - b.makeSampledImageType(image_cube_type_)}; + // Texture bindings + Id tex_t[] = {b.makeSampledImageType(image_2d_type_), + b.makeSampledImageType(image_3d_type_), + b.makeSampledImageType(image_cube_type_)}; - Id tex_a_t[] = {b.makeArrayType(tex_t[0], b.makeUintConstant(32), 0), - b.makeArrayType(tex_t[1], b.makeUintConstant(32), 0), - b.makeArrayType(tex_t[2], b.makeUintConstant(32), 0)}; + uint32_t num_tex_bindings = uint32_t(texture_bindings().size()); + Id tex_a_t[] = { + b.makeArrayType(tex_t[0], b.makeUintConstant(num_tex_bindings), 0), + b.makeArrayType(tex_t[1], b.makeUintConstant(num_tex_bindings), 0), + b.makeArrayType(tex_t[2], b.makeUintConstant(num_tex_bindings), 0)}; - // Create 3 texture types, all aliased on the same binding - for (int i = 0; i < 3; i++) { - tex_[i] = b.createVariable(spv::StorageClass::StorageClassUniformConstant, - tex_a_t[i], - xe::format_string("textures%dD", i + 2).c_str()); - b.addDecoration(tex_[i], spv::Decoration::DecorationDescriptorSet, 1); - b.addDecoration(tex_[i], spv::Decoration::DecorationBinding, 0); + // Create 3 texture types, all aliased on the same binding + for (int i = 0; i < 3; i++) { + tex_[i] = b.createVariable( + spv::StorageClass::StorageClassUniformConstant, tex_a_t[i], + xe::format_string("textures%dD", i + 2).c_str()); + b.addDecoration(tex_[i], spv::Decoration::DecorationDescriptorSet, 1); + b.addDecoration(tex_[i], spv::Decoration::DecorationBinding, 0); + } + + // Set up the map from binding -> ssbo index + for (const auto& binding : texture_bindings()) { + tex_binding_map_[binding.fetch_constant] = + uint32_t(binding.binding_index); + } } // Interpolators. @@ -1760,7 +1770,8 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( switch (instr.opcode) { case FetchOpcode::kTextureFetch: { - auto texture_index = b.makeUintConstant(instr.operands[1].storage_index); + auto texture_index = + b.makeUintConstant(tex_binding_map_[instr.operands[1].storage_index]); auto texture_ptr = b.createAccessChain(spv::StorageClass::StorageClassUniformConstant, tex_[dim_idx], std::vector({texture_index})); @@ -1829,7 +1840,8 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( false, false, false, false, params); } break; case FetchOpcode::kGetTextureGradients: { - auto texture_index = b.makeUintConstant(instr.operands[2].storage_index); + auto texture_index = + b.makeUintConstant(tex_binding_map_[instr.operands[2].storage_index]); auto texture_ptr = b.createAccessChain(spv::StorageClass::StorageClassUniformConstant, tex_[dim_idx], std::vector({texture_index})); @@ -1849,7 +1861,8 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( } break; case FetchOpcode::kGetTextureWeights: { // fract(src0 * textureSize); - auto texture_index = b.makeUintConstant(instr.operands[1].storage_index); + auto texture_index = + b.makeUintConstant(tex_binding_map_[instr.operands[1].storage_index]); auto texture_ptr = b.createAccessChain(spv::StorageClass::StorageClassUniformConstant, tex_[dim_idx], std::vector({texture_index})); diff --git a/src/xenia/gpu/spirv_shader_translator.h b/src/xenia/gpu/spirv_shader_translator.h index dd72f6f66..c1e97d127 100644 --- a/src/xenia/gpu/spirv_shader_translator.h +++ b/src/xenia/gpu/spirv_shader_translator.h @@ -12,6 +12,7 @@ #include #include +#include #include #include "third_party/glslang-spirv/SpvBuilder.h" @@ -157,8 +158,9 @@ class SpirvShaderTranslator : public ShaderTranslator { spv::Id frag_outputs_ = 0, frag_depth_ = 0; spv::Id samplers_ = 0; spv::Id tex_[3] = {0}; // Images {2D, 3D, Cube} - spv::Id vtx_ = 0; // Vertex buffer array (32 runtime arrays) - std::map vtx_binding_map_; + std::unordered_map tex_binding_map_; + spv::Id vtx_ = 0; // Vertex buffer array (32 runtime arrays) + std::unordered_map vtx_binding_map_; // SPIR-V IDs that are part of the in/out interface. std::vector interface_ids_; diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index 7f1f344d6..32bfef36f 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -1442,11 +1442,14 @@ bool TextureCache::SetupTextureBinding(VkCommandBuffer command_buffer, &update_set_info->image_writes[update_set_info->image_write_count]; update_set_info->image_write_count++; + // Sanity check, we only have 32 binding slots. + assert(binding.binding_index < 32); + image_write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; image_write->pNext = nullptr; // image_write->dstSet is set later... image_write->dstBinding = 0; - image_write->dstArrayElement = binding.fetch_constant; + image_write->dstArrayElement = uint32_t(binding.binding_index); image_write->descriptorCount = 1; image_write->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; image_write->pImageInfo = image_info;