UnityGame/Library/PackageCache/com.unity.render-pipelines.core/ShaderLibrary/VirtualTexturing.hlsl
2024-10-27 10:53:47 +03:00

221 lines
7.6 KiB
HLSL

#include "GraniteShaderLibBase.hlsl"
#define VtAddressMode_Wrap 0
#define VtAddressMode_Clamp 1
#define VtAddressMode_Udim 2
#define VtFilter_Anisotropic 0
#define VtLevel_Automatic 0
#define VtLevel_Lod 1
#define VtLevel_Bias 2
#define VtLevel_Derivatives 3
#define VtUvSpace_Regular 0
#define VtUvSpace_PreTransformed 1
#define VtSampleQuality_Low 0
#define VtSampleQuality_High 1
struct VtInputParameters
{
float2 uv;
float lodOrOffset;
float2 dx;
float2 dy;
int addressMode;
int filterMode;
int levelMode;
int uvMode;
int sampleQuality;
int enableGlobalMipBias;
};
int VirtualTexturingLookup(
in GraniteConstantBuffers grCB,
in GraniteTranslationTexture translationTable,
in VtInputParameters input,
out GraniteLookupData graniteLookupData,
out float4 resolveResult
)
{
GraniteStreamingTextureConstantBuffer grSTCB = grCB.streamingTextureBuffer;
GraniteTilesetConstantBuffer tsCB = grCB.tilesetBuffer;
float2 texCoord = input.uv;
float2 dx;
float2 dy;
float mipLevel; //interger
if (input.levelMode == VtLevel_Automatic)
{
dx = ddx(texCoord);
dy = ddy(texCoord);
}
else if (input.levelMode == VtLevel_Bias)
{
// We can't simply add the bias after the mip-calculation since the derivatives
// are also used when sampling the cache so make sure we apply bias by scaling derivatives
if ( input.sampleQuality == VtSampleQuality_High )
{
float offsetPow2 = pow(2.0f, input.lodOrOffset);
dx = ddx(texCoord) * offsetPow2;
dy = ddy(texCoord) * offsetPow2;
}
// In low quality we don't care about cache derivatives and will add the bias later
else
{
dx = ddx(texCoord);
dy = ddy(texCoord);
}
}
else if (input.levelMode == VtLevel_Derivatives)
{
dx = input.dx;
dy = input.dy;
}
else /*input.levelMode == VtLevel_Lod*/
{
//gra_TrilinearOffset ensures we do round-nearest for no-trilinear and
//round-floor for trilinear.
float clampedLevel = clamp(input.lodOrOffset + gra_TrilinearOffset, 0.0f, gra_NumLevels);
mipLevel = floor(clampedLevel);
dx = float2(frac(clampedLevel), 0.0f); // trilinear blend ratio
dy = float2(0.0f,0.0f);
}
// Transform the derivatives to atlas space if needed
if (input.uvMode == VtUvSpace_Regular && input.levelMode != VtLevel_Lod)
{
dx = gra_Transform.zw * dx;
dy = gra_Transform.zw * dy;
}
if (input.levelMode != VtLevel_Lod)
{
#ifdef VT_GLOBAL_MIP_BIAS_MULTIPLIER
if (input.enableGlobalMipBias)
{
dx *= VT_GLOBAL_MIP_BIAS_MULTIPLIER;
dy *= VT_GLOBAL_MIP_BIAS_MULTIPLIER;
}
#endif
mipLevel = GranitePrivate_CalcMiplevelAnisotropic(grCB.tilesetBuffer, grCB.streamingTextureBuffer, dx, dy);
// Simply add it here derivatives are wrong from this point onwards but not used anymore
if ( input.sampleQuality == VtSampleQuality_Low && input.levelMode == VtLevel_Bias)
{
mipLevel += input.lodOrOffset;
// GranitePrivate_CalcMiplevelAnisotropic will already clamp between 0 gra_NumLevels
// But we need to do it again here. The alternative is modifying dx,dy before passing to
// GranitePrivate_CalcMiplevelAnisotropic adding a pow2 + 4 fmuls so probably
// the exra clamp is more appropriate here.
mipLevel = clamp(mipLevel, 0.0f, gra_NumLevels);
}
mipLevel = floor(mipLevel + 0.5f); //round nearest
}
// Apply clamp/wrap mode if needed and transform into atlas space
// If the user passes in pre-transformed texture coords clamping and wrapping should be handled by the user
if (input.uvMode == VtUvSpace_Regular)
{
if (input.addressMode == VtAddressMode_Wrap)
{
texCoord = frac(input.uv);
}
else if (input.addressMode == VtAddressMode_Clamp)
{
float2 epsilon2 = float2(gra_AssetWidthRcp, gra_AssetHeightRcp);
texCoord = clamp(input.uv, epsilon2, float2(1,1) - epsilon2);
}
else if (input.addressMode == VtAddressMode_Udim)
{
// not modified (i.e outside of the 0-1 range, atlas transform below will take care of it)
texCoord = input.uv;
}
texCoord = Granite_Transform(gra_StreamingTextureCB, texCoord);
}
// calculate resolver data
float2 level0NumTiles = float2(gra_Level0NumTilesX, gra_Level0NumTilesX*gra_NumTilesYScale);
float2 virtualTilesUv = floor(texCoord * level0NumTiles * pow(0.5, mipLevel));
resolveResult = GranitePrivate_MakeResolveOutput(tsCB, virtualTilesUv, mipLevel);
float4 translationTableData;
if (input.levelMode != VtLevel_Lod)
{
// Look up the physical page indexes and the number of pages on the mipmap
// level of the page in the translation texture
// Note: this is equal for both anisotropic and linear sampling
// We could use a sample bias here for 'auto' mip level detection
#if (GRA_LOAD_INSTR==0)
translationTableData = GranitePrivate_SampleLevel_Translation(translationTable, texCoord, mipLevel);
#else
translationTableData = GranitePrivate_Load(translationTable, gra_Int3(virtualTilesUv, mipLevel));
#endif
}
else
{
// Look up the physical page indexes and the number of pages on the mipmap
// level of the page in the translation texture
// Note: this is equal for both anisotropic and linear sampling
// We could use a sample bias here for 'auto' mip level detection
#if (GRA_LOAD_INSTR==0)
translationTableData = GranitePrivate_SampleLevel_Translation(translationTable, texCoord, mipLevel);
#else
translationTableData = GranitePrivate_Load(translationTable, gra_Int3(virtualTilesUv, mipLevel));
#endif
}
graniteLookupData.translationTableData = translationTableData;
graniteLookupData.textureCoordinates = texCoord;
graniteLookupData.dX = dx;
graniteLookupData.dY = dy;
return 1;
}
int VirtualTexturingSample(
in GraniteTilesetConstantBuffer tsCB,
in GraniteLookupData graniteLookupData,
in GraniteCacheTexture cacheTexture,
in int layer,
in int levelMode,
in int quality,
out float4 result)
{
// Convert from pixels to [0-1] and look up in the physical page texture
float2 deltaScale;
float3 cacheCoord = GranitePrivate_TranslateCoord(tsCB, graniteLookupData.textureCoordinates, graniteLookupData.translationTableData, layer, deltaScale);
if ( levelMode != VtLevel_Lod )
{
if ( quality == VtSampleQuality_Low )
{
// This leads to small artefacts at tile borders but is generally not noticable unless the texture
// is greatly magnified
result = GranitePrivate_SampleArray(cacheTexture, cacheCoord);
}
else /* quality == VtSampleQuality_High */
{
deltaScale *= gra_LodBiasPow2;
// Calculate the delta scale this works by first converting the [0-1] texcoord deltas to
// pixel deltas on the current mip level, then dividing by the cache size to convert to [0-1] cache deltas
float2 sampDeltaX = graniteLookupData.dX*deltaScale;
float2 sampDeltaY = graniteLookupData.dY*deltaScale;
result = GranitePrivate_SampleGradArray(cacheTexture, cacheCoord, sampDeltaX, sampDeltaY);
}
}
else
{
result = GranitePrivate_SampleLevelArray(cacheTexture, cacheCoord, graniteLookupData.dX.x);
}
return 1;
}