A game about forced loneliness, made by TACStudios
1#ifndef TEXTURESTACK_include 2#define TEXTURESTACK_include 3 4#define GRA_HLSL_5 1 5#define GRA_ROW_MAJOR 1 6#define GRA_TEXTURE_ARRAY_SUPPORT 1 7#define GRA_PACK_RESOLVE_OUTPUT 0 8#if SHADER_API_PSSL 9#define GRA_NO_UNORM 1 10#endif 11#include "VirtualTexturing.hlsl" 12#include "Packing.hlsl" 13 14/* 15 Warning: the following guide is subject to change due to VT's experimental status. 16 For more information, visit https://docs.unity3d.com/ScriptReference/UnityEngine.VirtualTexturingModule.html. 17 18 This header adds the following pseudo definitions. Actual types etc may vary depending 19 on vt- being on or off. 20 21 struct StackInfo { opaque struct ... } 22 struct VTProperty { opaque struct ... } 23 struct VTPropertyWithTextureType { VTProperty + int layerTextureType[4] } 24 25 StackInfo PrepareVT(VTProperty vtProperty, VtInputParameters vtParams) 26 float4 SampleVTLayerWithTextureType(VTPropertyWithTextureType vtPropWithTexType, VtInputParameters vtParams, StackInfo info, [immediate] int layerIndex) 27 ("int layerIndex" cannot be a variable or expression, must be an immediate constant) 28 29 To use this in your materials add the following to various locations in the shader: 30 31 In shaderlab "Properties" section add: 32 33 [TextureStack.MyFancyStack] DiffuseTexture ("DiffuseTexture", 2D) = "white" {} 34 [TextureStack.MyFancyStack] NormalTexture ("NormalTexture", 2D) = "white" {} 35 36 This will declare a texture stack with two textures. 37 38 Then add the following to the PerMaterial constant buffer: 39 40 CBUFFER_START(UnityPerMaterial) 41 ... 42 DECLARE_STACK_CB(MyFancyStack) 43 ... 44 CBUFFER_END 45 46 Then in your shader root add the following: 47 48 ... 49 50 DECLARE_STACK(MyFancyStack, DiffuseTexture) 51 or 52 DECLARE_STACK2(MyFancyStack, DiffuseTexture, NormalTexture) 53 or 54 DECLARE_STACK3(MyFancyStack, TextureSlot1, TextureSlot2, TextureSlot2) 55 etc... 56 57 NOTE: The Stack shaderlab property and DECLARE_STACKn define need to match i.e. the same name and same texture slots. 58 59 Then in the pixel shader function (likely somewhere at the beginning) do: 60 61 VTPropertyWithTextureType vtPropWithTexType = AddTextureType(BuildVTProperties_MyFancyStack(), TEXTURETYPE_DEFAULT, TEXTURETYPE_DEFAULT, ...); 62 // or: TEXTURETYPE_NORMALTANGENTSPACE / TEXTURETYPE_NORMALOBJECTSPACE, match with each texture slot's actual texture type. 63 64 VtInputParameters vtParams; 65 vtParams.uv = uv; 66 vtParams.lodOrOffset = 0.0f; 67 ... 68 StackInfo info = PrepareVT(vtPropWithTexType.vtProperty, vtParams); 69 70 Then later on when you want to sample the actual texture do a call(s): 71 72 // LayerIndex must be an immediate constant, do not use a variable or expression. 73 float4 color1 = SampleVTLayerWithTextureType(vtPropWithTexType, vtParams, info, 0); 74 float4 color2 = SampleVTLayerWithTextureType(vtPropWithTexType, vtParams, info, 1); 75 ... 76 77 The above steps can be repeated for multiple stacks. But be sure that when using the SampleVTLayerWithTextureType you always 78 pass in the VtInputParameters + the result of the AddTextureType and PrepareVT for the correct stack the texture belongs to. 79 80 Also, for tiles to be automatically loaded, you need to write to the VT Feedback texture 81 (SV_Target1) by yourself in the "ForwardOnly" pass. For example: 82 83 #if defined(UNITY_VIRTUAL_TEXTURING) && defined(SHADER_API_PSSL) 84 // Prevent loss of precision on some Sony platforms. 85 #pragma PSSL_target_output_format(target 1 FMT_32_ABGR) 86 #endif 87 88 void Frag(PackedVaryingsToPS packedInput, out float4 outColor : SV_Target0 89 #ifdef UNITY_VIRTUAL_TEXTURING 90 , out float4 outVTFeedback : SV_Target1 91 #endif 92 , ...) 93 { 94 ... (PrepareVT and SampleVTLayerWithTextureType called at some point) 95 96 #ifdef UNITY_VIRTUAL_TEXTURING 97 float4 resolveOutput = GetResolveOutput(info); 98 float4 vtPackedFeedback = GetPackedVTFeedback(resolveOutput); 99 outVTFeedback = PackVTFeedbackWithAlpha(vtPackedFeedback, screenSpacePos.xy, color1.a); 100 // Include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" 101 // for "PackVTFeedbackWithAlpha". 102 #endif 103 104 ... 105 } 106 107 If multiple stacks are present on the same pixel, alternate between resolve outputs in the following manner 108 and pass the result to "GetPackedVTFeedback", etc... to ensure that all relevant tiles get loaded properly: 109 110 ... 111 float4 resolveOutput = GetResolveOutput(info); 112 float4 resolveOutput2 = GetResolveOutput(info2); 113 float4 resolveOutputs[2] = { resolveOutput, resolveOutput2 }; 114 115 uint pixelColumn = screenSpacePos.x; 116 float4 actualResolveOutput = resolveOutputs[(pixelColumn + _FrameCount) % 2]; 117 float4 vtPackedFeedback = GetPackedVTFeedback(actualResolveOutput); 118 outVTFeedback = PackVTFeedbackWithAlpha(vtPackedFeedback, ... 119 ... 120*/ 121 122#if defined(UNITY_VIRTUAL_TEXTURING) && !defined(FORCE_VIRTUAL_TEXTURING_OFF) 123 124struct StackInfo 125{ 126 GraniteLookupData lookupData; 127 GraniteLODLookupData lookupDataLod; 128 float4 resolveOutput; 129}; 130 131struct VTProperty 132{ 133 GraniteConstantBuffers grCB; 134 GraniteTranslationTexture translationTable; 135 GraniteCacheTexture cacheLayer[4]; 136 int layerCount; 137 int layerIndex[4]; 138}; 139 140#ifdef TEXTURESTACK_CLAMP 141 #define GR_LOOKUP Granite_Lookup_Clamp_Linear 142 #define GR_LOOKUP_LOD Granite_Lookup_Clamp 143#else 144 #define GR_LOOKUP Granite_Lookup_Anisotropic 145 #define GR_LOOKUP_LOD Granite_Lookup 146#endif 147 148// This can be used by certain resolver implementations to override screen space derivatives 149#ifndef RESOLVE_SCALE_OVERRIDE 150#define RESOLVE_SCALE_OVERRIDE float2(1,1) 151#endif 152 153#ifndef VT_CACHE_SAMPLER 154 #define VT_CACHE_SAMPLER sampler_clamp_trilinear_aniso4 155 SAMPLER(VT_CACHE_SAMPLER); 156#endif 157 158StructuredBuffer<GraniteTilesetConstantBuffer> _VTTilesetBuffer; 159 160#define DECLARE_STACK_CB(stackName) \ 161 float4 stackName##_atlasparams[2] 162 163#define DECLARE_STACK_BASE(stackName) \ 164TEXTURE2D(stackName##_transtab);\ 165SAMPLER(sampler##stackName##_transtab);\ 166\ 167GraniteTilesetConstantBuffer GetConstantBuffer_##stackName() \ 168{ \ 169 int idx = (int)stackName##_atlasparams[1].w; \ 170 GraniteTilesetConstantBuffer graniteParamBlock; \ 171 graniteParamBlock = _VTTilesetBuffer[idx]; \ 172 \ 173 graniteParamBlock.data[0][2][0] *= RESOLVE_SCALE_OVERRIDE.x; \ 174 graniteParamBlock.data[0][3][0] *= RESOLVE_SCALE_OVERRIDE.y; \ 175 \ 176 return graniteParamBlock; \ 177} \ 178StackInfo PrepareVT_##stackName(VtInputParameters par)\ 179{\ 180 GraniteStreamingTextureConstantBuffer textureParamBlock;\ 181 textureParamBlock.data[0] = stackName##_atlasparams[0];\ 182 textureParamBlock.data[1] = stackName##_atlasparams[1];\ 183\ 184 GraniteTilesetConstantBuffer graniteParamBlock = GetConstantBuffer_##stackName(); \ 185\ 186 GraniteConstantBuffers grCB;\ 187 grCB.tilesetBuffer = graniteParamBlock;\ 188 grCB.streamingTextureBuffer = textureParamBlock;\ 189\ 190 GraniteTranslationTexture translationTable;\ 191 translationTable.Texture = stackName##_transtab;\ 192 translationTable.Sampler = sampler##stackName##_transtab;\ 193\ 194 StackInfo info;\ 195 VirtualTexturingLookup(grCB, translationTable, par, info.lookupData, info.resolveOutput);\ 196 return info;\ 197} 198 199// TODO: we could replace all uses of GetConstantBuffer_*() with this one: 200GraniteTilesetConstantBuffer GetConstantBuffer(GraniteStreamingTextureConstantBuffer textureParamBlock) 201{ 202 int idx = (int)textureParamBlock.data[1].w; 203 GraniteTilesetConstantBuffer graniteParamBlock; 204 graniteParamBlock = _VTTilesetBuffer[idx]; 205 206 graniteParamBlock.data[0][2][0] *= RESOLVE_SCALE_OVERRIDE.x; 207 graniteParamBlock.data[0][3][0] *= RESOLVE_SCALE_OVERRIDE.y; 208 209 return graniteParamBlock; 210} 211 212#define jj2(a, b) a##b 213#define jj(a, b) jj2(a, b) 214 215#define DECLARE_STACK_LAYER(stackName, layerSamplerName, layerIndex) \ 216TEXTURE2D_ARRAY(stackName##_c##layerIndex); 217 218#define DECLARE_BUILD_PROPERTIES(stackName, layers, layer0Index, layer1Index, layer2Index, layer3Index)\ 219 VTProperty BuildVTProperties_##stackName()\ 220 {\ 221 VTProperty vtProperty; \ 222 \ 223 GraniteStreamingTextureConstantBuffer textureParamBlock; \ 224 textureParamBlock.data[0] = stackName##_atlasparams[0]; \ 225 textureParamBlock.data[1] = stackName##_atlasparams[1]; \ 226 \ 227 vtProperty.grCB.tilesetBuffer = GetConstantBuffer(textureParamBlock); \ 228 vtProperty.grCB.streamingTextureBuffer = textureParamBlock; \ 229 \ 230 vtProperty.translationTable.Texture = stackName##_transtab; \ 231 vtProperty.translationTable.Sampler = sampler##stackName##_transtab; \ 232 \ 233 vtProperty.layerCount = layers; \ 234 vtProperty.layerIndex[0] = layer0Index; \ 235 vtProperty.layerIndex[1] = layer1Index; \ 236 vtProperty.layerIndex[2] = layer2Index; \ 237 vtProperty.layerIndex[3] = layer3Index; \ 238 \ 239 vtProperty.cacheLayer[0].TextureArray = stackName##_c##layer0Index; \ 240 ASSIGN_SAMPLER(vtProperty.cacheLayer[0].Sampler, VT_CACHE_SAMPLER);\ 241 vtProperty.cacheLayer[1].TextureArray = stackName##_c##layer1Index; \ 242 ASSIGN_SAMPLER(vtProperty.cacheLayer[1].Sampler, VT_CACHE_SAMPLER);\ 243 vtProperty.cacheLayer[2].TextureArray = stackName##_c##layer2Index; \ 244 ASSIGN_SAMPLER(vtProperty.cacheLayer[2].Sampler, VT_CACHE_SAMPLER);\ 245 vtProperty.cacheLayer[3].TextureArray = stackName##_c##layer3Index; \ 246 ASSIGN_SAMPLER(vtProperty.cacheLayer[3].Sampler, VT_CACHE_SAMPLER);\ 247 \ 248 return vtProperty; \ 249 } 250 251#define DECLARE_STACK(stackName, layer0SamplerName)\ 252 DECLARE_STACK_BASE(stackName)\ 253 DECLARE_STACK_LAYER(stackName, layer0SamplerName, 0)\ 254 DECLARE_BUILD_PROPERTIES(stackName, 1, 0, 0, 0, 0) 255 256#define DECLARE_STACK2(stackName, layer0SamplerName, layer1SamplerName)\ 257 DECLARE_STACK_BASE(stackName)\ 258 DECLARE_STACK_LAYER(stackName, layer0SamplerName, 0)\ 259 DECLARE_STACK_LAYER(stackName, layer1SamplerName, 1)\ 260 DECLARE_BUILD_PROPERTIES(stackName, 2, 0, 1, 1, 1) 261 262#define DECLARE_STACK3(stackName, layer0SamplerName, layer1SamplerName, layer2SamplerName)\ 263 DECLARE_STACK_BASE(stackName)\ 264 DECLARE_STACK_LAYER(stackName, layer0SamplerName, 0)\ 265 DECLARE_STACK_LAYER(stackName, layer1SamplerName, 1)\ 266 DECLARE_STACK_LAYER(stackName, layer2SamplerName, 2)\ 267 DECLARE_BUILD_PROPERTIES(stackName, 3, 0, 1, 2, 2) 268 269#define DECLARE_STACK4(stackName, layer0SamplerName, layer1SamplerName, layer2SamplerName, layer3SamplerName)\ 270 DECLARE_STACK_BASE(stackName)\ 271 DECLARE_STACK_LAYER(stackName, layer0SamplerName, 0)\ 272 DECLARE_STACK_LAYER(stackName, layer1SamplerName, 1)\ 273 DECLARE_STACK_LAYER(stackName, layer2SamplerName, 2)\ 274 DECLARE_STACK_LAYER(stackName, layer3SamplerName, 3)\ 275 DECLARE_BUILD_PROPERTIES(stackName, 4, 0, 1, 2, 3) 276 277#define PrepareStack(inputParams, stackName) PrepareVT_##stackName(inputParams) 278#define SampleStack(info, lodMode, quality, textureName) SampleVT_##textureName(info, lodMode, quality) 279#define GetResolveOutput(info) info.resolveOutput 280#define PackResolveOutput(output) Granite_PackTileId(output) 281 282StackInfo PrepareVT(VTProperty vtProperty, VtInputParameters vtParams) 283{ 284 StackInfo info; 285 VirtualTexturingLookup(vtProperty.grCB, vtProperty.translationTable, vtParams, info.lookupData, info.resolveOutput); 286 return info; 287} 288 289// NOTE: layerIndex here can only be an immediate constant (i.e. 0,1,2, or 3) -- it CANNOT be a variable or expression 290// this is because we use macro concatentation on it when VT is disabled 291float4 SampleVTLayer(VTProperty vtProperty, VtInputParameters vtParams, StackInfo info, int layerIndex) 292{ 293 float4 result; 294 VirtualTexturingSample(vtProperty.grCB.tilesetBuffer, info.lookupData, vtProperty.cacheLayer[layerIndex], vtProperty.layerIndex[layerIndex], vtParams.levelMode, vtParams.sampleQuality, result); 295 return result; 296} 297 298float4 GetPackedVTFeedback(float4 feedback) 299{ 300 return Granite_PackTileId(feedback); 301} 302 303#define VIRTUAL_TEXTURING_SHADER_ENABLED 304 305#else 306// Virtual Texturing Disabled -- fallback to regular texture sampling 307 308#define DECLARE_BUILD_PROPERTIES(stackName, layers, layer0, layer1, layer2, layer3)\ 309 VTProperty BuildVTProperties_##stackName()\ 310 {\ 311 VTProperty vtProperty; \ 312 \ 313 vtProperty.layerCount = layers; \ 314 vtProperty.Layer0 = layer0; \ 315 vtProperty.Layer1 = layer1; \ 316 vtProperty.Layer2 = layer2; \ 317 vtProperty.Layer3 = layer3; \ 318 \ 319 ASSIGN_SAMPLER(vtProperty.samplerLayer0, sampler##layer0); \ 320 ASSIGN_SAMPLER(vtProperty.samplerLayer1, sampler##layer1); \ 321 ASSIGN_SAMPLER(vtProperty.samplerLayer2, sampler##layer2); \ 322 ASSIGN_SAMPLER(vtProperty.samplerLayer3, sampler##layer3); \ 323 \ 324 return vtProperty; \ 325 } 326 327// Stacks amount to nothing when VT is off 328#define DECLARE_STACK(stackName, layer0) \ 329 DECLARE_BUILD_PROPERTIES(stackName, 1, layer0, layer0, layer0, layer0) 330 331#define DECLARE_STACK2(stackName, layer0, layer1) \ 332 DECLARE_BUILD_PROPERTIES(stackName, 2, layer0, layer1, layer1, layer1) 333 334#define DECLARE_STACK3(stackName, layer0, layer1, layer2) \ 335 DECLARE_BUILD_PROPERTIES(stackName, 3, layer0, layer1, layer2, layer2) 336 337#define DECLARE_STACK4(stackName, layer0, layer1, layer2, layer3) \ 338 DECLARE_BUILD_PROPERTIES(stackName, 4, layer0, layer1, layer2, layer3) 339 340#define DECLARE_STACK_CB(stackName) 341 342// Info is just the uv's 343// We could do a straight #define StackInfo float2 but this makes it a bit more type safe 344// and allows us to do things like function overloads,... 345struct StackInfo 346{ 347 VtInputParameters vt; 348}; 349 350struct VTProperty 351{ 352 int layerCount; 353 TEXTURE2D(Layer0); 354 TEXTURE2D(Layer1); 355 TEXTURE2D(Layer2); 356 TEXTURE2D(Layer3); 357 SAMPLER(samplerLayer0); 358 SAMPLER(samplerLayer1); 359 SAMPLER(samplerLayer2); 360 SAMPLER(samplerLayer3); 361}; 362 363StackInfo MakeStackInfo(VtInputParameters vt) 364{ 365 StackInfo result; 366 result.vt = vt; 367 return result; 368} 369 370// Prepare just passes the texture coord around 371#define PrepareStack(inputParams, stackName) MakeStackInfo(inputParams) 372 373// Sample just samples the texture 374#define SampleStack(info, vtLevelMode, quality, texture) \ 375 SampleVTFallbackToTexture(info, vtLevelMode, TEXTURE2D_ARGS(texture, sampler##texture)) 376 377 378float4 SampleVTFallbackToTexture(StackInfo info, int vtLevelMode, TEXTURE2D_PARAM(layerTexture, layerSampler)) 379{ 380 if (info.vt.enableGlobalMipBias) 381 { 382 if (vtLevelMode == VtLevel_Automatic) 383 return SAMPLE_TEXTURE2D(layerTexture, layerSampler, info.vt.uv); 384 else if (vtLevelMode == VtLevel_Lod) 385 return SAMPLE_TEXTURE2D_LOD(layerTexture, layerSampler, info.vt.uv, info.vt.lodOrOffset); 386 else if (vtLevelMode == VtLevel_Bias) 387 return SAMPLE_TEXTURE2D_BIAS(layerTexture, layerSampler, info.vt.uv, info.vt.lodOrOffset); 388 else // vtLevelMode == VtLevel_Derivatives 389 return SAMPLE_TEXTURE2D_GRAD(layerTexture, layerSampler, info.vt.uv, info.vt.dx, info.vt.dy); 390 } 391 else 392 { 393 if (vtLevelMode == VtLevel_Automatic) 394 return PLATFORM_SAMPLE_TEXTURE2D(layerTexture, layerSampler, info.vt.uv); 395 else if (vtLevelMode == VtLevel_Lod) 396 return PLATFORM_SAMPLE_TEXTURE2D_LOD(layerTexture, layerSampler, info.vt.uv, info.vt.lodOrOffset); 397 else if (vtLevelMode == VtLevel_Bias) 398 return PLATFORM_SAMPLE_TEXTURE2D_BIAS(layerTexture, layerSampler, info.vt.uv, info.vt.lodOrOffset); 399 else // vtLevelMode == VtLevel_Derivatives 400 return PLATFORM_SAMPLE_TEXTURE2D_GRAD(layerTexture, layerSampler, info.vt.uv, info.vt.dx, info.vt.dy); 401 } 402} 403 404StackInfo PrepareVT(VTProperty vtProperty, VtInputParameters vtParams) 405{ 406 StackInfo result; 407 result.vt = vtParams; 408 return result; 409} 410 411// NOTE: layerIndex here can only be an immediate constant (i.e. 0,1,2, or 3) -- it CANNOT be a variable or expression 412// this is because we use macro concatentation on it when VT is disabled 413#define SampleVTLayer(vtProperty, vtParams, info, layerIndex) \ 414 SampleVTFallbackToTexture(info, vtParams.levelMode, TEXTURE2D_ARGS(vtProperty.Layer##layerIndex, vtProperty.samplerLayer##layerIndex)) 415 416// Resolve does nothing 417#define GetResolveOutput(info) float4(1,1,1,1) 418#define PackResolveOutput(output) output 419#define GetPackedVTFeedback(feedback) feedback 420 421#endif 422 423 424 425// Shared code between VT enabled and VT disabled, adding TextureType handling 426 427// these texture types should be kept in sync with LayerTextureType in C# code 428#define TEXTURETYPE_DEFAULT 0 // LayerTextureType.Default 429#define TEXTURETYPE_NORMALTANGENTSPACE 1 // LayerTextureType.NormalTangentSpace 430#define TEXTURETYPE_NORMALOBJECTSPACE 2 // LayerTextureType.NormalObjectSpace 431 432struct VTPropertyWithTextureType 433{ 434 VTProperty vtProperty; 435 int layerTextureType[4]; 436}; 437 438VTPropertyWithTextureType AddTextureType(VTProperty vtProperty, int layer0TextureType, int layer1TextureType = TEXTURETYPE_DEFAULT, int layer2TextureType = TEXTURETYPE_DEFAULT, int layer3TextureType = TEXTURETYPE_DEFAULT) 439{ 440 VTPropertyWithTextureType result; 441 result.vtProperty = vtProperty; 442 result.layerTextureType[0] = layer0TextureType; 443 result.layerTextureType[1] = layer1TextureType; 444 result.layerTextureType[2] = layer2TextureType; 445 result.layerTextureType[3] = layer3TextureType; 446 return result; 447} 448 449float4 ApplyTextureType(float4 value, int textureType) 450{ 451 // NOTE: when textureType is a compile-time constant, the branches compile out 452 if (textureType == TEXTURETYPE_NORMALTANGENTSPACE) 453 { 454 value.rgb = UnpackNormalmapRGorAG(value); 455 } 456 else if (textureType == TEXTURETYPE_NORMALOBJECTSPACE) 457 { 458 value.rgb = UnpackNormalRGB(value); 459 } 460 return value; 461} 462 463// if we _could_ express it as a function, the function signature would be: 464// float4 SampleVTLayerWithTextureType(VTPropertyWithTextureType vtPropWithTexType, VtInputParameters vtParams, StackInfo info, [immediate] int layerIndex) 465// NOTE: layerIndex here can only be an immediate constant (i.e. 0,1,2, or 3) -- it CANNOT be a variable or expression 466// this is because we use macro concatentation on it when VT is disabled 467 468#define SampleVTLayerWithTextureType(vtPropWithTexType, vtParams, info, layerIndex) \ 469 ApplyTextureType(SampleVTLayer(vtPropWithTexType.vtProperty, vtParams, info, layerIndex), vtPropWithTexType.layerTextureType[layerIndex]) 470 471#endif //TEXTURESTACK_include