[Vulkan] Fix draw_resolution_scaled_texture_offsets cancelling itself out

The offset was being multiplied by the scale and divided by the host scaled size, which collapsed back to guest step, so the cvar changed nothing on Vulkan while D3D12 stepped host texels. Since the size is already in host texels, dividing the offset by it gives the proper step.

Unnormalized coordinates convert to host texels before the offset add so the offset isn't multiplied along with the coordinate. Folds in the fix for 5841095A.

Co-authored-by: Herman S. <429230+has207@users.noreply.github.com>
This commit is contained in:
goldislead
2026-08-08 10:18:00 -07:00
committed by Radosław Gliński
parent 3eab2b8b39
commit 31168682b0

View File

@@ -1245,12 +1245,9 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
} else { } else {
// kTextureFetch or kGetTextureComputedLod. // kTextureFetch or kGetTextureComputedLod.
// Normalize the XY coordinates, and apply the offset. // Normalize the XY coordinates, and apply the offset. When the texture
// When a texture is from a resolution-scaled resolve, offsets are in // is resolution-scaled, size has already been scaled up to host texels
// guest texels but the size is in host texels. We need to scale offsets // above so dividing the offset by it yields a 1-host-texel step.
// to compensate:
// - For normalized coords: coord + (offset * scale) / size_scaled
// - For unnormalized coords: (coord + offset) * scale / size_scaled
for (uint32_t i = 0; for (uint32_t i = 0;
i <= uint32_t(coordinate_dimension != xenos::FetchOpDimension::k1D); i <= uint32_t(coordinate_dimension != xenos::FetchOpDimension::k1D);
++i) { ++i) {
@@ -1260,15 +1257,10 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
: spv::NoResult; : spv::NoResult;
spv::Id size_component = size[i]; spv::Id size_component = size[i];
if (instr.attributes.unnormalized_coordinates) { if (instr.attributes.unnormalized_coordinates) {
if (component_offset != spv::NoResult) { // Convert the guest-texel coord to host texels for resolution-scaled
coordinate_ref = builder_->createNoContractionBinOp( // textures, since size below is in host texels. Done before the
spv::OpFAdd, type_float_, coordinate_ref, component_offset); // offset add so the offset stays at 1 host texel rather than being
} // multiplied with the coord.
// For resolution-scaled textures with unnormalized coords, we need
// to scale the coordinate (which now includes offset) before
// dividing by the scaled size. This ensures:
// (coord + offset) * scale / size_scaled = (coord + offset) /
// guest_size
if (is_texture_resolved != spv::NoResult && if (is_texture_resolved != spv::NoResult &&
((i == 0 && draw_resolution_scale_x_ > 1) || ((i == 0 && draw_resolution_scale_x_ > 1) ||
(i == 1 && draw_resolution_scale_y_ > 1))) { (i == 1 && draw_resolution_scale_y_ > 1))) {
@@ -1281,32 +1273,19 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
spv::OpSelect, type_float_, is_texture_resolved, scaled_coord, spv::OpSelect, type_float_, is_texture_resolved, scaled_coord,
coordinate_ref); coordinate_ref);
} }
if (component_offset != spv::NoResult) {
coordinate_ref = builder_->createNoContractionBinOp(
spv::OpFAdd, type_float_, coordinate_ref, component_offset);
}
assert_true(size_component != spv::NoResult); assert_true(size_component != spv::NoResult);
coordinate_ref = builder_->createNoContractionBinOp( coordinate_ref = builder_->createNoContractionBinOp(
spv::OpFDiv, type_float_, coordinate_ref, size_component); spv::OpFDiv, type_float_, coordinate_ref, size_component);
} else { } else {
if (component_offset != spv::NoResult) { if (component_offset != spv::NoResult) {
assert_true(size_component != spv::NoResult); assert_true(size_component != spv::NoResult);
// For resolution-scaled textures with normalized coords, scale the
// offset before normalizing. This ensures:
// coord + (offset * scale) / size_scaled = coord + offset /
// guest_size
spv::Id effective_offset = component_offset;
if (is_texture_resolved != spv::NoResult &&
((i == 0 && draw_resolution_scale_x_ > 1) ||
(i == 1 && draw_resolution_scale_y_ > 1))) {
float scale = (i == 0) ? float(draw_resolution_scale_x_)
: float(draw_resolution_scale_y_);
spv::Id scaled_offset = builder_->createNoContractionBinOp(
spv::OpFMul, type_float_, component_offset,
builder_->makeFloatConstant(scale));
effective_offset = builder_->createTriOp(
spv::OpSelect, type_float_, is_texture_resolved,
scaled_offset, component_offset);
}
spv::Id component_offset_normalized = spv::Id component_offset_normalized =
builder_->createNoContractionBinOp( builder_->createNoContractionBinOp(
spv::OpFDiv, type_float_, effective_offset, size_component); spv::OpFDiv, type_float_, component_offset, size_component);
coordinate_ref = builder_->createNoContractionBinOp( coordinate_ref = builder_->createNoContractionBinOp(
spv::OpFAdd, type_float_, coordinate_ref, spv::OpFAdd, type_float_, coordinate_ref,
component_offset_normalized); component_offset_normalized);