123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- #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;
- }
|