Adaug proiectul Unity

This commit is contained in:
2026-11-01 23:39:55 +02:00
parent cb14d9d37d
commit 863eac8f2c
23463 changed files with 5412601 additions and 0 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 77658d0b0e15bb342a01e17ef1b2172a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
#ifndef VRS_IMAGE_INCLUDED
#define VRS_IMAGE_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
RW_TEXTURE2D(uint, _ShadingRateImage);
uniform float4 _VrsScaleBias;
void ImageStore(uint shadingRateNativeValue, uint2 gid)
{
#if !defined(APPLY_Y_FLIP)
// compute shader introduce a natural y-flip
// hence the reverse test
gid.y = _VrsScaleBias.w - 1 - gid.y;
#endif
_ShadingRateImage[gid] = shadingRateNativeValue;
}
#endif // VRS_IMAGE_INCLUDED
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3cc7957ff84646bbbb849b88919e2109
timeCreated: 1710958387
@@ -0,0 +1,23 @@
#ifndef VRS_MAINTEX_INCLUDED
#define VRS_MAINTEX_INCLUDED
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GlobalSamplers.hlsl"
TEXTURE2D_X(_VrsMainTex);
StructuredBuffer<float4> _VrsMainTexLut;
float4 LoadVrsMainTex(uint2 tid)
{
return LOAD_TEXTURE2D_X(_VrsMainTex, tid);
}
float4 SampleVrsMainTexFromCoords(float2 coords)
{
return SAMPLE_TEXTURE2D_X_LOD(_VrsMainTex, sampler_PointClamp, coords, 0);
}
#endif // VRS_MAINTEX_INCLUDED
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 08b9525dab8d497cb640174e593275d1
timeCreated: 1710958899
@@ -0,0 +1,45 @@
#ifndef VRS_SHADING_RATES_INCLUDED
#define VRS_SHADING_RATES_INCLUDED
// Must be kept in sync with ShadingRateFragmentSize
#define SHADING_RATE_FRAGMENT_SIZE_1X1 0 // native value = 0b0000 -> 0
#define SHADING_RATE_FRAGMENT_SIZE_1X2 1 // native value = 0b0001 -> 1
#define SHADING_RATE_FRAGMENT_SIZE_2X1 2 // native value = 0b0100 -> 4
#define SHADING_RATE_FRAGMENT_SIZE_2X2 3 // native value = 0b0101 -> 5
#define SHADING_RATE_FRAGMENT_SIZE_1x4 4 // native value = 0b0010 -> 2
#define SHADING_RATE_FRAGMENT_SIZE_4x1 5 // native value = 0b1000 -> 8
#define SHADING_RATE_FRAGMENT_SIZE_2x4 6 // native value = 0b0110 -> 6
#define SHADING_RATE_FRAGMENT_SIZE_4x2 7 // native value = 0b1001 -> 9
#define SHADING_RATE_FRAGMENT_SIZE_4x4 8 // native value = 0b1010 -> 10
#define SHADING_RATE_FRAGMENT_SIZE_COUNT 9
StructuredBuffer<uint> _ShadingRateNativeValues;
/// <summary>
/// Unpack a shading rate native value into its horizontal and vertical components.
/// </summary>
/// <param name="shadingRateNativeValue">Shading rate native value to unpack.</param>
/// <returns>Unpacked value where x component is the horizontal shading rate and y is the vertical shading rate.</returns>
uint2 UnpackShadingRate(uint shadingRateNativeValue)
{
return uint2((shadingRateNativeValue >> 2) & 0x03, shadingRateNativeValue & 0x03);
}
/// <summary>
/// Pack an unpacked shading rates into its native value.
/// </summary>
/// <param name="unpackedShadingRate">Unpacked shading rate.</param>
/// <returns>Shading rate native value.</returns>
uint PackShadingRate(uint2 unpackedShadingRate)
{
// If using 4x4 rate, be careful to check for invalid rates
// if (shadingRate.x == 2 && shadingRate.y == 0)
// shadingRate.y = 1;
//
// if (shadingRate.x == 0 && shadingRate.y == 2)
// shadingRate.x = 1;
return (unpackedShadingRate.x << 2) | unpackedShadingRate.y;
}
#endif // VRS_SHADING_RATES_INCLUDED
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dbb73cb4c1954036a32ce1ade17ac0fd
timeCreated: 1710965275
@@ -0,0 +1,69 @@
// #pragma enable_d3d11_debug_symbols
#pragma exclude_renderers glcore gles3
#pragma multi_compile VRS_TILE_SIZE_8 VRS_TILE_SIZE_16 VRS_TILE_SIZE_32
#pragma multi_compile _ DISABLE_TEXTURE2D_X_ARRAY
#pragma multi_compile _ APPLY_Y_FLIP
#pragma kernel TextureCopy
#pragma kernel TextureReduce
#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsTileSize.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsImage.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsMainTex.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Vrs/Shaders/VrsShadingRates.hlsl"
uint GetShadingRateNativeValueFromColor(float3 color)
{
for (uint i = 0; i < SHADING_RATE_FRAGMENT_SIZE_COUNT; ++i)
{
float3 delta = abs(color - _VrsMainTexLut[i].rgb);
if (all(delta < 0.01f))
return _ShadingRateNativeValues[i];
}
return _ShadingRateNativeValues[SHADING_RATE_FRAGMENT_SIZE_1X1];
}
[numthreads(1, 1, 1)]
void TextureCopy(uint2 tid : SV_DispatchThreadID)
{
float3 color = LoadVrsMainTex(tid).rgb;
uint shadingRateNativeValue = GetShadingRateNativeValueFromColor(color);
ImageStore(shadingRateNativeValue, tid);
}
groupshared uint2 ldsShadingRate;
[numthreads(VRS_TILE_SIZE, VRS_TILE_SIZE, 1)]
void TextureReduce(uint2 tid : SV_DispatchThreadID, uint2 gid: SV_GroupID, uint gidx: SV_GroupIndex)
{
// initialize lds: only 1st thread of group does it
if (gidx == 0)
ldsShadingRate = UnpackShadingRate(_ShadingRateNativeValues[SHADING_RATE_FRAGMENT_SIZE_4x4]);
// read: 1 thread == 1 pixel in main tex, each thread in group must read
float3 color = SampleVrsMainTexFromCoords(tid * _VrsScaleBias.xy).rgb;
uint shadingRateNativeValue = GetShadingRateNativeValueFromColor(color);
uint2 shadingRate = UnpackShadingRate(shadingRateNativeValue);
GroupMemoryBarrierWithGroupSync();
// parallel reduce: 1 group == 1 pixel in vrs image
// conservative reduce: pick highest rate (hence min)
InterlockedMin(ldsShadingRate.x, shadingRate.x);
InterlockedMin(ldsShadingRate.y, shadingRate.y);
GroupMemoryBarrierWithGroupSync();
// store result: only 1st thread of group does it
if (gidx == 0)
{
shadingRateNativeValue = PackShadingRate(ldsShadingRate);
ImageStore(shadingRateNativeValue, gid);
}
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: cacb30de6c40c7444bbc78cb0a81fd2a
ComputeShaderImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
#ifndef VRS_TILE_SIZE_INCLUDED
#define VRS_TILE_SIZE_INCLUDED
#if defined(VRS_TILE_SIZE_8)
#define VRS_TILE_SIZE 8
#elif defined(VRS_TILE_SIZE_16)
#define VRS_TILE_SIZE 16
#elif defined(VRS_TILE_SIZE_32)
#define VRS_TILE_SIZE 32
#else
#error Unsupported tile size
#endif
#endif // VRS_TILE_SIZE_INCLUDED
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 234c0613ab6043a7852e6ab1a268352a
timeCreated: 1710957835
@@ -0,0 +1,46 @@
Shader "Hidden/Core/VrsVisualization"
{
SubShader
{
Pass
{
Name "VrsVisualization"
ZTest Always
ZWrite Off
Cull Off
HLSLPROGRAM
//#pragma enable_debug_symbols
#pragma exclude_renderers glcore gles3
#pragma vertex Vert
#pragma fragment Fragment
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
TYPED_TEXTURE2D(uint, _ShadingRateImage);
StructuredBuffer<float4> _VisualizationLut;
uniform float4 _VisualizationParams;
#define PixelToTileScale _VisualizationParams.xy
float4 Fragment(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
uint2 pixel = (uint2)(input.positionCS.xy * PixelToTileScale);
uint shadingRate = LOAD_TEXTURE2D_LOD(_ShadingRateImage, pixel, 0);
return _VisualizationLut[shadingRate];
}
ENDHLSL
}
}
Fallback Off
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 620b55b8040a88d468e94abe55bed5ba
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,406 @@
using System;
using Unity.Scripting.LifecycleManagement;
using UnityEngine.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering
{
/// <summary>
/// Encapsulates variable shading rate support (VRS) and texture conversion to shading rate image
/// </summary>
public static partial class Vrs
{
class ConversionPassData
{
public TextureHandle sriTextureHandle;
public TextureHandle mainTexHandle;
public TextureDimension mainTexDimension;
public BufferHandle mainTexLutHandle;
public BufferHandle validatedShadingRateFragmentSizeHandle;
public ComputeShader computeShader;
public int kernelIndex;
public Vector4 scaleBias;
public Vector2Int dispatchSize;
public bool yFlip;
}
class VisualizationPassData
{
public Material material;
public TextureHandle source;
public BufferHandle lut;
public TextureHandle dummy;
public Vector4 visualizationParams;
}
[NoAutoStaticsCleanup]
internal static readonly int shadingRateFragmentSizeCount = Enum.GetNames(typeof(ShadingRateFragmentSize)).Length;
[OnCodeInitializing]
static void ResetStaticsOnLoad()
{
DisposeResources();
}
[NoAutoStaticsCleanup]
static VrsResources s_VrsResources;
/// <summary>
/// Check if conversion of color texture to shading rate image is supported.
/// Convenience to abstract all capabilities checks.
///
/// The `IsColorMaskTextureConversionSupported` method checks for the following:
///- VRS hardware support through [ShadingRateInfo.supportsPerImageTile](xref:UnityEngine.Rendering.ShadingRateInfo.supportsPerImageTile). The `supportsPerImageTile` property determines whether your GPU can define different quality levels to different tiles.
///- Compute shader support through [SystemInfo.supportsComputeShaders](xref:UnityEngine.Device.SystemInfo.supportsComputeShaders)
///- Proper initialization of VRS utility functions and compute shaders required for converting color textures to shading rate image (SRI). This is automatically handled by the render pipeline. However, for custom implementations, you must call <see cref="InitializeResources"/> manually.
/// </summary>
/// <returns>Returns true if conversion of color texture to shading rate image is supported, false otherwise.</returns>
public static bool IsColorMaskTextureConversionSupported()
{
return SystemInfo.supportsComputeShaders &&
ShadingRateInfo.supportsPerImageTile &&
IsInitialized();
}
/// <summary>
/// Checks if VRS resources are initialized.
/// Initialization may fail due to platform restrictions.
/// </summary>
/// <returns>Returns true if the Vrs resources are initialized.</returns>
public static bool IsInitialized()
{
return s_VrsResources != null &&
s_VrsResources.textureComputeShader != null &&
s_VrsResources.textureReduceKernel != -1 &&
s_VrsResources.textureCopyKernel != -1;
}
/// <summary>
/// Preprocess resources found in VrsRenderPipelineRuntimeResources for use at runtime.
/// </summary>
public static void InitializeResources()
{
// GLES3.0/WebGL2 and older GL platforms do not support compute shaders (for conversion).
// Unity does not implement VRS for OpenGL.
bool isOpenGL = SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLCore ||
SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3;
// NOTE: should match "#pragma exclude_renderers" in shaders.
bool isPlatformSupported = !isOpenGL;
// VRS resources are initialized even on platforms that do not support VRS to allow debugging Color<->VRS conversion.
// For example when you are building on a non-VRS platform to a VRS platform.
// VRS conversion requires compute shader support.
// NOTE: Init might fail.
if (SystemInfo.supportsComputeShaders &&
isPlatformSupported)
{
var pipelineRuntimeResources = GraphicsSettings.GetRenderPipelineSettings<VrsRenderPipelineRuntimeResources>();
s_VrsResources = new VrsResources(pipelineRuntimeResources);
}
}
/// <summary>
/// Cleanup resources.
/// </summary>
public static void DisposeResources()
{
s_VrsResources?.Dispose();
s_VrsResources = null;
}
/// <summary>
/// Converts a color mask texture to a shading rate image.
/// </summary>
/// <param name="renderGraph">Render graph to record conversion commands</param>
/// <param name="sriRtHandle">Shading rate images to convert to.</param>
/// <param name="colorMaskRtHandle">Texture to convert from.</param>
/// <param name="yFlip">True if shading rate image should be generated flipped.</param>
/// <returns>Shading rate image texture handle created.</returns>
/// <remarks>
/// sriRtHandle and colorMaskRtHandle are imported with renderGraph before doing the conversion.
/// </remarks>
public static TextureHandle ColorMaskTextureToShadingRateImage(RenderGraph renderGraph, RTHandle sriRtHandle, RTHandle colorMaskRtHandle, bool yFlip)
{
if (renderGraph == null || sriRtHandle == null || colorMaskRtHandle == null)
{
Debug.LogError($"TextureToShadingRateImage: invalid argument.");
return TextureHandle.nullHandle;
}
var sriTextureHandle = renderGraph.ImportShadingRateImageTexture(sriRtHandle);
var colorMaskHandle = renderGraph.ImportTexture(colorMaskRtHandle);
return ColorMaskTextureToShadingRateImage(renderGraph,
sriTextureHandle,
colorMaskHandle,
((Texture)colorMaskRtHandle).dimension,
yFlip);
}
/// <summary>
/// Converts a color mask texture to a shading rate image.
/// </summary>
/// <param name="renderGraph">Render graph to record conversion commands</param>
/// <param name="sriTextureHandle">Shading rate images to convert to.</param>
/// <param name="colorMaskHandle">Texture to convert from.</param>
/// <param name="colorMaskDimension">Texture's dimension.</param>
/// <param name="yFlip">True if shading rate image should be generated flipped.</param>
/// <returns>Shading rate image texture handle created.</returns>
/// <remarks>
/// sriRtHandle and colorMaskHandle are expected to be imported by renderGraph prior to this call.
/// </remarks>
public static TextureHandle ColorMaskTextureToShadingRateImage(RenderGraph renderGraph, TextureHandle sriTextureHandle, TextureHandle colorMaskHandle, TextureDimension colorMaskDimension, bool yFlip)
{
if (!IsColorMaskTextureConversionSupported())
{
Debug.LogError($"ColorMaskTextureToShadingRateImage: conversion not supported.");
return TextureHandle.nullHandle;
}
var sriDesc = sriTextureHandle.GetDescriptor(renderGraph);
if (sriDesc.dimension != TextureDimension.Tex2D)
{
Debug.LogError($"ColorMaskTextureToShadingRateImage: Vrs image not a texture 2D.");
return TextureHandle.nullHandle;
}
if (colorMaskDimension != TextureDimension.Tex2D && colorMaskDimension != TextureDimension.Tex2DArray)
{
Debug.LogError($"ColorMaskTextureToShadingRateImage: Input texture dimension not supported.");
return TextureHandle.nullHandle;
}
using (var builder = renderGraph.AddComputePass<ConversionPassData>("TextureToShadingRateImage", out var outerPassData, s_VrsResources.conversionProfilingSampler))
{
outerPassData.sriTextureHandle = sriTextureHandle;
outerPassData.mainTexHandle = colorMaskHandle;
outerPassData.mainTexDimension = colorMaskDimension;
outerPassData.mainTexLutHandle = renderGraph.ImportBuffer(s_VrsResources.conversionLutBuffer);
outerPassData.validatedShadingRateFragmentSizeHandle = renderGraph.ImportBuffer(s_VrsResources.validatedShadingRateFragmentSizeBuffer);
outerPassData.computeShader = s_VrsResources.textureComputeShader;
outerPassData.kernelIndex = s_VrsResources.textureReduceKernel;
outerPassData.scaleBias = new Vector4()
{
x = 1.0f / (sriDesc.width * s_VrsResources.tileSize.x),
y = 1.0f / (sriDesc.height * s_VrsResources.tileSize.y),
z = sriDesc.width,
w = sriDesc.height,
};
outerPassData.dispatchSize = new Vector2Int(sriDesc.width, sriDesc.height);
outerPassData.yFlip = yFlip;
builder.UseTexture(outerPassData.sriTextureHandle, AccessFlags.Write);
builder.UseTexture(outerPassData.mainTexHandle);
builder.UseBuffer(outerPassData.mainTexLutHandle);
builder.AllowGlobalStateModification(true);
builder.SetRenderFunc(static (ConversionPassData innerPassData, ComputeGraphContext context) =>
{
ConversionDispatch(context.cmd, innerPassData);
});
return outerPassData.sriTextureHandle;
}
}
/// <summary>
/// Converts a shading rate image to a color texture for visualization.
/// </summary>
/// <param name="renderGraph">Render graph to record conversion commands</param>
/// <param name="sriTextureHandle">Texture to convert from.</param>
/// <param name="colorMaskHandle">Output of conversion.</param>
public static void ShadingRateImageToColorMaskTexture(RenderGraph renderGraph, in TextureHandle sriTextureHandle, in TextureHandle colorMaskHandle)
{
if (s_VrsResources == null)
{
Debug.LogError($"ShadingRateImageToColorMaskTexture: VRS not initialized.");
return;
}
if (!colorMaskHandle.IsValid())
{
Debug.LogError($"ShadingRateImageToColorMaskTexture: Output target handle is not valid.");
return;
}
using (var builder = renderGraph.AddRasterRenderPass<VisualizationPassData>("ShadingRateImageToTexture", out var outerPassData, s_VrsResources.visualizationProfilingSampler))
{
outerPassData.material = s_VrsResources.visualizationMaterial;
if (sriTextureHandle.IsValid())
outerPassData.source = sriTextureHandle;
else
outerPassData.source = renderGraph.defaultResources.blackTexture;
outerPassData.lut = renderGraph.ImportBuffer(s_VrsResources.visualizationLutBuffer);
outerPassData.dummy = renderGraph.defaultResources.blackTexture;
outerPassData.visualizationParams = new Vector4(
1.0f / s_VrsResources.tileSize.x,
1.0f / s_VrsResources.tileSize.y,
0,
0);;
builder.UseTexture(outerPassData.source);
builder.UseBuffer(outerPassData.lut);
builder.UseTexture(outerPassData.dummy);
builder.SetRenderAttachment(colorMaskHandle, 0);
builder.AllowPassCulling(false);
builder.SetRenderFunc(static (VisualizationPassData innerPassData, RasterGraphContext context) =>
{
// must setup blitter source via the material: it's a typed texture (uint)
innerPassData.material.SetTexture(VrsShaders.s_ShadingRateImage, innerPassData.source);
innerPassData.material.SetBuffer(VrsShaders.s_VisualizationLut, innerPassData.lut);
innerPassData.material.SetVector(VrsShaders.s_VisualizationParams, innerPassData.visualizationParams);
Blitter.BlitTexture(context.cmd,
innerPassData.dummy,
new Vector4(1, 1, 0, 0),
innerPassData.material,
0);
});
}
}
static void ConversionDispatch(ComputeCommandBuffer cmd, ConversionPassData conversionPassData)
{
var disableTexture2dXArray = new LocalKeyword(conversionPassData.computeShader, VrsShaders.k_DisableTexture2dXArray);
if (conversionPassData.mainTexDimension == TextureDimension.Tex2DArray)
cmd.DisableKeyword(conversionPassData.computeShader, disableTexture2dXArray);
else
cmd.EnableKeyword(conversionPassData.computeShader, disableTexture2dXArray);
var yFlip = new LocalKeyword(conversionPassData.computeShader, VrsShaders.k_YFlip);
if (conversionPassData.yFlip)
cmd.EnableKeyword(conversionPassData.computeShader, yFlip);
else
cmd.DisableKeyword(conversionPassData.computeShader, yFlip);
cmd.SetComputeTextureParam(conversionPassData.computeShader, conversionPassData.kernelIndex, VrsShaders.s_MainTex, conversionPassData.mainTexHandle);
cmd.SetComputeBufferParam(conversionPassData.computeShader, conversionPassData.kernelIndex, VrsShaders.s_MainTexLut, conversionPassData.mainTexLutHandle);
cmd.SetComputeBufferParam(conversionPassData.computeShader, conversionPassData.kernelIndex, VrsShaders.s_ShadingRateNativeValues, conversionPassData.validatedShadingRateFragmentSizeHandle);
cmd.SetComputeTextureParam(conversionPassData.computeShader, conversionPassData.kernelIndex, VrsShaders.s_ShadingRateImage, conversionPassData.sriTextureHandle);
cmd.SetComputeVectorParam(conversionPassData.computeShader, VrsShaders.s_ScaleBias, conversionPassData.scaleBias);
cmd.DispatchCompute(conversionPassData.computeShader, conversionPassData.kernelIndex, conversionPassData.dispatchSize.x, conversionPassData.dispatchSize.y, 1);
}
/// <summary>
/// Converts a color mask texture to a shading rate image.
/// Use this function to perform the conversion without the RenderGraph.
/// </summary>
/// <param name="cmd">CommandBuffer used for the compute dispatch.</param>
/// <param name="sriDestination">Shading rate images to convert to.</param>
/// <param name="colorMaskSource">Texture to convert from.</param>
/// <param name="yFlip">True if shading rate image should be generated flipped.</param>
public static void ColorMaskTextureToShadingRateImageDispatch(CommandBuffer cmd, RTHandle sriDestination, Texture colorMaskSource, bool yFlip = true)
{
if (sriDestination == null)
{
Debug.LogError("ColorMaskTextureToShadingRateImageDispatch: VRS destination shading rate texture is null.");
return;
}
if (colorMaskSource == null)
{
Debug.LogError("ColorMaskTextureToShadingRateImageDispatch: VRS source color texture is null.");
return;
}
if (!IsInitialized())
{
Debug.LogError("ColorMaskTextureToShadingRateImageDispatch: VRS is not initialized.");
return;
}
var computeShader = s_VrsResources.textureComputeShader;
var kernelIndex = s_VrsResources.textureReduceKernel;
var colorLutBuffer = s_VrsResources.conversionLutBuffer;
var validatedShadingRateFragmentSizeBuffer = s_VrsResources.validatedShadingRateFragmentSizeBuffer;
int sriDestWidth = sriDestination.rt.width;
int sriDestHeight = sriDestination.rt.height;
var scaleBias = new Vector4()
{
x = 1.0f / (sriDestWidth * s_VrsResources.tileSize.x),
y = 1.0f / (sriDestHeight * s_VrsResources.tileSize.y),
z = sriDestWidth,
w = sriDestHeight,
};
var dispatchSize = new Vector2Int(sriDestWidth, sriDestHeight);
var disableTexture2dXArray = new LocalKeyword(computeShader, VrsShaders.k_DisableTexture2dXArray);
if (colorMaskSource?.dimension == TextureDimension.Tex2DArray)
cmd.DisableKeyword(computeShader, disableTexture2dXArray);
else
cmd.EnableKeyword(computeShader, disableTexture2dXArray);
var yFlipKeyword = new LocalKeyword(computeShader, VrsShaders.k_YFlip);
if (yFlip)
cmd.EnableKeyword(computeShader, yFlipKeyword);
else
cmd.DisableKeyword(computeShader, yFlipKeyword);
cmd.SetComputeTextureParam(computeShader, kernelIndex, VrsShaders.s_MainTex, colorMaskSource);
cmd.SetComputeBufferParam(computeShader, kernelIndex, VrsShaders.s_MainTexLut, colorLutBuffer);
cmd.SetComputeBufferParam(computeShader, kernelIndex, VrsShaders.s_ShadingRateNativeValues, validatedShadingRateFragmentSizeBuffer);
cmd.SetComputeTextureParam(computeShader, kernelIndex, VrsShaders.s_ShadingRateImage, sriDestination);
cmd.SetComputeVectorParam(computeShader, VrsShaders.s_ScaleBias, scaleBias);
cmd.DispatchCompute(computeShader, kernelIndex, dispatchSize.x, dispatchSize.y, 1);
}
/// <summary>
/// Converts a shading rate image to a color mask texture.
/// Use this function to perform the conversion without the RenderGraph.
/// </summary>
/// <param name="cmd">CommandBuffer used for the compute dispatch.</param>
/// <param name="sriSource">Shading rate images to convert from.</param>
/// <param name="colorMaskDestination">Texture to convert to.</param>
public static void ShadingRateImageToColorMaskTextureBlit(CommandBuffer cmd, RTHandle sriSource, RTHandle colorMaskDestination)
{
if (sriSource == null)
{
Debug.LogError("ShadingRateImageToColorMaskTextureBlit: VRS source shading rate texture is null.");
return;
}
if (colorMaskDestination == null)
{
Debug.LogError("ShadingRateImageToColorMaskTextureBlit: VRS destination color texture is null.");
return;
}
if(!IsInitialized())
{
Debug.LogError("ShadingRateImageToColorMaskTextureBlit: VRS is not initialized.");
return;
}
RTHandle source = sriSource;
RTHandle destination = colorMaskDestination;
var material = s_VrsResources.visualizationMaterial;
var lut = s_VrsResources.visualizationLutBuffer;
Vector4 visualizationParams = new Vector4(
1.0f / s_VrsResources.tileSize.x,
1.0f / s_VrsResources.tileSize.y,
0,
0);
material.SetTexture(VrsShaders.s_ShadingRateImage, source);
material.SetBuffer(VrsShaders.s_VisualizationLut, lut);
material.SetVector(VrsShaders.s_VisualizationParams, visualizationParams);
CoreUtils.SetRenderTarget(cmd, destination);
Blitter.BlitTexture(cmd,
new Vector4(1, 1, 0, 0),
material,
0);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a5153735ff79d6149a038ac6417b9301
@@ -0,0 +1,124 @@
using System;
using System.Runtime.InteropServices;
namespace UnityEngine.Rendering
{
/// <summary>
/// Variable rate shading lookup table. Use to convert shading rate fragment size and color back and forth.
/// </summary>
[Serializable]
public class VrsLut
{
/// <summary>
/// Get a new instance of default VrsLut
/// </summary>
/// <returns>New instance of default VrsLut</returns>
public static VrsLut CreateDefault()
{
return new VrsLut()
{
[ShadingRateFragmentSize.FragmentSize1x1] = new Color(0.785f, 0.23f, 0.20f, 1), // Red
[ShadingRateFragmentSize.FragmentSize1x2] = new Color(1.00f, 0.80f, 0.80f, 1), // Light Red
[ShadingRateFragmentSize.FragmentSize2x1] = new Color(0.40f, 0.20f, 0.20f, 1), // Dark Red
[ShadingRateFragmentSize.FragmentSize2x2] = new Color(0.51f, 0.80f, 0.60f, 1), // Green
[ShadingRateFragmentSize.FragmentSize1x4] = new Color(0.60f, 0.80f, 1.00f, 1), // Light Blue
[ShadingRateFragmentSize.FragmentSize4x1] = new Color(0.20f, 0.40f, 0.60f, 1), // Medium Blue
[ShadingRateFragmentSize.FragmentSize2x4] = new Color(0.80f, 1.00f, 0.80f, 1), // Light Green
[ShadingRateFragmentSize.FragmentSize4x2] = new Color(0.20f, 0.40f, 0.20f, 1), // Dark Green
[ShadingRateFragmentSize.FragmentSize4x4] = new Color(0.125f, 0.22f, 0.36f, 1), // Dark Blue
};
}
[SerializeField]
Color[] m_Data = new Color[Vrs.shadingRateFragmentSizeCount];
/// <summary>
/// Indexing data with ShadingRateFragmentSize enum.
/// </summary>
/// <param name="fragmentSize">Shading rate fragment size to set/get</param>
public Color this[ShadingRateFragmentSize fragmentSize]
{
get => m_Data[(int)fragmentSize];
set => m_Data[(int)fragmentSize] = value;
}
/// <summary>
/// Create a compute buffer from the lookup table.
/// </summary>
/// <param name="forVisualization">If true, the buffer will be created with the visualization shader in mind</param>
/// <returns>Graphics buffer representing this lookup table</returns>
public GraphicsBuffer CreateBuffer(bool forVisualization = false)
{
GraphicsBuffer buffer;
Color[] bufferData;
if (forVisualization)
{
// lookup table will be used to map shading rate native values to colors
var fragmentSizes = Enum.GetValues(typeof(ShadingRateFragmentSize));
// Get the encoded binary value associated of the max shading rate supported by our LUT.
// The encoded value will not be sequential. For example, 4x4 is encoded as 0b1010 = 10.
// We do this manually as ShadingRateInfo.QueryNativeValue will return 0 for rates that are
// not supported, which can lead to overflow on devices that support only up to 2x2.
var maxNativeValue = MapFragmentShadingRateToBinary(ShadingRateFragmentSize.FragmentSize4x4);
bufferData = new Color[maxNativeValue + 1];
for (int i = fragmentSizes.Length - 1; i >= 0; --i)
{
var fragmentSize = (ShadingRateFragmentSize)fragmentSizes.GetValue(i);
var nativeValue = ShadingRateInfo.QueryNativeValue(fragmentSize);
bufferData[nativeValue] = m_Data[(int) fragmentSize].linear;
}
}
else
{
// lookup table will be used to map colors to shading rate index
bufferData = new Color[m_Data.Length];
for (int i = 0; i < m_Data.Length; ++i)
{
bufferData[i] = m_Data[i].linear;
}
}
buffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, bufferData.Length, Marshal.SizeOf(typeof(Color)));
buffer.SetData(bufferData);
return buffer;
}
private const uint Rate1x = 0;
private const uint Rate2x = 1;
private const uint Rate4x = 2;
private uint MapFragmentShadingRateToBinary(ShadingRateFragmentSize fs)
{
switch (fs)
{
default:
case ShadingRateFragmentSize.FragmentSize1x1:
return EncodeShadingRate(Rate1x, Rate1x);
case ShadingRateFragmentSize.FragmentSize1x2:
return EncodeShadingRate(Rate1x, Rate2x);
case ShadingRateFragmentSize.FragmentSize2x1:
return EncodeShadingRate(Rate2x, Rate1x);
case ShadingRateFragmentSize.FragmentSize2x2:
return EncodeShadingRate(Rate2x, Rate2x);
case ShadingRateFragmentSize.FragmentSize1x4:
return EncodeShadingRate(Rate1x, Rate4x);
case ShadingRateFragmentSize.FragmentSize4x1:
return EncodeShadingRate(Rate4x, Rate1x);
case ShadingRateFragmentSize.FragmentSize2x4:
return EncodeShadingRate(Rate2x, Rate4x);
case ShadingRateFragmentSize.FragmentSize4x2:
return EncodeShadingRate(Rate4x, Rate2x);
case ShadingRateFragmentSize.FragmentSize4x4:
return EncodeShadingRate(Rate4x, Rate4x);
}
}
private uint EncodeShadingRate(uint x, uint y)
{
return ((x << 2) | (y));
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 022af1b7cce79be46aec3272d72bf1f8
@@ -0,0 +1,74 @@
using System;
namespace UnityEngine.Rendering
{
/// <summary>
/// Class that stores the Variable Rate Shading common global resources
/// </summary>
[Serializable]
[SupportedOnRenderPipeline]
[Categorization.CategoryInfo(Name = "VRS - Runtime Resources", Order = 1000)]
public sealed class VrsRenderPipelineRuntimeResources : IRenderPipelineResources
{
/// <summary>
/// Version of the Vrs Resources
/// </summary>
public int version => 0;
bool IRenderPipelineGraphicsSettings.isAvailableInPlayerBuild => true;
[SerializeField]
[Tooltip("Compute shader used for converting textures to shading rate values")]
[ResourcePath("Runtime/Vrs/Shaders/VrsTexture.compute")]
ComputeShader m_TextureComputeShader;
/// <summary>
/// General Vrs compute shader.
/// </summary>
public ComputeShader textureComputeShader
{
get => m_TextureComputeShader;
set => this.SetValueAndNotify(ref m_TextureComputeShader, value, nameof(m_TextureComputeShader));
}
[SerializeField]
[Tooltip("Shader used when visualizing shading rate values as a color image")]
[ResourcePath("Runtime/Vrs/Shaders/VrsVisualization.shader")]
Shader m_VisualizationShader;
/// <summary>
/// Show resource shader.
/// </summary>
public Shader visualizationShader
{
get => m_VisualizationShader;
set => this.SetValueAndNotify(ref m_VisualizationShader, value, nameof(m_VisualizationShader));
}
[SerializeField]
[Tooltip("Colors to visualize the shading rates")]
VrsLut m_VisualizationLookupTable = VrsLut.CreateDefault();
/// <summary>
/// Shading rate visualization lookup table.
/// </summary>
public VrsLut visualizationLookupTable
{
get => m_VisualizationLookupTable;
set => this.SetValueAndNotify(ref m_VisualizationLookupTable, value, nameof(m_VisualizationLookupTable));
}
[SerializeField]
[Tooltip("Colors to convert between shading rates and textures")]
VrsLut m_ConversionLookupTable = VrsLut.CreateDefault();
/// <summary>
/// texture to/from Shading rate conversion lookup table.
/// </summary>
public VrsLut conversionLookupTable
{
get => m_ConversionLookupTable;
set => this.SetValueAndNotify(ref m_ConversionLookupTable, value, nameof(m_ConversionLookupTable));
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c75bfa9127302bc4cbc67983804a44ac
@@ -0,0 +1,174 @@
using System;
namespace UnityEngine.Rendering
{
class VrsResources : IDisposable
{
internal ProfilingSampler conversionProfilingSampler = new ProfilingSampler("VrsConversion");
internal ProfilingSampler visualizationProfilingSampler = new ProfilingSampler("VrsVisualization");
internal GraphicsBuffer conversionLutBuffer;
internal GraphicsBuffer visualizationLutBuffer;
internal ComputeShader textureComputeShader;
internal int textureReduceKernel = -1;
internal int textureCopyKernel = -1;
internal Vector2Int tileSize;
internal GraphicsBuffer validatedShadingRateFragmentSizeBuffer;
Shader m_VisualizationShader;
Material m_VisualizationMaterial;
internal Material visualizationMaterial
{
get
{
// explicit check here: handle case where m_Material is set to null when editor reloads
if (m_VisualizationMaterial == null)
m_VisualizationMaterial = new Material(m_VisualizationShader);
return m_VisualizationMaterial;
}
}
internal VrsResources(VrsRenderPipelineRuntimeResources resources)
{
InitializeResources(resources);
#if UNITY_EDITOR
GraphicsSettings.Unsubscribe<VrsRenderPipelineRuntimeResources>(OnVrsResourcesChanged);
GraphicsSettings.Subscribe<VrsRenderPipelineRuntimeResources>(OnVrsResourcesChanged);
#endif
}
#if UNITY_EDITOR
void OnVrsResourcesChanged(VrsRenderPipelineRuntimeResources resources, string propertyName)
{
DisposeResources();
InitializeResources(resources);
}
#endif
~VrsResources()
{
Dispose();
GC.SuppressFinalize(this);
}
public void Dispose()
{
#if UNITY_EDITOR
GraphicsSettings.Unsubscribe<VrsRenderPipelineRuntimeResources>(OnVrsResourcesChanged);
#endif
DisposeResources();
}
void InitializeResources(VrsRenderPipelineRuntimeResources resources)
{
bool success = InitComputeShader(resources);
if (!success)
{
DisposeResources();
return;
}
m_VisualizationShader = resources.visualizationShader;
conversionLutBuffer = resources.conversionLookupTable.CreateBuffer();
visualizationLutBuffer = resources.visualizationLookupTable.CreateBuffer(true);
AllocFragmentSizeBuffer();
}
void DisposeResources()
{
conversionLutBuffer?.Dispose();
conversionLutBuffer = null;
visualizationLutBuffer?.Dispose();
visualizationLutBuffer = null;
validatedShadingRateFragmentSizeBuffer?.Dispose();
validatedShadingRateFragmentSizeBuffer = null;
m_VisualizationShader = null;
CoreUtils.Destroy(m_VisualizationMaterial);
m_VisualizationMaterial = null;
}
void AllocFragmentSizeBuffer()
{
// Get available shading rate fragment sizes; unsupported ones
// will be mapped to the closest supported one.
var fragmentSize = new uint[Vrs.shadingRateFragmentSizeCount];
var lastAvailableFragmentSize = ShadingRateFragmentSize.FragmentSize1x1;
uint fragmentSizeNativeValue = ShadingRateInfo.QueryNativeValue(lastAvailableFragmentSize);
foreach (var availableFragmentSize in ShadingRateInfo.availableFragmentSizes)
{
Array.Fill(fragmentSize,
fragmentSizeNativeValue,
(int)lastAvailableFragmentSize,
availableFragmentSize - lastAvailableFragmentSize + 1);
lastAvailableFragmentSize = availableFragmentSize;
fragmentSizeNativeValue = ShadingRateInfo.QueryNativeValue(lastAvailableFragmentSize);
}
Array.Fill(fragmentSize,
fragmentSizeNativeValue,
(int)lastAvailableFragmentSize,
ShadingRateFragmentSize.FragmentSize4x4 - lastAvailableFragmentSize + 1);
validatedShadingRateFragmentSizeBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, fragmentSize.Length, sizeof(uint));
validatedShadingRateFragmentSizeBuffer.SetData(fragmentSize);
}
bool InitComputeShader(VrsRenderPipelineRuntimeResources resources)
{
// This Compute Shader resource is used for converting an RGB texture to an R8 SRI
// Don't initialize it if the device does not support image-based VRS
if (!ShadingRateInfo.supportsPerImageTile)
{
return false;
}
if (!SystemInfo.supportsComputeShaders)
{
return false;
}
tileSize = ShadingRateInfo.imageTileSize;
var tileSizeOk = tileSize.x == tileSize.y && (tileSize.x == 8 || tileSize.x == 16 || tileSize.x == 32);
if (!tileSizeOk)
{
Debug.LogError($"VRS unsupported tile size: {tileSize.x}x{tileSize.y}.");
return false;
}
// We expect keywords, if the shader was excluded/discarded then no keywords.
if (resources.textureComputeShader?.keywordSpace.keywordCount <= 0)
{
// Invalidate kernel indices in case they were set (shader reload)
textureReduceKernel = -1;
textureCopyKernel = -1;
return false;
}
textureComputeShader = resources.textureComputeShader;
// this keyword need only be set once
textureComputeShader.EnableKeyword($"{VrsShaders.k_TileSizePrefix}{tileSize.x}");
// find kernel might fail
textureReduceKernel = TryFindKernel(textureComputeShader, VrsShaders.k_KernelTextureReduce);
textureCopyKernel = TryFindKernel(textureComputeShader, VrsShaders.k_KernelTextureReduce);
if (textureReduceKernel == -1 || textureCopyKernel == -1)
return false;
return true;
}
static int TryFindKernel(ComputeShader computeShader, string name) => computeShader.HasKernel(name) ? computeShader.FindKernel(name) : -1;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 785d30f91e90dd2448cb87e5f026e49a
@@ -0,0 +1,24 @@
namespace UnityEngine.Rendering
{
static class VrsShaders
{
internal const string k_TileSizePrefix = "VRS_TILE_SIZE_";
internal const string k_DisableTexture2dXArray = "DISABLE_TEXTURE2D_X_ARRAY";
internal const string k_YFlip = "APPLY_Y_FLIP";
internal static readonly int s_ScaleBias = Shader.PropertyToID("_VrsScaleBias");
internal static readonly int s_MainTex = Shader.PropertyToID("_VrsMainTex");
internal static readonly int s_MainTexLut = Shader.PropertyToID("_VrsMainTexLut");
internal static readonly int s_ShadingRateNativeValues = Shader.PropertyToID("_ShadingRateNativeValues");
internal static readonly int s_ShadingRateImage = Shader.PropertyToID("_ShadingRateImage");
internal const string k_KernelTextureCopy = "TextureCopy";
internal const string k_KernelTextureReduce = "TextureReduce";
internal static readonly int s_VisualizationLut = Shader.PropertyToID("_VisualizationLut");
internal static readonly int s_VisualizationParams = Shader.PropertyToID("_VisualizationParams");
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4ba9dce31226373439673a105ffbaef2