diff --git a/src/xenia/gpu/dxbc_shader_translator_fetch.cc b/src/xenia/gpu/dxbc_shader_translator_fetch.cc index 3f8e5f5f8..26146ff5d 100644 --- a/src/xenia/gpu/dxbc_shader_translator_fetch.cc +++ b/src/xenia/gpu/dxbc_shader_translator_fetch.cc @@ -713,6 +713,11 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( } uint32_t tfetch_index = instr.operands[1].storage_index; + xenos::FetchOpDimension coordinate_dimension = + instr.dimension == xenos::FetchOpDimension::k1D && + instr.operands[0].component_count > 1 + ? xenos::FetchOpDimension::k2D + : instr.dimension; // Whether to use gradients (implicit or explicit) for LOD calculation. bool use_computed_lod = @@ -755,7 +760,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( // be floored as expected, but the left/upper pixel is still sampled // instead. constexpr float rounding_offset = 1.5f / 1024.0f; - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: offsets[0] = instr.attributes.offset_x + rounding_offset; if (instr.opcode == FetchOpcode::kGetTextureWeights) { @@ -824,7 +829,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( // calculation with normalized coordinates (or, if a texture filled with LOD // indices is used, coordinates will need to be normalized as normally). if (!instr.attributes.unnormalized_coordinates) { - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: size_needed_components |= used_result_nonzero_components & 0b0001; break; @@ -841,7 +846,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( // Size needed for normalization (or, for stacked texture layers, // denormalization) and for offsets. size_needed_components |= offsets_not_zero; - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: if (instr.attributes.unnormalized_coordinates) { size_needed_components |= 0b0001; @@ -882,7 +887,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( uint32_t size_and_is_3d_temp = size_needed_components ? PushSystemTemp() : UINT32_MAX; if (size_needed_components) { - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: a_.OpUBFE(dxbc::Dest::R(size_and_is_3d_temp, 0b0001), dxbc::Src::LU(24), dxbc::Src::LU(0), @@ -1058,10 +1063,11 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( bool coord_operand_temp_pushed = false; dxbc::Src coord_operand = LoadOperand( instr.operands[0], - (1 << xenos::GetFetchOpDimensionComponentCount(instr.dimension)) - 1, + (1 << xenos::GetFetchOpDimensionComponentCount(coordinate_dimension)) - + 1, coord_operand_temp_pushed); uint32_t normalized_components = 0b0000; - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: normalized_components = 0b0001; break; @@ -1217,7 +1223,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( } } } - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: // Pad to 2D array coordinates. a_.OpMov(dxbc::Dest::R(coord_and_sampler_temp, 0b0110), @@ -1521,7 +1527,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( } if (use_computed_lod) { grad_v_temp = PushSystemTemp(); - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: grad_component_count = 1; break; @@ -1615,7 +1621,7 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction( dxbc::Src::R(grad_v_temp), lod_src); #endif } - if (instr.dimension == xenos::FetchOpDimension::k1D) { + if (coordinate_dimension == xenos::FetchOpDimension::k1D) { // Pad the gradients to 2D because 1D textures are fetched as 2D // arrays. a_.OpMov(dxbc::Dest::R(grad_h_lod_temp, 0b0010), diff --git a/src/xenia/gpu/shader_translator.cc b/src/xenia/gpu/shader_translator.cc index d381edc94..a7eb4e6ff 100644 --- a/src/xenia/gpu/shader_translator.cc +++ b/src/xenia/gpu/shader_translator.cc @@ -1121,6 +1121,18 @@ void ParseTextureFetchInstruction(const TextureFetchInstruction& op, opcode_info.override_component_count ? opcode_info.override_component_count : xenos::GetFetchOpDimensionComponentCount(op.dimension()); + if (op.opcode() == FetchOpcode::kTextureFetch && + op.dimension() == xenos::FetchOpDimension::k1D) { + uint32_t src_swizzle = op.src_swizzle(); + uint32_t src_select_x = src_swizzle & 0x3; + if (((src_swizzle >> 2) & 0x3) != src_select_x || + ((src_swizzle >> 4) & 0x3) != src_select_x) { + // 1D may provide XY for a 2D fetch constant. 545407D4's UI shader does + // this, and it seems like we have to support it, even if it doesn't + // make sense on paper. + src_op.component_count = 2; + } + } uint32_t swizzle = op.src_swizzle(); for (uint32_t j = 0; j < src_op.component_count; ++j, swizzle >>= 2) { src_op.components[j] = GetSwizzleFromComponentIndex(swizzle & 0x3); diff --git a/src/xenia/gpu/spirv_shader_translator_fetch.cc b/src/xenia/gpu/spirv_shader_translator_fetch.cc index 03d3c665c..c1e254623 100644 --- a/src/xenia/gpu/spirv_shader_translator_fetch.cc +++ b/src/xenia/gpu/spirv_shader_translator_fetch.cc @@ -659,6 +659,11 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( uint32_t fetch_constant_index = instr.operands[1].storage_index; uint32_t fetch_constant_word_0_index = 6 * fetch_constant_index; + xenos::FetchOpDimension coordinate_dimension = + instr.dimension == xenos::FetchOpDimension::k1D && + instr.operands[0].component_count > 1 + ? xenos::FetchOpDimension::k2D + : instr.dimension; spv::Id sampler = spv::NoResult; spv::Id image_2d_array_or_cube_unsigned = spv::NoResult; @@ -770,7 +775,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( // `mul` gives a value that would be floored as expected, but the // left/upper pixel is still sampled instead. constexpr float kRoundingOffset = 1.5f / 1024.0f; - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: offset_values[0] = instr.attributes.offset_x + kRoundingOffset; if (instr.opcode == ucode::FetchOpcode::kGetTextureWeights) { @@ -847,7 +852,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( // texture filled with LOD indices is used, coordinates will need to be // normalized as normally). if (!instr.attributes.unnormalized_coordinates) { - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: size_needed_components |= used_result_nonzero_components & 0b0001; break; @@ -864,7 +869,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( // Size needed for normalization (or, for stacked texture layers, // denormalization) and for offsets. size_needed_components |= offsets_not_zero; - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: if (instr.attributes.unnormalized_coordinates) { size_needed_components |= 0b0001; @@ -939,7 +944,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( spv::StorageClassUniform, uniform_fetch_constants_, id_vector_temp_), spv::NoPrecision); - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: { if (size_needed_components & 0b1) { size[0] = builder_->createTriOp( @@ -1143,8 +1148,8 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( uint32_t coordinates_needed_components = instr.opcode == ucode::FetchOpcode::kGetTextureWeights ? used_result_nonzero_components - : ((UINT32_C(1) - << xenos::GetFetchOpDimensionComponentCount(instr.dimension)) - + : ((UINT32_C(1) << xenos::GetFetchOpDimensionComponentCount( + coordinate_dimension)) - 1); assert_not_zero(coordinates_needed_components); spv::Id coordinates_operand = @@ -1215,7 +1220,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( // - For normalized coords: coord + (offset * scale) / size_scaled // - For unnormalized coords: (coord + offset) * scale / size_scaled for (uint32_t i = 0; - i <= uint32_t(instr.dimension != xenos::FetchOpDimension::k1D); + i <= uint32_t(coordinate_dimension != xenos::FetchOpDimension::k1D); ++i) { spv::Id& coordinate_ref = coordinates[i]; spv::Id component_offset = @@ -1691,7 +1696,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction( // the future when it's handled in getCompTexLOD somehow. spv::Id lod_gradient_scale = builder_->createUnaryBuiltinCall( type_float_, ext_inst_glsl_std_450_, GLSLstd450Exp2, lod); - switch (instr.dimension) { + switch (coordinate_dimension) { case xenos::FetchOpDimension::k1D: { spv::Id gradient_h_1d, gradient_v_1d; if (instr.attributes.use_register_gradients) {