A game about forced loneliness, made by TACStudios
at master 771 lines 36 kB view raw
1#ifndef UNITY_DEBUG_MIPMAP_STREAMING_INCLUDED 2#define UNITY_DEBUG_MIPMAP_STREAMING_INCLUDED 3 4#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Debug.hlsl" 5 6// Indices for Mipmap Debug Legend Strings 7#define _kNotStreamingIndex 0 8#define _kStreamingIndex 1 9#define _kStreamingManuallyIndex 2 10#define _kStatusNoTextureIndex 3 11#define _kStatusWarningIndex 4 12#define _kStatusUnknownIndex 5 13#define _kStatusStreamerDisabledIndex 6 14#define _kStatusMessageNoMipMapIndex 7 15#define _kStatusMessageNotSetToStreamIndex 8 16#define _kStatusMessageNoAsyncIndex 9 17#define _kStatusMessageTerrainIndex 10 18#define _kStatusNoTexturesIndex 11 19#define _kStatusSomeTexturesHaveIssues 12 20#define _kStatusAllTexturesAreStreaming 13 21#define _kStatusAllTexturesAreStreamingSomeManually 14 22#define _kStatusNoTexturesAreStreaming 15 23#define _kStatusSomeTexturesAreStreaming 16 24#define _kStatusSomeTexturesAreStreamingSomeManually 17 25 26#define _kNoMipCountIndex 18 27#define _kTooManyMipsIndex 19 28 29#define _kHighPixelDensityIndex 20 30#define _kLowPixelDensityIndex 21 31 32#define _kLowPriorityIndex 22 33#define _kHighPriorityIndex 23 34 35#define _kBudgetSavingMips 24 36#define _kBudgetSavingMipsWithCache 25 37#define _kBudgetNothingSaved 26 38#define _kBudgetMissingMips 27 39 40#define _kRecentlyUpdated 28 41#define _kNotRecentlyUpdated 29 42 43static const uint kMipmapDebugLegendStrings[][32] = 44{ 45 // Status 46 {13, 'N','o','t',' ','s','t','r','e','a','m','i','n','g','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 47 { 9, 'S','t','r','e','a','m','i','n','g','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 48 {31, 'S','t','r','e','a','m','i','n','g',' ','(','m','a','n','u','a','l','l','y',' ','v','i','a',' ','s','c','r','i','p','t',')'}, 49 {18, 'N','o',' ','t','e','x','t','u','r','e',' ','i','n',' ','s','l','o','t','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 50 { 7, 'W','a','r','n','i','n','g','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 51 {21, 'U','n','k','n','o','w','n',' ','(','n','o',' ','r','e','n','d','e','r','e','r',')','.','.','.','.','.','.','.','.','.','.'}, 52 {24, 'T','e','x','t','u','r','e','S','t','r','e','a','m','e','r',' ','d','i','s','a','b','l','e','d','.','.','.','.','.','.','.'}, 53 {19, 'N','o',' ','m','i','p','m','a','p',' ','g','e','n','e','r','a','t','e','d','.','.','.','.','.','.','.','.','.','.','.','.'}, 54 {21, 'S','t','r','e','a','m','i','n','g',' ','n','o','t',' ','e','n','a','b','l','e','d','.','.','.','.','.','.','.','.','.','.'}, 55 {19, 'C','a','n','n','o','t',' ','s','t','r','e','a','m',' ','a','s','y','n','c','.','.','.','.','.','.','.','.','.','.','.','.'}, 56 { 7, 'T','e','r','r','a','i','n','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 57 58 {23, 'N','o',' ','t','e','x','t','u','r','e','s',' ','o','n',' ','m','a','t','e','r','i','a','l','.','.','.','.','.','.','.','.'}, 59 {15, 'I','s','s','u','e','s',' ','d','e','t','e','c','t','e','d','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 60 {13, 'A','l','l',' ','s','t','r','e','a','m','i','n','g','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 61 {29, 'A','l','l',' ','s','t','r','e','a','m','i','n','g',' ','(','s','o','m','e',' ','m','a','n','u','a','l','l','y',')','.','.'}, 62 {21, 'N','o',' ','t','e','x','t','u','r','e','s',' ','s','t','r','e','a','m','i','n','g','.','.','.','.','.','.','.','.','.','.'}, 63 {14, 'S','o','m','e',' ','s','t','r','e','a','m','i','n','g','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 64 {30, 'S','o','m','e',' ','s','t','r','e','a','m','i','n','g',' ','(','s','o','m','e',' ','m','a','n','u','a','l','l','y',')','.'}, 65 66 // MipCount 67 {16, 'I','n','v','a','l','i','d',' ','m','i','p','C','o','u','n','t','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 68 {26, 'M','o','r','e',' ','t','h','a','n',' ','1','4',' ','m','i','p','s',' ','u','p','l','o','a','d','e','d','.','.','.','.','.'}, 69 70 // Ratio 71 {18, 'H','i','g','h',' ','p','i','x','e','l',' ','d','e','n','s','i','t','y','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 72 {17, 'L','o','w',' ','p','i','x','e','l',' ','d','e','n','s','i','t','y','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 73 74 // Priorities 75 {10, 'L','o','w',' ','(','-','1','2','8',')','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 76 {10, 'H','i','g','h',' ','(','1','2','7',')','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 77 78 // Performance 79 {10, 'M','i','p','s',' ','s','a','v','e','d','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 80 {31, 'M','i','p','s',' ','s','a','v','e','d',' ','(','s','o','m','e',' ','c','a','c','h','e','d',' ','o','n',' ','G','P','U',')'}, 81 {30, 'N','o',' ','s','a','v','i','n','g','s',' ','(','a','l','l',' ','m','i','p','s',' ','r','e','q','u','i','r','e','d',')','.'}, 82 {30, 'N','o','t',' ','a','l','l',' ','r','e','q','u','i','r','e','d',' ','m','i','p','s',' ','u','p','l','o','a','d','e','d','.'}, 83 84 // RecentlyUpdated 85 {13, 'J','u','s','t',' ','s','t','r','e','a','m','e','d','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.'}, 86 {21, 'N','o','t',' ','r','e','c','e','n','t','l','y',' ','s','t','r','e','a','m','e','d','.','.','.','.','.','.','.','.','.','.'}, 87}; 88 89void DrawString(int stringIdx, uint2 unormCoord, float3 textColor, uint2 textLocation, bool alignRight, inout float3 outputColor) 90{ 91 const uint stringSize = kMipmapDebugLegendStrings[stringIdx][0]; 92 const int direction = alignRight ? -1 : 1; 93 uint i = alignRight ? stringSize : 1; 94 95 [fastopt] for (; alignRight ? i > 0 : i <= stringSize; i += direction) 96 DrawCharacter(kMipmapDebugLegendStrings[stringIdx][i], textColor, unormCoord, textLocation, outputColor.rgb, direction); 97} 98 99void DrawString(int stringIdx, uint2 unormCoord, float3 textColor, uint2 textLocation, inout float3 outputColor) 100{ 101 DrawString(stringIdx, unormCoord, textColor, textLocation, false, outputColor); 102} 103 104// mipInfo : 105// x = quality settings maxLevelReduction 106// y = original mip count for texture (if it has not been set, it's not a streamed texture) 107// z = desired on screen mip level 108// w = 0 109uint GetMaxLevelReduction(float4 mipInfo) { return max(1, uint(mipInfo.x)); } // Always has a minimum value of 1. 110uint GetTextureAssetMipCount(float4 mipInfo) { return uint(mipInfo.y); } 111uint GetDesiredMipLevel(float4 mipInfo) { return uint(mipInfo.z); } 112 113// Mipmap Debug Status Codes found in StreamInfo.z (Per-Texture) 114#define kMipmapDebugStatusCodeNotSet 0 // No status code has been set by the streamer 115#define kMipmapDebugStatusCodeStreamerDisabled 1 // Not streaming: streamer disabled 116#define kMipmapDebugStatusCodeNoTexture 2 // Nothing there, empty slot 117#define kMipmapDebugStatusCodeNoMipMap 3 // Not streaming: no mips 118#define kMipmapDebugStatusCodeNotSetToStream 4 // Not streaming: streaming not enabled for this texture 119#define kMipmapDebugStatusCodeNoAsync 5 // Not streaming: cannot asyncStream 120#define kMipmapDebugStatusCodeTerrain 6 // Not streaming: terrain 121#define kMipmapDebugStatusCodeInvalidStreamingIndex 7 // Not streaming: invalid streaming index (issue at Unity side?) 122#define kMipmapDebugStatusCodeManuallyRequested 8 // Streaming manually through script (RequestedMipmapLevel) 123 124// Mipmap Debug Status Code Flags found in StreamInfo.z (Per-Material) 125#define kMipmapDebugStatusCodeFlagNoTexturesSet 0 // No textures have been set on the material, all slots are empty 126#define kMipmapDebugStatusCodeFlagHasStreamingTextures 1 // 1 or more textures assigned to the material are streaming 127#define kMipmapDebugStatusCodeFlagHasNonStreamingTextures 2 // 1 or more textures assigned to the material aren't streaming 128#define kMipmapDebugStatusCodeFlagHasTexturesWithIssues 4 // 1 or more textures assigned to the material have issues preventing them from streaming 129#define kMipmapDebugStatusCodeFlagHasManualRequests 8 // 1 or more textures assigned to the material are streaming manually through script (RequestedMipmapLevel) 130 131// streamInfo : 132// x = streaming priority 133// y = time stamp of the latest texture upload 134// z = streaming status 135// w = 0 136int GetStreamingPriority(float4 streamInfo) { return int(streamInfo.x);} 137float GetUpdateTimestamp(float4 streamInfo) { return streamInfo.y;} 138bool IsStreaming(float4 streamInfo) { return streamInfo.z < 0 || (int)streamInfo.z == kMipmapDebugStatusCodeManuallyRequested; } // if manually set, that's also streaming 139int GetStatusCode(float4 streamInfo, bool perMaterial) { return perMaterial ? (int)streamInfo.z >> 4 : (int)streamInfo.z & 0xF;} // 0-15 are reserved for per-texture codes 140 141#define kMipmapDebugLowPixelDensity float3(0.049, 0.32, 0.751) 142#define kMipmapDebugHighPixelDensity float3(0.982, 0.32, 0) 143 144float3 GetDebugMipRatioColor(float value) 145{ 146 if (value > 0.5) 147 return lerp(float3(0.5, 0.5, 0.5), kMipmapDebugHighPixelDensity, 2 * value - 1); 148 else 149 return lerp(kMipmapDebugLowPixelDensity, float3(0.5, 0.5, 0.5), 2 * value); 150} 151 152float3 GetMipLevelColor(float2 uv, float4 texelSize) 153{ 154 // Push down into colors list to "optimal level" in following table. 155 // .zw is texture width,height so *2 is down one mip, *4 is down two mips 156 texelSize.zw *= 4.0; 157 158 float mipLevel = ComputeTextureLOD(uv, texelSize.zw); 159 mipLevel = clamp(mipLevel, 0.0, 5.0 - 0.0001); 160 161 return GetDebugMipRatioColor(mipLevel / 5.0); 162} 163 164float3 GetDebugMipColor(float3 originalColor, float4 texelSize, float2 uv) 165{ 166 // https://aras-p.info/blog/2011/05/03/a-way-to-visualize-mip-levels/ 167 return GetMipLevelColor(uv, texelSize); 168} 169 170#define kMipmapDebugTooManyMips float3(0.194, 0.007, 0.034) 171#define kMipmapDebugInvalidMipCount float3(0.716, 0.066, 0.9) 172 173float3 GetDebugMipCountColor(uint mipCount, out bool needsHatching) 174{ 175 needsHatching = false; 176 177 if (mipCount == 0 || mipCount > 14) 178 { 179 needsHatching = true; 180 return mipCount == 0 ? kMipmapDebugInvalidMipCount : kMipmapDebugTooManyMips; 181 } 182 183 const float3 colors[14] = { 184 float3(0.349, 0.782, 0.965), 185 float3(0.188, 0.933, 0.847), 186 float3(0.034, 0.9, 0.442), 187 float3(0.027, 0.878, 0.035), 188 float3(0.4, 0.858, 0.023), 189 float3(0.694, 0.929, 0.047), 190 float3(1.0, 0.982, 0.072), 191 float3(0.996, 0.843, 0.039), 192 float3(0.991, 0.687, 0.004), 193 float3(0.988, 0.510, 0.004), 194 float3(0.982, 0.320, 0.0), 195 float3(0.992, 0.184, 0.016), 196 float3(1.0, 0.051, 0.029), 197 float3(1.0, 0.043, 0.180) 198 }; 199 200 return colors[mipCount - 1]; 201} 202 203float3 GetDebugMipCountHatchingColor(uint mipCount) 204{ 205 if (mipCount == 0 || mipCount > 14) 206 return float3(0.9, 0.9, 0.9); 207 else 208 return float3(0.1, 0.1, 0.1); 209} 210 211 212#define kMipmapDebugBudgetSavingMips float3(0.036, 0.9, 0.442) 213#define kMipmapDebugBudgetMissing float3(1.0, 0.053, 0.029) 214#define kMipmapDebugBudgetFullResolution float3(0.5, 0.5, 0.5) 215#define kMipMapDebugStatusColorNotStreaming float3(0.0, 0.007, 0.731) 216 217float3 GetDebugStreamingMipColor(uint mipCount, float4 mipInfo, float4 streamInfo, out bool needsHatching) 218{ 219 needsHatching = false; 220 221 if (!IsStreaming(streamInfo)) 222 return kMipMapDebugStatusColorNotStreaming; 223 224 if (mipCount == 0) 225 return float3(1.0, 0.0, 1.0); // Magenta if mip count invalid 226 227 const uint originalTextureMipCount = GetTextureAssetMipCount(mipInfo); 228 const uint mipCountDesired = uint(originalTextureMipCount)-GetDesiredMipLevel(mipInfo); 229 const uint maxLevelReduction = GetMaxLevelReduction(mipInfo); 230 231 const float3 colorNeutral = float3(0.5, 0.5, 0.5); 232 if (mipCount < mipCountDesired) 233 { 234 const int missingMips = mipCountDesired - mipCount; 235 const float missingRatio = float(missingMips) / float(maxLevelReduction); 236 237 // red tones when not at the desired mip level (reduction due to budget). Full red means no more mips were allowed to be discarded 238 return lerp(colorNeutral, kMipmapDebugBudgetMissing, missingRatio); 239 } 240 else if (mipCountDesired < originalTextureMipCount) 241 { 242 const int savedMips = originalTextureMipCount - mipCountDesired; 243 const float savedRatio = float(savedMips) / float(maxLevelReduction); 244 245 // green tones when we require less mips than the original texture. Full green means we've dropped as many mips as allowed 246 if (mipCount > mipCountDesired) // some mips were cached 247 { 248 needsHatching = true; 249 return lerp(colorNeutral, kMipmapDebugBudgetSavingMips, savedRatio); 250 } 251 else 252 return lerp(colorNeutral, kMipmapDebugBudgetSavingMips, savedRatio); 253 } 254 else // so, (mipCount >= originalTextureMipCount) 255 { 256 return kMipmapDebugBudgetFullResolution; 257 } 258} 259 260#define kMipMapDebugStatusColorStreaming float3(0.036, 0.9, 0.442) 261#define kMipMapDebugStatusColorUnknown float3(0.349, 0.782, 0.965) 262#define kMipMapDebugStatusColorNoTexture float3(0.982, 0.320, 0) 263#define kMipMapDebugStatusColorWarning float3(1.0, 0.982, 0.072) 264 265float3 GetDebugStreamingStatusColor(float4 streamInfo, out bool needsHatching) 266{ 267 needsHatching = false; 268 269 if (IsStreaming(streamInfo)) 270 { 271 if (GetStatusCode(streamInfo, false) == kMipmapDebugStatusCodeManuallyRequested) 272 needsHatching = true; 273 return kMipMapDebugStatusColorStreaming; 274 } 275 276 int statusCode = GetStatusCode(streamInfo, false); 277 switch(statusCode) 278 { 279 case kMipmapDebugStatusCodeNoTexture: 280 return kMipMapDebugStatusColorNoTexture; 281 case kMipmapDebugStatusCodeStreamerDisabled: 282 case kMipmapDebugStatusCodeNoMipMap: 283 case kMipmapDebugStatusCodeNotSetToStream: 284 return kMipMapDebugStatusColorNotStreaming; 285 case kMipmapDebugStatusCodeNoAsync: 286 case kMipmapDebugStatusCodeTerrain: 287 return kMipMapDebugStatusColorWarning; 288 case kMipmapDebugStatusCodeInvalidStreamingIndex: 289 return float3(1.0, 0.0, 1.0); 290 case kMipmapDebugStatusCodeNotSet: 291 default: 292 return kMipMapDebugStatusColorUnknown; 293 } 294} 295 296#define kMipMapDebugMaterialStatusColorSomeStreaming float3(0.018, 0.454, 0.587) 297 298float3 GetDebugPerMaterialStreamingStatusColor(float4 streamInfo, out bool needsHatching) 299{ 300 needsHatching = false; 301 302 int statusCode = GetStatusCode(streamInfo, true); 303 if (statusCode == kMipmapDebugStatusCodeFlagNoTexturesSet) 304 return kMipMapDebugStatusColorNoTexture; 305 306 const bool hasStreamingTextures = (statusCode & kMipmapDebugStatusCodeFlagHasStreamingTextures) != 0; 307 const bool hasNonStreamingTextures = (statusCode & kMipmapDebugStatusCodeFlagHasNonStreamingTextures) != 0; 308 const bool hasTexturesWithIssues = (statusCode & kMipmapDebugStatusCodeFlagHasTexturesWithIssues) != 0; 309 const bool hasManualRequests = (statusCode & kMipmapDebugStatusCodeFlagHasManualRequests) != 0; 310 311 if(hasTexturesWithIssues) 312 { 313 return kMipMapDebugStatusColorWarning; 314 } 315 316 // at this point, there are no issues to report 317 if(hasStreamingTextures && !hasNonStreamingTextures) 318 { 319 needsHatching = hasManualRequests; 320 return kMipMapDebugStatusColorStreaming; 321 } 322 else if(hasNonStreamingTextures && !hasStreamingTextures) 323 { 324 return kMipMapDebugStatusColorNotStreaming; 325 } 326 else 327 { 328 // mix of streaming and non-streaming 329 needsHatching = hasManualRequests; 330 return kMipMapDebugMaterialStatusColorSomeStreaming; 331 } 332} 333 334float3 GetDebugMipPriorityColor(float value) 335{ 336 const float3 kMipMapDebugLowPriorityColor = float3(0.982, 0.32, 0); 337 const float3 kMipMapDebugHighPriorityColor = float3(0.4, 0.858, 0.023); 338 339 if(value < 0.5) 340 return lerp(kMipMapDebugLowPriorityColor, float3(0.5, 0.5, 0.5), 2 * value); 341 else 342 return lerp(float3(0.5, 0.5, 0.5), kMipMapDebugHighPriorityColor, 2 * (value - 0.5)); 343} 344 345float3 GetDebugStreamingPriorityColor(float4 streamInfo) 346{ 347 if (!IsStreaming(streamInfo)) 348 return kMipMapDebugStatusColorNotStreaming; 349 350 const int textureStreamingPriority = GetStreamingPriority(streamInfo); 351 const float priorityValue = (textureStreamingPriority + 128) / 255.0; 352 return GetDebugMipPriorityColor(priorityValue); 353} 354 355float3 GetDebugMipRecentlyUpdatedColor(float value) 356{ 357 const float3 kRecentlyUpdatedColor = float3(0.194, 0.007, 0.034); 358 return lerp(kRecentlyUpdatedColor, float3(0.766, 0.766, 0.766), value); 359} 360 361float3 GetDebugStreamingRecentlyUpdatedColor(float currentTime, float cooldownTime, bool perMaterial, float4 streamInfo) 362{ 363 if (!perMaterial && !IsStreaming(streamInfo)) 364 return kMipMapDebugStatusColorNotStreaming; 365 366 if (perMaterial) 367 { 368 // The other per-material status codes don't really matter here (users visualize these in the status view). 369 // Even if there are slots with issues, as long as there is one slot with a streaming texture, we can visualize 370 // recent updates here. 371 int statusCode = GetStatusCode(streamInfo, true); 372 const bool hasStreamingTextures = (statusCode & kMipmapDebugStatusCodeFlagHasStreamingTextures) != 0; 373 if (!hasStreamingTextures) 374 return kMipMapDebugStatusColorNotStreaming; // nothing there, all slots are empty 375 } 376 377 const float timeSinceUpdate = currentTime - GetUpdateTimestamp(streamInfo); 378 const float ratio = clamp(timeSinceUpdate / cooldownTime, 0.0, 1.0); 379 return GetDebugMipRecentlyUpdatedColor(ratio); 380} 381 382float3 GetDebugMipColorIncludingMipReduction(float3 originalColor, uint mipCount, float4 texelSize, float2 uv, float4 mipInfo) 383{ 384 const uint originalTextureMipCount = GetTextureAssetMipCount(mipInfo); 385 if (originalTextureMipCount != 0) 386 { 387 // Mip count has been reduced but the texelSize was not updated to take that into account 388 const uint mipReductionLevel = originalTextureMipCount - mipCount; 389 const uint mipReductionFactor = 1U << mipReductionLevel; 390 if (mipReductionFactor) 391 { 392 const float oneOverMipReductionFactor = 1.0 / mipReductionFactor; 393 // texelSize.xy *= mipReductionRatio; // Unused in GetDebugMipColor so lets not re-calculate it 394 texelSize.zw *= oneOverMipReductionFactor; 395 } 396 } 397 return GetDebugMipColor(originalColor, texelSize, uv); 398} 399 400void HatchColor(uint2 unormCoord, real3 hatchingColor, inout real3 color) 401{ 402 const uint spacing = 8; 403 const uint thickness = 3; 404 if((unormCoord.x + unormCoord.y) % spacing < thickness) 405 color = hatchingColor; 406} 407 408void HatchColor(uint2 unormCoord, inout real3 color) 409{ 410 HatchColor(unormCoord, real3(0.1, 0.1, 0.1), color); 411} 412 413// Legend configuration 414static const float _kLegendBarPaddingHorizontal = 20.0; 415static const float _kLegendBarPaddingBottom = 20.0; 416static const float _kLegendBarHeight = 20.0; 417static const float _kLegendBarBorderThickness = 4.0; 418 419static const float _kLegendPaddingBottom = 5.0; 420static const float _kLegendMargin = 5.0; 421static const float _kLegendEntryBlockSize = 15.0; 422static const float _kLegendEntryBlockBorderSize = 1.0; 423static const float _kLegendBorderSize = 2.0; 424static const float _kLegendPaddingTextRight = 10.0; 425 426void DrawLegendEntry(uint2 unormCoord, uint stringIndex, int code, float3 entryColor, bool hatched, real3 hatchingColor, inout uint2 pos, inout real3 outputColor) 427{ 428 const float3 borderColor = float3(1,1,1); 429 const float3 lightTextColor = float3(0.90, 0.90, 0.90); 430 const float3 darkTextColor = float3(0.10, 0.10, 0.10); 431 432 uint2 blockBottom = pos; 433 uint2 blockTop = blockBottom + uint2(_kLegendEntryBlockSize, _kLegendEntryBlockSize); 434 435 if (all(unormCoord > blockBottom) && all(unormCoord < blockTop)) 436 { 437 if (all(unormCoord > blockBottom + uint(_kLegendEntryBlockBorderSize)) && all(unormCoord < blockTop - uint(_kLegendEntryBlockBorderSize))) 438 { 439 outputColor = entryColor; 440 441 if (hatched) 442 HatchColor(unormCoord, hatchingColor, outputColor); 443 444 if (code != -1) 445 { 446 bool invertColor = (code == kMipmapDebugStatusCodeNotSet || code == kMipmapDebugStatusCodeNoTexture || code == kMipmapDebugStatusCodeNoAsync || code == kMipmapDebugStatusCodeTerrain); 447 448 // draw "bold" 449 UNITY_LOOP for (uint i = 0; i < 4; ++i) 450 { 451 const bool isFont = SampleDebugFontNumber2Digits(unormCoord - pos + uint2(i % 2, i / 2), code); 452 UNITY_FLATTEN if (isFont) 453 { 454 outputColor = invertColor ? darkTextColor : lightTextColor; 455 break; 456 } 457 } 458 } 459 } 460 else 461 outputColor = borderColor; 462 } 463 464 uint2 textLocation = pos + uint2(_kLegendEntryBlockSize + _kLegendPaddingTextRight, 0); 465 DrawString(stringIndex, unormCoord, lightTextColor, textLocation, outputColor); 466 467 pos.y -= _kLegendEntryBlockSize + _kLegendMargin; 468} 469 470// Drawing a legend entry with an status code (no hatching) 471void DrawLegendEntry(uint2 unormCoord, uint stringIndex, int code, float3 entryColor, inout uint2 pos, inout real3 outputColor) 472{ 473 DrawLegendEntry(unormCoord, stringIndex, code, entryColor, false, real3(0.1, 0.1, 0.1), pos, outputColor); 474} 475 476// Drawing a legend entry with just a color (no status code) 477void DrawLegendEntry(uint2 unormCoord, uint stringIndex, float3 entryColor, real3 hatchingColor, inout uint2 pos, inout real3 outputColor) 478{ 479 DrawLegendEntry(unormCoord, stringIndex, -1, entryColor, true, hatchingColor, pos, outputColor); 480} 481 482// Drawing a legend entry with just a color (no status code) 483void DrawLegendEntry(uint2 unormCoord, uint stringIndex, float3 entryColor, bool hatched, inout uint2 pos, inout real3 outputColor) 484{ 485 DrawLegendEntry(unormCoord, stringIndex, -1, entryColor, hatched, real3(0.1, 0.1, 0.1), pos, outputColor); 486} 487 488// Drawing a legend entry without hatching or status code 489void DrawLegendEntry(uint2 unormCoord, uint stringIndex, float3 entryColor, inout uint2 pos, inout real3 outputColor) 490{ 491 DrawLegendEntry(unormCoord, stringIndex, -1, entryColor, false, real3(0.1, 0.1, 0.1), pos, outputColor); 492} 493 494void DrawLegendBackground(float2 texCoord, float4 screenSize, int numEntries, inout real3 color, out uint2 initialEntryPos) 495{ 496 const int largestStringSize = 31; 497 const int requiredWidth = largestStringSize * DEBUG_FONT_TEXT_SCALE_WIDTH + _kLegendPaddingTextRight + _kLegendEntryBlockSize + 2 * _kLegendMargin; 498 const int requiredHeight = numEntries * (_kLegendEntryBlockSize + _kLegendMargin) + _kLegendMargin; 499 500 // Screen space (fixed x, fixed y, rel x, rel y) 501 const int heightOfLegendBar = _kLegendBarPaddingBottom + _kLegendBarHeight + _kLegendBarBorderThickness; 502 const float4 legendPosition = float4(screenSize.x - requiredWidth - _kLegendBarPaddingHorizontal, heightOfLegendBar + _kLegendPaddingBottom, 0, 0); 503 const float4 legendSize = float4(requiredWidth, requiredHeight, 0, 0); 504 const float4 legendBorderThickness = float4(_kLegendBorderSize, _kLegendBorderSize, 0, 0); 505 const float4 legendWithBorderPosition = legendPosition - legendBorderThickness; 506 const float4 legendWithBorderSize = legendSize + 2 * legendBorderThickness; 507 508 // Screen UV space 509 const float2 legendPositionUV = legendPosition.xy * screenSize.zw + legendPosition.zw; 510 const float2 legendSizeUV = legendSize.xy * screenSize.zw + legendSize.zw; 511 const float2 legendWithBorderPositionUV = legendWithBorderPosition.xy * screenSize.zw + legendWithBorderPosition.zw; 512 const float2 legendWithBorderSizeUV = legendWithBorderSize.xy * screenSize.zw + legendWithBorderSize.zw; 513 514 // Legend (with border) space 515 const float2 legendBorderCoord = (texCoord - legendWithBorderPositionUV) / legendWithBorderSizeUV; 516 const float2 legendCoord = (texCoord - legendPositionUV) / legendSizeUV; 517 518 // Draw Legend border 519 if (all(legendBorderCoord >= 0) && all(legendBorderCoord <= 1)) 520 color = real3(0.1, 0.1, 0.1); 521 522 // Draw Legend background 523 if (all(legendCoord >= 0) && all(legendCoord <= 1)) 524 color = real3(0.022, 0.022, 0.022); 525 526 initialEntryPos = uint2(legendPosition.xy) + uint2(_kLegendMargin, requiredHeight - _kLegendMargin - _kLegendEntryBlockSize); 527} 528 529void DrawLegendBar(float2 texCoord, float4 screenSize, inout real3 color) 530{ 531 // Screen space (fixed x, fixed y, rel x, rel y) 532 const float4 legendBarPosition = float4(_kLegendBarPaddingHorizontal, _kLegendBarPaddingBottom, 0, 0); 533 const float4 legendBarSize = float4(-_kLegendBarPaddingHorizontal * 2, _kLegendBarHeight, 1, 0); 534 const float4 legendBarBorderThickness = float4(_kLegendBarBorderThickness, _kLegendBarBorderThickness, 0, 0); 535 const float4 legendBarWithBorderPosition = legendBarPosition - legendBarBorderThickness; 536 const float4 legendBarWithBorderSize = legendBarSize + 2 * legendBarBorderThickness; 537 538 // Screen UV space 539 const float2 legendBarWithBorderPositionUV = legendBarWithBorderPosition.xy * screenSize.zw + legendBarWithBorderPosition.zw; 540 const float2 legendBarWithBorderSizeUV = legendBarWithBorderSize.xy * screenSize.zw + legendBarWithBorderSize.zw; 541 542 // Legend bar (with border) space 543 const float2 legendBarBorderCoord = (texCoord - legendBarWithBorderPositionUV) / legendBarWithBorderSizeUV; 544 545 // Draw legend bar (still to be filled later) 546 if (all(legendBarBorderCoord >= 0) && all(legendBarBorderCoord <= 1)) 547 color = real3(0.1, 0.1, 0.1); 548} 549 550bool InsideLegendBar(float2 texCoord, float4 screenSize, out float xCoord) 551{ 552 // Screen space (fixed x, fixed y, rel x, rel y) 553 const float4 legendBarPosition = float4(_kLegendBarPaddingHorizontal, _kLegendBarPaddingBottom, 0, 0); 554 const float4 legendBarSize = float4(-_kLegendBarPaddingHorizontal * 2, _kLegendBarHeight, 1, 0); 555 556 // Screen UV space 557 const float2 legendBarPositionUV = legendBarPosition.xy * screenSize.zw + legendBarPosition.zw; 558 const float2 legendBarSizeUV = legendBarSize.xy * screenSize.zw + legendBarSize.zw; 559 560 // Legend bar space 561 const float2 legendBarCoord = (texCoord - legendBarPositionUV) / legendBarSizeUV; 562 563 // Check if inside the legend bar (and fill in the "legend bar space" horizontal coordinate) 564 xCoord = legendBarCoord.x; 565 return all(legendBarCoord >= 0) && all(legendBarCoord <= 1); 566} 567 568void DrawLabelBarBackground(float2 texCoord, float4 screenSize, inout real3 color) 569{ 570 // Screen space (fixed x, fixed y, rel x, rel y) 571 const float4 labelBarPosition = float4(_kLegendBarPaddingHorizontal, 0, 0, 0); 572 const float4 labelBarSize = float4(-_kLegendBarPaddingHorizontal * 2, _kLegendBarPaddingBottom - _kLegendBarBorderThickness, 1, 0); 573 574 // Screen UV space 575 const float2 labelBarPositionUV = labelBarPosition.xy * screenSize.zw + labelBarPosition.zw; 576 const float2 labelBarSizeUV = labelBarSize.xy * screenSize.zw + labelBarSize.zw; 577 578 // Label bar space 579 const float2 labelBarCoord = (texCoord - labelBarPositionUV) / labelBarSizeUV; 580 581 // Draw label bar background 582 if (all(labelBarCoord >= 0) && all(labelBarCoord <= 1)) 583 color = real3(0.022, 0.022, 0.022); 584} 585 586void DrawTwoValueLabelBar(uint2 unormCoord, float4 screenSize, uint leftStringId, uint rightStringId, inout real3 color) 587{ 588 const float3 textColor = float3(1,1,1); 589 590 // Draw left and right labels 591 const uint2 startPosition = uint2(_kLegendBarPaddingHorizontal, 0); 592 const uint2 endPosition = uint2(screenSize.x - _kLegendBarPaddingHorizontal - DEBUG_FONT_TEXT_SCALE_WIDTH, 0); 593 594 DrawString(leftStringId, unormCoord, textColor, startPosition, color); 595 DrawString(rightStringId, unormCoord, textColor, endPosition, true, color); 596} 597 598void DrawUniformlySpreadValues(uint2 unormCoord, float4 screenSize, uint numValues, uint startValue, inout real3 color) 599{ 600 const float bucketWidth = (screenSize.x - 2 * _kLegendBarPaddingHorizontal) / numValues; 601 602 for (uint i = 0; i < numValues; ++i) 603 { 604 const uint bucketLabel = uint(i + startValue); 605 const uint labelOffset = bucketLabel < 10 ? DEBUG_FONT_TEXT_SCALE_WIDTH / 2 : DEBUG_FONT_TEXT_SCALE_WIDTH; 606 const uint2 labelStartCoord = uint2(_kLegendBarPaddingHorizontal + i * bucketWidth + bucketWidth / 2 - labelOffset, 0); 607 608 const uint2 pixCoord = unormCoord - labelStartCoord; 609 if (SampleDebugFontNumberAllDigits(pixCoord, bucketLabel)) 610 color = real3(1, 1, 1); 611 } 612} 613 614 615// Legend drawing functions 616// ------------------------ 617 618void DrawMipCountLegend(float2 texCoord, float4 screenSize, inout real3 color) 619{ 620 const uint2 unormCoord = texCoord * screenSize.xy; 621 const real maxMipCount = 14; 622 623 // Draw legend 624 uint2 pos; 625 DrawLegendBackground(texCoord, screenSize, 2, color, pos); 626 DrawLegendEntry(unormCoord, _kNoMipCountIndex, kMipmapDebugInvalidMipCount, float3(0.9, 0.9, 0.9), pos, color); 627 DrawLegendEntry(unormCoord, _kTooManyMipsIndex, kMipmapDebugTooManyMips, float3(0.9, 0.9, 0.9), pos, color); 628 629 // Draw legend bar 630 DrawLegendBar(texCoord, screenSize, color); 631 632 float xCoord; 633 if (InsideLegendBar(texCoord, screenSize, xCoord)) 634 { 635 // Compute bucket index 636 const int bucket = ceil(xCoord * maxMipCount); 637 bool needsHatching; 638 color = GetDebugMipCountColor(bucket, needsHatching); 639 if (needsHatching) 640 // no need to get the hatching color (to keep in sync with rendering), it's always dark anyway inside the legend bar 641 HatchColor(unormCoord, color); 642 } 643 644 DrawLabelBarBackground(texCoord, screenSize, color); 645 DrawUniformlySpreadValues(unormCoord, screenSize, maxMipCount, 1, color); 646} 647 648void DrawMipRatioLegend(float2 texCoord, float4 screenSize, inout real3 color) 649{ 650 const uint2 unormCoord = texCoord * screenSize.xy; 651 652 // Draw legend bar 653 DrawLegendBar(texCoord, screenSize, color); 654 655 float xCoord; 656 if (InsideLegendBar(texCoord, screenSize, xCoord)) 657 color = GetDebugMipRatioColor(xCoord); 658 659 // Text labels 660 DrawLabelBarBackground(texCoord, screenSize, color); 661 DrawTwoValueLabelBar(unormCoord, screenSize, _kLowPixelDensityIndex, _kHighPixelDensityIndex, color); 662} 663 664void DrawMipPriorityLegend(float2 texCoord, float4 screenSize, inout real3 color) 665{ 666 const uint2 unormCoord = texCoord * screenSize.xy; 667 668 // Draw the legend 669 uint2 pos; 670 DrawLegendBackground(texCoord, screenSize, 1, color, pos); 671 DrawLegendEntry(unormCoord, _kNotStreamingIndex, kMipMapDebugStatusColorNotStreaming, pos, color); 672 673 // Draw legend bar 674 DrawLegendBar(texCoord, screenSize, color); 675 676 float xCoord; 677 if (InsideLegendBar(texCoord, screenSize, xCoord)) 678 color = GetDebugMipPriorityColor(xCoord); 679 680 // Text labels 681 DrawLabelBarBackground(texCoord, screenSize, color); 682 DrawTwoValueLabelBar(unormCoord, screenSize, _kLowPriorityIndex, _kHighPriorityIndex, color); 683} 684 685void DrawMipRecentlyUpdatedLegend(float2 texCoord, float4 screenSize, bool perMaterial, inout real3 color) 686{ 687 const uint2 unormCoord = texCoord * screenSize.xy; 688 689 // Draw the legend 690 uint2 pos; 691 DrawLegendBackground(texCoord, screenSize, 1, color, pos); 692 if(perMaterial) 693 DrawLegendEntry(unormCoord, _kStatusNoTexturesAreStreaming, kMipMapDebugStatusColorNotStreaming, pos, color); 694 else 695 DrawLegendEntry(unormCoord, _kNotStreamingIndex, kMipMapDebugStatusColorNotStreaming, pos, color); 696 697 // Draw legend bar 698 DrawLegendBar(texCoord, screenSize, color); 699 700 float xCoord; 701 if (InsideLegendBar(texCoord, screenSize, xCoord)) 702 color = GetDebugMipRecentlyUpdatedColor(xCoord); 703 704 // Text labels 705 DrawLabelBarBackground(texCoord, screenSize, color); 706 DrawTwoValueLabelBar(unormCoord, screenSize, _kRecentlyUpdated, _kNotRecentlyUpdated, color); 707} 708 709void DrawMipStreamingStatusLegend(float2 texCoord, float4 screenSize, bool needsStatusCodes, inout real3 color) 710{ 711 const uint2 unormCoord = texCoord * screenSize.xy; 712 713 // Draw the legend 714 uint2 pos; 715 const int numEntries = needsStatusCodes ? 11 : 6; 716 DrawLegendBackground(texCoord, screenSize, numEntries, color, pos); 717 718 DrawLegendEntry(unormCoord, _kStatusNoTextureIndex, kMipMapDebugStatusColorNoTexture, pos, color); 719 DrawLegendEntry(unormCoord, _kNotStreamingIndex, kMipMapDebugStatusColorNotStreaming, pos, color); 720 if (needsStatusCodes) 721 { 722 DrawLegendEntry(unormCoord, _kStatusStreamerDisabledIndex, kMipmapDebugStatusCodeStreamerDisabled, kMipMapDebugStatusColorNotStreaming, pos, color); 723 DrawLegendEntry(unormCoord, _kStatusMessageNoMipMapIndex, kMipmapDebugStatusCodeNoMipMap, kMipMapDebugStatusColorNotStreaming, pos, color); 724 DrawLegendEntry(unormCoord, _kStatusMessageNotSetToStreamIndex, kMipmapDebugStatusCodeNotSetToStream, kMipMapDebugStatusColorNotStreaming, pos, color); 725 } 726 DrawLegendEntry(unormCoord, _kStreamingIndex, kMipMapDebugStatusColorStreaming, pos, color); 727 DrawLegendEntry(unormCoord, _kStreamingManuallyIndex, kMipMapDebugStatusColorStreaming, true, pos, color); 728 729 DrawLegendEntry(unormCoord, _kStatusWarningIndex, kMipMapDebugStatusColorWarning, pos, color); 730 if (needsStatusCodes) 731 { 732 DrawLegendEntry(unormCoord, _kStatusMessageNoAsyncIndex, kMipmapDebugStatusCodeNoAsync, kMipMapDebugStatusColorWarning, pos, color); 733 DrawLegendEntry(unormCoord, _kStatusMessageTerrainIndex, kMipmapDebugStatusCodeTerrain, kMipMapDebugStatusColorWarning, pos, color); 734 } 735 736 DrawLegendEntry(unormCoord, _kStatusUnknownIndex, kMipMapDebugStatusColorUnknown, pos, color); 737} 738 739void DrawMipStreamingStatusPerMaterialLegend(float2 texCoord, float4 screenSize, inout real3 color) 740{ 741 const uint2 unormCoord = texCoord * screenSize.xy; 742 743 // Draw the legend 744 uint2 pos; 745 DrawLegendBackground(texCoord, screenSize, 7, color, pos); 746 747 DrawLegendEntry(unormCoord, _kStatusNoTexturesIndex, kMipMapDebugStatusColorNoTexture, pos, color); 748 DrawLegendEntry(unormCoord, _kStatusNoTexturesAreStreaming, kMipMapDebugStatusColorNotStreaming, pos, color); 749 DrawLegendEntry(unormCoord, _kStatusSomeTexturesAreStreaming, kMipMapDebugMaterialStatusColorSomeStreaming, pos, color); 750 DrawLegendEntry(unormCoord, _kStatusSomeTexturesAreStreamingSomeManually, kMipMapDebugMaterialStatusColorSomeStreaming, true, pos, color); 751 DrawLegendEntry(unormCoord, _kStatusAllTexturesAreStreaming, kMipMapDebugStatusColorStreaming, pos, color); 752 DrawLegendEntry(unormCoord, _kStatusAllTexturesAreStreamingSomeManually, kMipMapDebugStatusColorStreaming, true, pos, color); 753 DrawLegendEntry(unormCoord, _kStatusSomeTexturesHaveIssues, kMipMapDebugStatusColorWarning, pos, color); 754} 755 756void DrawTextureStreamingPerformanceLegend(float2 texCoord, float4 screenSize, inout real3 color) 757{ 758 const uint2 unormCoord = texCoord * screenSize.xy; 759 760 // Draw the legend 761 uint2 pos; 762 DrawLegendBackground(texCoord, screenSize, 5, color, pos); 763 764 DrawLegendEntry(unormCoord, _kNotStreamingIndex, kMipMapDebugStatusColorNotStreaming, pos, color); 765 DrawLegendEntry(unormCoord, _kBudgetSavingMips, kMipmapDebugBudgetSavingMips, pos, color); 766 DrawLegendEntry(unormCoord, _kBudgetSavingMipsWithCache, kMipmapDebugBudgetSavingMips, true, pos, color); 767 DrawLegendEntry(unormCoord, _kBudgetNothingSaved, kMipmapDebugBudgetFullResolution, pos, color); 768 DrawLegendEntry(unormCoord, _kBudgetMissingMips, kMipmapDebugBudgetMissing, pos, color); 769} 770 771#endif // UNITY_DEBUG_MIPMAP_STREAMING_INCLUDED