[GPU] Apply gradient exponent bias during fetch that's per-axis
The fetch constant carries independent signed exponent biases in [-16, 15] for the horizontal and vertical LOD gradients. Scale the H and V gradients by exp2(lod + bias_h) and exp2(lod + bias_v) respectively in the computed LOD sample path. getCompTexLOD keeps returning the raw queried LOD, treating the adjustment like the fetch-constant LOD bias, which is also not folded into it. Zero, the common case, is a no-op. On the cube implicit-LOD path, where no explicit gradients exist to scale, the greater of the two biases is added to the LOD bias instead - exact when both are equal, erring towards a blurrier mip otherwise. Co-Authored-By: Herman S. <429230+has207@users.noreply.github.com>
This commit is contained in:
committed by
Radosław Gliński
parent
090cecd1b8
commit
0f2980de44
@@ -114,7 +114,7 @@ class DxbcShaderTranslator : public ShaderTranslator {
|
||||
// If anything in this is structure is changed in a way not compatible with
|
||||
// the previous layout, invalidate the pipeline storages by increasing this
|
||||
// version number (0xYYYYMMDD)!
|
||||
static constexpr uint32_t kVersion = 0x20260802;
|
||||
static constexpr uint32_t kVersion = 0x20260803;
|
||||
|
||||
enum class DepthStencilMode : uint32_t {
|
||||
kNoModifiers,
|
||||
|
||||
@@ -1628,13 +1628,12 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
|
||||
}
|
||||
assert_not_zero(grad_component_count);
|
||||
uint32_t grad_mask = (1 << grad_component_count) - 1;
|
||||
// Convert the bias to a gradient scale.
|
||||
// Convert the bias to a gradient scale, and merge the per-axis
|
||||
// gradient exponent biases into it. Zero (common case) is a no-op.
|
||||
// getCompTexLOD keeps returning the raw queried LOD, treating the
|
||||
// adjustment like the fetch constant LOD bias, which is also not
|
||||
// folded into it.
|
||||
a_.OpExp(lod_dest, lod_src);
|
||||
// FIXME(Triang3l): Gradient exponent adjustment is currently not done
|
||||
// in getCompTexLOD, so don't do it here too.
|
||||
#if 0
|
||||
// Extract gradient exponent biases from the fetch constant and merge
|
||||
// them with the LOD bias.
|
||||
a_.OpIBFE(dxbc::Dest::R(grad_h_lod_temp, 0b0011), dxbc::Src::LU(5),
|
||||
dxbc::Src::LU(22, 27, 0, 0),
|
||||
RequestTextureFetchConstantWord(tfetch_index, 4));
|
||||
@@ -1645,7 +1644,6 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
|
||||
dxbc::Src::R(grad_h_lod_temp, dxbc::Src::kYYYY));
|
||||
a_.OpMul(lod_dest, lod_src,
|
||||
dxbc::Src::R(grad_h_lod_temp, dxbc::Src::kXXXX));
|
||||
#endif
|
||||
// Obtain the gradients and apply biases to them.
|
||||
// For 1D textures, always use automatic gradients. For wide 1D
|
||||
// textures, coordinates have been remapped to 2D, and register
|
||||
@@ -1657,16 +1655,9 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
|
||||
// Register gradients are already in the cube space for cube maps.
|
||||
a_.OpMul(dxbc::Dest::R(grad_h_lod_temp, grad_mask),
|
||||
dxbc::Src::R(system_temp_grad_h_lod_), lod_src);
|
||||
// FIXME(Triang3l): Gradient exponent adjustment is currently not
|
||||
// done in getCompTexLOD, so don't do it here too.
|
||||
#if 0
|
||||
a_.OpMul(dxbc::Dest::R(grad_v_temp, grad_mask),
|
||||
dxbc::Src::R(system_temp_grad_v_vfetch_address_),
|
||||
dxbc::Src::R(grad_v_temp, dxbc::Src::kWWWW));
|
||||
#else
|
||||
a_.OpMul(dxbc::Dest::R(grad_v_temp, grad_mask),
|
||||
dxbc::Src::R(system_temp_grad_v_vfetch_address_), lod_src);
|
||||
#endif
|
||||
// TODO(Triang3l): Are cube map register gradients unnormalized if
|
||||
// the coordinates themselves are unnormalized?
|
||||
if (instr.attributes.unnormalized_coordinates &&
|
||||
@@ -1705,16 +1696,9 @@ void DxbcShaderTranslator::ProcessTextureFetchInstruction(
|
||||
dxbc::Src::R(grad_h_lod_temp), lod_src);
|
||||
a_.OpDerivRTYCoarse(dxbc::Dest::R(grad_v_temp, grad_mask),
|
||||
dxbc::Src::R(coord_and_sampler_temp));
|
||||
// FIXME(Triang3l): Gradient exponent adjustment is currently not
|
||||
// done in getCompTexLOD, so don't do it here too.
|
||||
#if 0
|
||||
a_.OpMul(dxbc::Dest::R(grad_v_temp, grad_mask),
|
||||
dxbc::Src::R(grad_v_temp),
|
||||
dxbc::Src::R(grad_v_temp, dxbc::Src::kWWWW));
|
||||
#else
|
||||
a_.OpMul(dxbc::Dest::R(grad_v_temp, grad_mask),
|
||||
dxbc::Src::R(grad_v_temp), lod_src);
|
||||
#endif
|
||||
}
|
||||
if (coordinate_dimension == xenos::FetchOpDimension::k1D) {
|
||||
// Pad the gradients to 2D because 1D textures are fetched as 2D
|
||||
|
||||
@@ -34,7 +34,7 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||
// TODO(Triang3l): Change to 0xYYYYMMDD once it's out of the rapid
|
||||
// prototyping stage (easier to do small granular updates with an
|
||||
// incremental counter).
|
||||
static constexpr uint32_t kVersion = 16;
|
||||
static constexpr uint32_t kVersion = 17;
|
||||
|
||||
enum class DepthStencilMode : uint32_t {
|
||||
kNoModifiers,
|
||||
|
||||
@@ -1792,18 +1792,58 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||
!instr.attributes.use_register_gradients &&
|
||||
instr.dimension == xenos::FetchOpDimension::kCube;
|
||||
|
||||
if (use_lod_bias) {
|
||||
// The per-axis gradient exponent biases can't be applied to the
|
||||
// host's implicit gradients, so we approximate them by adding the
|
||||
// greater of the two to the LOD bias. Scaling both gradients by 2^n
|
||||
// shifts the computed LOD by n, so this is exact whenever both biases
|
||||
// are equal, and biases a blurrier mip rather than a shimmering one.
|
||||
spv::Id grad_exp_adjust_max = builder_->createBinBuiltinCall(
|
||||
type_int_, ext_inst_glsl_std_450_, GLSLstd450SMax,
|
||||
builder_->createTriOp(spv::OpBitFieldSExtract, type_int_,
|
||||
fetch_constant_word_4_signed,
|
||||
builder_->makeUintConstant(22),
|
||||
builder_->makeUintConstant(5)),
|
||||
builder_->createTriOp(spv::OpBitFieldSExtract, type_int_,
|
||||
fetch_constant_word_4_signed,
|
||||
builder_->makeUintConstant(27),
|
||||
builder_->makeUintConstant(5)));
|
||||
lod = builder_->createNoContractionBinOp(
|
||||
spv::OpFAdd, type_float_, lod,
|
||||
builder_->createUnaryOp(spv::OpConvertSToF, type_float_,
|
||||
grad_exp_adjust_max));
|
||||
}
|
||||
// Calculate the gradients for sampling the texture if needed.
|
||||
// 2D vectors for k1D (because 1D images are emulated as 2D arrays),
|
||||
// k2D.
|
||||
// 3D vectors for k3DOrStacked, kCube.
|
||||
spv::Id gradients_h = spv::NoResult, gradients_v = spv::NoResult;
|
||||
if (use_computed_lod && !use_lod_bias) {
|
||||
// TODO(Triang3l): Gradient exponent adjustment is currently not done
|
||||
// in getCompTexLOD, so not doing it here too for now. Apply the
|
||||
// gradient exponent biases from the word 4 of the fetch constant in
|
||||
// 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);
|
||||
// Per-axis gradient exponent biases (LodBiasH/V) from word 4: h in
|
||||
// bits 22:26, v in bits 27:31. Applied here in the sample path like
|
||||
// the fetch-constant LOD bias (getCompTexLOD returns the raw queried
|
||||
// LOD, so neither bias is folded into it). Zero (the common case) is
|
||||
// a no-op.
|
||||
spv::Id grad_exp_adjust_h = builder_->createUnaryOp(
|
||||
spv::OpConvertSToF, type_float_,
|
||||
builder_->createTriOp(spv::OpBitFieldSExtract, type_int_,
|
||||
fetch_constant_word_4_signed,
|
||||
builder_->makeUintConstant(22),
|
||||
builder_->makeUintConstant(5)));
|
||||
spv::Id grad_exp_adjust_v = builder_->createUnaryOp(
|
||||
spv::OpConvertSToF, type_float_,
|
||||
builder_->createTriOp(spv::OpBitFieldSExtract, type_int_,
|
||||
fetch_constant_word_4_signed,
|
||||
builder_->makeUintConstant(27),
|
||||
builder_->makeUintConstant(5)));
|
||||
spv::Id lod_gradient_scale_h = builder_->createUnaryBuiltinCall(
|
||||
type_float_, ext_inst_glsl_std_450_, GLSLstd450Exp2,
|
||||
builder_->createNoContractionBinOp(spv::OpFAdd, type_float_, lod,
|
||||
grad_exp_adjust_h));
|
||||
spv::Id lod_gradient_scale_v = builder_->createUnaryBuiltinCall(
|
||||
type_float_, ext_inst_glsl_std_450_, GLSLstd450Exp2,
|
||||
builder_->createNoContractionBinOp(spv::OpFAdd, type_float_, lod,
|
||||
grad_exp_adjust_v));
|
||||
switch (coordinate_dimension) {
|
||||
case xenos::FetchOpDimension::k1D: {
|
||||
spv::Id gradient_h_x, gradient_v_x;
|
||||
@@ -1828,13 +1868,13 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||
gradient_v_y = builder_->createUnaryOp(
|
||||
spv::OpDPdyCoarse, type_float_, coordinates[1]);
|
||||
gradient_h_x = builder_->createNoContractionBinOp(
|
||||
spv::OpFMul, type_float_, gradient_h_x, lod_gradient_scale);
|
||||
spv::OpFMul, type_float_, gradient_h_x, lod_gradient_scale_h);
|
||||
gradient_v_x = builder_->createNoContractionBinOp(
|
||||
spv::OpFMul, type_float_, gradient_v_x, lod_gradient_scale);
|
||||
spv::OpFMul, type_float_, gradient_v_x, lod_gradient_scale_v);
|
||||
gradient_h_y = builder_->createNoContractionBinOp(
|
||||
spv::OpFMul, type_float_, gradient_h_y, lod_gradient_scale);
|
||||
spv::OpFMul, type_float_, gradient_h_y, lod_gradient_scale_h);
|
||||
gradient_v_y = builder_->createNoContractionBinOp(
|
||||
spv::OpFMul, type_float_, gradient_v_y, lod_gradient_scale);
|
||||
spv::OpFMul, type_float_, gradient_v_y, lod_gradient_scale_v);
|
||||
// 1D textures are sampled as 2D arrays - need 2-component
|
||||
// gradients.
|
||||
id_vector_temp_.clear();
|
||||
@@ -1895,10 +1935,10 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||
}
|
||||
gradients_h = builder_->createNoContractionBinOp(
|
||||
spv::OpVectorTimesScalar, type_float2_, gradients_h,
|
||||
lod_gradient_scale);
|
||||
lod_gradient_scale_h);
|
||||
gradients_v = builder_->createNoContractionBinOp(
|
||||
spv::OpVectorTimesScalar, type_float2_, gradients_v,
|
||||
lod_gradient_scale);
|
||||
lod_gradient_scale_v);
|
||||
} break;
|
||||
case xenos::FetchOpDimension::k3DOrStacked: {
|
||||
if (instr.attributes.use_register_gradients) {
|
||||
@@ -1942,10 +1982,10 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||
}
|
||||
gradients_h = builder_->createNoContractionBinOp(
|
||||
spv::OpVectorTimesScalar, type_float3_, gradients_h,
|
||||
lod_gradient_scale);
|
||||
lod_gradient_scale_h);
|
||||
gradients_v = builder_->createNoContractionBinOp(
|
||||
spv::OpVectorTimesScalar, type_float3_, gradients_v,
|
||||
lod_gradient_scale);
|
||||
lod_gradient_scale_v);
|
||||
} break;
|
||||
case xenos::FetchOpDimension::kCube: {
|
||||
// Only register gradients reach here (auto-LOD uses implicit LOD
|
||||
@@ -1959,10 +1999,10 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||
spv::NoPrecision);
|
||||
gradients_h = builder_->createNoContractionBinOp(
|
||||
spv::OpVectorTimesScalar, type_float3_, gradients_h,
|
||||
lod_gradient_scale);
|
||||
lod_gradient_scale_h);
|
||||
gradients_v = builder_->createNoContractionBinOp(
|
||||
spv::OpVectorTimesScalar, type_float3_, gradients_v,
|
||||
lod_gradient_scale);
|
||||
lod_gradient_scale_v);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user