221 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			HLSL
		
	
	
	
	
	
			
		
		
	
	
			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;
 | |
| }
 |