411 lines
20 KiB
C#
411 lines
20 KiB
C#
using UnityEngine.Experimental.Rendering;
|
|
|
|
namespace UnityEngine.Rendering.HighDefinition
|
|
{
|
|
public partial class HDRenderPipeline
|
|
{
|
|
// String values
|
|
const string m_RayGenIndirectDiffuseIntegrationName = "RayGenIntegration";
|
|
|
|
// Kernels
|
|
int m_RaytracingIndirectDiffuseFullResKernel;
|
|
int m_RaytracingIndirectDiffuseHalfResKernel;
|
|
int m_IndirectDiffuseUpscaleFullResKernel;
|
|
int m_IndirectDiffuseUpscaleHalfResKernel;
|
|
int m_AdjustIndirectDiffuseWeightKernel;
|
|
|
|
void InitRayTracedIndirectDiffuse()
|
|
{
|
|
ComputeShader indirectDiffuseShaderCS = m_Asset.renderPipelineRayTracingResources.indirectDiffuseRaytracingCS;
|
|
|
|
// Grab all the kernels we shall be using
|
|
m_RaytracingIndirectDiffuseFullResKernel = indirectDiffuseShaderCS.FindKernel("RaytracingIndirectDiffuseFullRes");
|
|
m_RaytracingIndirectDiffuseHalfResKernel = indirectDiffuseShaderCS.FindKernel("RaytracingIndirectDiffuseHalfRes");
|
|
m_IndirectDiffuseUpscaleFullResKernel = indirectDiffuseShaderCS.FindKernel("IndirectDiffuseIntegrationUpscaleFullRes");
|
|
m_IndirectDiffuseUpscaleHalfResKernel = indirectDiffuseShaderCS.FindKernel("IndirectDiffuseIntegrationUpscaleHalfRes");
|
|
m_AdjustIndirectDiffuseWeightKernel = indirectDiffuseShaderCS.FindKernel("AdjustIndirectDiffuseWeight");
|
|
}
|
|
|
|
void ReleaseRayTracedIndirectDiffuse()
|
|
{
|
|
}
|
|
|
|
static RTHandle IndirectDiffuseHistoryBufferAllocatorFunction(string viewName, int frameIndex, RTHandleSystem rtHandleSystem)
|
|
{
|
|
return rtHandleSystem.Alloc(Vector2.one, TextureXR.slices, colorFormat: GraphicsFormat.R16G16B16A16_SFloat, dimension: TextureXR.dimension,
|
|
enableRandomWrite: true, useMipMap: false, autoGenerateMips: false,
|
|
name: string.Format("{0}_IndirectDiffuseHistoryBuffer{1}", viewName, frameIndex));
|
|
}
|
|
|
|
DeferredLightingRTParameters PrepareIndirectDiffuseDeferredLightingRTParameters(HDCamera hdCamera)
|
|
{
|
|
DeferredLightingRTParameters deferredParameters = new DeferredLightingRTParameters();
|
|
|
|
// Fetch the GI volume component
|
|
var settings = hdCamera.volumeStack.GetComponent<GlobalIllumination>();
|
|
RayTracingSettings rTSettings = hdCamera.volumeStack.GetComponent<RayTracingSettings>();
|
|
|
|
// Make sure the binning buffer has the right size
|
|
CheckBinningBuffersSize(hdCamera);
|
|
|
|
// Generic attributes
|
|
deferredParameters.rayBinning = true;
|
|
deferredParameters.layerMask.value = (int)RayTracingRendererFlag.GlobalIllumination;
|
|
deferredParameters.diffuseLightingOnly = true;
|
|
|
|
deferredParameters.halfResolution = !settings.fullResolution;
|
|
deferredParameters.rayCountType = (int)RayCountValues.DiffuseGI_Deferred;
|
|
|
|
// Camera data
|
|
deferredParameters.width = hdCamera.actualWidth;
|
|
deferredParameters.height = hdCamera.actualHeight;
|
|
deferredParameters.viewCount = hdCamera.viewCount;
|
|
|
|
// Compute buffers
|
|
deferredParameters.rayBinResult = m_RayBinResult;
|
|
deferredParameters.rayBinSizeResult = m_RayBinSizeResult;
|
|
deferredParameters.accelerationStructure = RequestAccelerationStructure();
|
|
deferredParameters.lightCluster = RequestLightCluster();
|
|
|
|
// Shaders
|
|
deferredParameters.gBufferRaytracingRT = m_Asset.renderPipelineRayTracingResources.gBufferRaytracingRT;
|
|
deferredParameters.deferredRaytracingCS = m_Asset.renderPipelineRayTracingResources.deferredRaytracingCS;
|
|
deferredParameters.rayBinningCS = m_Asset.renderPipelineRayTracingResources.rayBinningCS;
|
|
|
|
// XRTODO: add ray binning support for single-pass
|
|
if (deferredParameters.viewCount > 1 && deferredParameters.rayBinning)
|
|
{
|
|
deferredParameters.rayBinning = false;
|
|
}
|
|
|
|
// Make a copy of the previous values that were defined in the CB
|
|
deferredParameters.raytracingCB = m_ShaderVariablesRayTracingCB;
|
|
// Override the ones we need to
|
|
deferredParameters.raytracingCB._RaytracingIntensityClamp = settings.clampValue;
|
|
deferredParameters.raytracingCB._RaytracingPreExposition = 1;
|
|
deferredParameters.raytracingCB._RaytracingIncludeSky = 1;
|
|
deferredParameters.raytracingCB._RaytracingRayMaxLength = settings.rayLength;
|
|
deferredParameters.raytracingCB._RayTracingDiffuseLightingOnly = 1;
|
|
|
|
return deferredParameters;
|
|
}
|
|
|
|
struct RTIndirectDiffuseDirGenParameters
|
|
{
|
|
// Camera parameters
|
|
public int texWidth;
|
|
public int texHeight;
|
|
public int viewCount;
|
|
|
|
// Generation parameters
|
|
public bool fullResolution;
|
|
|
|
// Additional resources
|
|
public BlueNoise.DitheredTextureSet ditheredTextureSet;
|
|
public int dirGenKernel;
|
|
public ComputeShader directionGenCS;
|
|
public ShaderVariablesRaytracing shaderVariablesRayTracingCB;
|
|
}
|
|
|
|
RTIndirectDiffuseDirGenParameters PrepareRTIndirectDiffuseDirGenParameters(HDCamera hdCamera, GlobalIllumination settings)
|
|
{
|
|
RTIndirectDiffuseDirGenParameters rtidDirGenParams = new RTIndirectDiffuseDirGenParameters();
|
|
|
|
// Set the camera parameters
|
|
rtidDirGenParams.texWidth = hdCamera.actualWidth;
|
|
rtidDirGenParams.texHeight = hdCamera.actualHeight;
|
|
rtidDirGenParams.viewCount = hdCamera.viewCount;
|
|
|
|
// Set the generation parameters
|
|
rtidDirGenParams.fullResolution = settings.fullResolution;
|
|
|
|
// Grab the right kernel
|
|
rtidDirGenParams.directionGenCS = m_Asset.renderPipelineRayTracingResources.indirectDiffuseRaytracingCS;
|
|
rtidDirGenParams.dirGenKernel = settings.fullResolution ? m_RaytracingIndirectDiffuseFullResKernel : m_RaytracingIndirectDiffuseHalfResKernel;
|
|
|
|
// Grab the additional parameters
|
|
BlueNoise blueNoise = GetBlueNoiseManager();
|
|
rtidDirGenParams.ditheredTextureSet = blueNoise.DitheredTextureSet8SPP();
|
|
rtidDirGenParams.shaderVariablesRayTracingCB = m_ShaderVariablesRayTracingCB;
|
|
|
|
return rtidDirGenParams;
|
|
}
|
|
|
|
struct RTIndirectDiffuseDirGenResources
|
|
{
|
|
// Input buffers
|
|
public RTHandle depthStencilBuffer;
|
|
public RTHandle normalBuffer;
|
|
|
|
// Output buffers
|
|
public RTHandle outputBuffer;
|
|
}
|
|
|
|
static void RTIndirectDiffuseDirGen(CommandBuffer cmd, RTIndirectDiffuseDirGenParameters rtidDirGenParams, RTIndirectDiffuseDirGenResources rtidDirGenResources)
|
|
{
|
|
// Inject the ray-tracing sampling data
|
|
BlueNoise.BindDitheredTextureSet(cmd, rtidDirGenParams.ditheredTextureSet);
|
|
|
|
// Bind all the required textures
|
|
cmd.SetComputeTextureParam(rtidDirGenParams.directionGenCS, rtidDirGenParams.dirGenKernel, HDShaderIDs._DepthTexture, rtidDirGenResources.depthStencilBuffer);
|
|
cmd.SetComputeTextureParam(rtidDirGenParams.directionGenCS, rtidDirGenParams.dirGenKernel, HDShaderIDs._NormalBufferTexture, rtidDirGenResources.normalBuffer);
|
|
|
|
// Bind the output buffers
|
|
cmd.SetComputeTextureParam(rtidDirGenParams.directionGenCS, rtidDirGenParams.dirGenKernel, HDShaderIDs._RaytracingDirectionBuffer, rtidDirGenResources.outputBuffer);
|
|
|
|
int numTilesXHR, numTilesYHR;
|
|
if (rtidDirGenParams.fullResolution)
|
|
{
|
|
// Evaluate the dispatch parameters
|
|
numTilesXHR = (rtidDirGenParams.texWidth + (rtReflectionsComputeTileSize - 1)) / rtReflectionsComputeTileSize;
|
|
numTilesYHR = (rtidDirGenParams.texHeight + (rtReflectionsComputeTileSize - 1)) / rtReflectionsComputeTileSize;
|
|
}
|
|
else
|
|
{
|
|
// Evaluate the dispatch parameters
|
|
numTilesXHR = (rtidDirGenParams.texWidth / 2 + (rtReflectionsComputeTileSize - 1)) / rtReflectionsComputeTileSize;
|
|
numTilesYHR = (rtidDirGenParams.texHeight / 2 + (rtReflectionsComputeTileSize - 1)) / rtReflectionsComputeTileSize;
|
|
}
|
|
|
|
// Compute the directions
|
|
cmd.DispatchCompute(rtidDirGenParams.directionGenCS, rtidDirGenParams.dirGenKernel, numTilesXHR, numTilesYHR, rtidDirGenParams.viewCount);
|
|
}
|
|
|
|
struct RTIndirectDiffuseUpscaleParameters
|
|
{
|
|
// Camera parameters
|
|
public int texWidth;
|
|
public int texHeight;
|
|
public int viewCount;
|
|
|
|
// Generation parameters
|
|
public int upscaleRadius;
|
|
|
|
// Additional resources
|
|
public Texture2DArray blueNoiseTexture;
|
|
public Texture2D scramblingTexture;
|
|
public int upscaleKernel;
|
|
public ComputeShader upscaleCS;
|
|
}
|
|
|
|
RTIndirectDiffuseUpscaleParameters PrepareRTIndirectDiffuseUpscaleParameters(HDCamera hdCamera, GlobalIllumination settings)
|
|
{
|
|
RTIndirectDiffuseUpscaleParameters rtidUpscaleParams = new RTIndirectDiffuseUpscaleParameters();
|
|
|
|
// Set the camera parameters
|
|
rtidUpscaleParams.texWidth = hdCamera.actualWidth;
|
|
rtidUpscaleParams.texHeight = hdCamera.actualHeight;
|
|
rtidUpscaleParams.viewCount = hdCamera.viewCount;
|
|
|
|
// Set the generation parameters
|
|
rtidUpscaleParams.upscaleRadius = settings.upscaleRadius;
|
|
|
|
// Grab the right kernel
|
|
rtidUpscaleParams.upscaleCS = m_Asset.renderPipelineRayTracingResources.indirectDiffuseRaytracingCS;
|
|
rtidUpscaleParams.upscaleKernel = settings.fullResolution ? m_IndirectDiffuseUpscaleFullResKernel : m_IndirectDiffuseUpscaleHalfResKernel;
|
|
|
|
// Grab the additional parameters
|
|
BlueNoise blueNoise = GetBlueNoiseManager();
|
|
rtidUpscaleParams.blueNoiseTexture = blueNoise.textureArray16RGB;
|
|
rtidUpscaleParams.scramblingTexture = m_Asset.renderPipelineResources.textures.scramblingTex;
|
|
|
|
return rtidUpscaleParams;
|
|
}
|
|
|
|
struct RTIndirectDiffuseUpscaleResources
|
|
{
|
|
// Input buffers
|
|
public RTHandle depthStencilBuffer;
|
|
public RTHandle normalBuffer;
|
|
public RTHandle indirectDiffuseBuffer;
|
|
public RTHandle directionBuffer;
|
|
|
|
// Output buffers
|
|
public RTHandle outputBuffer;
|
|
}
|
|
|
|
static void RTIndirectDiffuseUpscale(CommandBuffer cmd, RTIndirectDiffuseUpscaleParameters rtidUpscaleParams, RTIndirectDiffuseUpscaleResources rtidUpscaleResources)
|
|
{
|
|
// Inject all the parameters for the compute
|
|
cmd.SetComputeTextureParam(rtidUpscaleParams.upscaleCS, rtidUpscaleParams.upscaleKernel, HDShaderIDs._DepthTexture, rtidUpscaleResources.depthStencilBuffer);
|
|
cmd.SetComputeTextureParam(rtidUpscaleParams.upscaleCS, rtidUpscaleParams.upscaleKernel, HDShaderIDs._NormalBufferTexture, rtidUpscaleResources.normalBuffer);
|
|
cmd.SetComputeTextureParam(rtidUpscaleParams.upscaleCS, rtidUpscaleParams.upscaleKernel, HDShaderIDs._IndirectDiffuseTexture, rtidUpscaleResources.indirectDiffuseBuffer);
|
|
cmd.SetComputeTextureParam(rtidUpscaleParams.upscaleCS, rtidUpscaleParams.upscaleKernel, HDShaderIDs._RaytracingDirectionBuffer, rtidUpscaleResources.directionBuffer);
|
|
cmd.SetComputeTextureParam(rtidUpscaleParams.upscaleCS, rtidUpscaleParams.upscaleKernel, HDShaderIDs._BlueNoiseTexture, rtidUpscaleParams.blueNoiseTexture);
|
|
cmd.SetComputeTextureParam(rtidUpscaleParams.upscaleCS, rtidUpscaleParams.upscaleKernel, HDShaderIDs._ScramblingTexture, rtidUpscaleParams.scramblingTexture);
|
|
cmd.SetComputeIntParam(rtidUpscaleParams.upscaleCS, HDShaderIDs._SpatialFilterRadius, rtidUpscaleParams.upscaleRadius);
|
|
|
|
// Output buffer
|
|
cmd.SetComputeTextureParam(rtidUpscaleParams.upscaleCS, rtidUpscaleParams.upscaleKernel, HDShaderIDs._UpscaledIndirectDiffuseTextureRW, rtidUpscaleResources.outputBuffer);
|
|
|
|
// Texture dimensions
|
|
int texWidth = rtidUpscaleParams.texWidth;
|
|
int texHeight = rtidUpscaleParams.texHeight;
|
|
|
|
// Evaluate the dispatch parameters
|
|
int areaTileSize = 8;
|
|
int numTilesXHR = (texWidth + (areaTileSize - 1)) / areaTileSize;
|
|
int numTilesYHR = (texHeight + (areaTileSize - 1)) / areaTileSize;
|
|
|
|
// Compute the texture
|
|
cmd.DispatchCompute(rtidUpscaleParams.upscaleCS, rtidUpscaleParams.upscaleKernel, numTilesXHR, numTilesYHR, rtidUpscaleParams.viewCount);
|
|
}
|
|
|
|
struct AdjustRTIDWeightParameters
|
|
{
|
|
// Camera parameters
|
|
public int texWidth;
|
|
public int texHeight;
|
|
public int viewCount;
|
|
|
|
// Additional resources
|
|
public int adjustWeightKernel;
|
|
public ComputeShader adjustWeightCS;
|
|
}
|
|
|
|
AdjustRTIDWeightParameters PrepareAdjustRTIDWeightParametersParameters(HDCamera hdCamera)
|
|
{
|
|
AdjustRTIDWeightParameters parameters = new AdjustRTIDWeightParameters();
|
|
|
|
// Set the camera parameters
|
|
parameters.texWidth = hdCamera.actualWidth;
|
|
parameters.texHeight = hdCamera.actualHeight;
|
|
parameters.viewCount = hdCamera.viewCount;
|
|
|
|
// Grab the right kernel
|
|
parameters.adjustWeightCS = m_Asset.renderPipelineRayTracingResources.indirectDiffuseRaytracingCS;
|
|
parameters.adjustWeightKernel = m_AdjustIndirectDiffuseWeightKernel;
|
|
|
|
return parameters;
|
|
}
|
|
|
|
static void AdjustRTIDWeight(CommandBuffer cmd, AdjustRTIDWeightParameters parameters, RTHandle indirectDiffuseTexture, RTHandle depthPyramid, RTHandle stencilBuffer)
|
|
{
|
|
// Input data
|
|
cmd.SetComputeTextureParam(parameters.adjustWeightCS, parameters.adjustWeightKernel, HDShaderIDs._DepthTexture, depthPyramid);
|
|
cmd.SetComputeTextureParam(parameters.adjustWeightCS, parameters.adjustWeightKernel, HDShaderIDs._StencilTexture, stencilBuffer, 0, RenderTextureSubElement.Stencil);
|
|
cmd.SetComputeIntParams(parameters.adjustWeightCS, HDShaderIDs._SsrStencilBit, (int)StencilUsage.TraceReflectionRay);
|
|
|
|
// In/Output buffer
|
|
cmd.SetComputeTextureParam(parameters.adjustWeightCS, parameters.adjustWeightKernel, HDShaderIDs._IndirectDiffuseTextureRW, indirectDiffuseTexture);
|
|
|
|
// Texture dimensions
|
|
int texWidth = parameters.texWidth;
|
|
int texHeight = parameters.texHeight;
|
|
|
|
// Evaluate the dispatch parameters
|
|
int areaTileSize = 8;
|
|
int numTilesXHR = (texWidth + (areaTileSize - 1)) / areaTileSize;
|
|
int numTilesYHR = (texHeight + (areaTileSize - 1)) / areaTileSize;
|
|
|
|
// Compute the texture
|
|
cmd.DispatchCompute(parameters.adjustWeightCS, parameters.adjustWeightKernel, numTilesXHR, numTilesYHR, parameters.viewCount);
|
|
}
|
|
|
|
struct QualityRTIndirectDiffuseParameters
|
|
{
|
|
// Camera parameters
|
|
public int texWidth;
|
|
public int texHeight;
|
|
public int viewCount;
|
|
|
|
// Evaluation parameters
|
|
public float rayLength;
|
|
public int sampleCount;
|
|
public float clampValue;
|
|
public int bounceCount;
|
|
|
|
// Other parameters
|
|
public RayTracingShader indirectDiffuseRT;
|
|
public RayTracingAccelerationStructure accelerationStructure;
|
|
public HDRaytracingLightCluster lightCluster;
|
|
public Texture skyTexture;
|
|
public ShaderVariablesRaytracing shaderVariablesRayTracingCB;
|
|
public BlueNoise.DitheredTextureSet ditheredTextureSet;
|
|
}
|
|
|
|
QualityRTIndirectDiffuseParameters PrepareQualityRTIndirectDiffuseParameters(HDCamera hdCamera, GlobalIllumination settings)
|
|
{
|
|
QualityRTIndirectDiffuseParameters qrtidParams = new QualityRTIndirectDiffuseParameters();
|
|
|
|
// Set the camera parameters
|
|
qrtidParams.texWidth = hdCamera.actualWidth;
|
|
qrtidParams.texHeight = hdCamera.actualHeight;
|
|
qrtidParams.viewCount = hdCamera.viewCount;
|
|
|
|
// Evaluation parameters
|
|
qrtidParams.rayLength = settings.rayLength;
|
|
qrtidParams.sampleCount = settings.sampleCount.value;
|
|
qrtidParams.clampValue = settings.clampValue;
|
|
qrtidParams.bounceCount = settings.bounceCount.value;
|
|
|
|
// Grab the additional parameters
|
|
qrtidParams.indirectDiffuseRT = m_Asset.renderPipelineRayTracingResources.indirectDiffuseRaytracingRT;
|
|
qrtidParams.accelerationStructure = RequestAccelerationStructure();
|
|
qrtidParams.lightCluster = RequestLightCluster();
|
|
qrtidParams.skyTexture = m_SkyManager.GetSkyReflection(hdCamera);
|
|
qrtidParams.shaderVariablesRayTracingCB = m_ShaderVariablesRayTracingCB;
|
|
BlueNoise blueNoise = GetBlueNoiseManager();
|
|
qrtidParams.ditheredTextureSet = blueNoise.DitheredTextureSet8SPP();
|
|
return qrtidParams;
|
|
}
|
|
|
|
struct QualityRTIndirectDiffuseResources
|
|
{
|
|
// Input buffer
|
|
public RTHandle depthBuffer;
|
|
public RTHandle normalBuffer;
|
|
|
|
// Debug buffer
|
|
public RTHandle rayCountTexture;
|
|
|
|
// Ouput buffer
|
|
public RTHandle outputBuffer;
|
|
}
|
|
|
|
static void RenderQualityRayTracedIndirectDiffuse(CommandBuffer cmd, QualityRTIndirectDiffuseParameters qrtidParameters, QualityRTIndirectDiffuseResources qrtidResources)
|
|
{
|
|
// Define the shader pass to use for the indirect diffuse pass
|
|
cmd.SetRayTracingShaderPass(qrtidParameters.indirectDiffuseRT, "IndirectDXR");
|
|
|
|
// Set the acceleration structure for the pass
|
|
cmd.SetRayTracingAccelerationStructure(qrtidParameters.indirectDiffuseRT, HDShaderIDs._RaytracingAccelerationStructureName, qrtidParameters.accelerationStructure);
|
|
|
|
// Inject the ray-tracing sampling data
|
|
BlueNoise.BindDitheredTextureSet(cmd, qrtidParameters.ditheredTextureSet);
|
|
|
|
// Set the data for the ray generation
|
|
cmd.SetRayTracingTextureParam(qrtidParameters.indirectDiffuseRT, HDShaderIDs._IndirectDiffuseTextureRW, qrtidResources.outputBuffer);
|
|
cmd.SetRayTracingTextureParam(qrtidParameters.indirectDiffuseRT, HDShaderIDs._DepthTexture, qrtidResources.depthBuffer);
|
|
cmd.SetRayTracingTextureParam(qrtidParameters.indirectDiffuseRT, HDShaderIDs._NormalBufferTexture, qrtidResources.normalBuffer);
|
|
|
|
// Set ray count texture
|
|
cmd.SetRayTracingTextureParam(qrtidParameters.indirectDiffuseRT, HDShaderIDs._RayCountTexture, qrtidResources.rayCountTexture);
|
|
|
|
// LightLoop data
|
|
qrtidParameters.lightCluster.BindLightClusterData(cmd);
|
|
|
|
// Set the data for the ray miss
|
|
cmd.SetRayTracingTextureParam(qrtidParameters.indirectDiffuseRT, HDShaderIDs._SkyTexture, qrtidParameters.skyTexture);
|
|
|
|
// Update global constant buffer
|
|
qrtidParameters.shaderVariablesRayTracingCB._RaytracingIntensityClamp = qrtidParameters.clampValue;
|
|
qrtidParameters.shaderVariablesRayTracingCB._RaytracingIncludeSky = 1;
|
|
qrtidParameters.shaderVariablesRayTracingCB._RaytracingRayMaxLength = qrtidParameters.rayLength;
|
|
qrtidParameters.shaderVariablesRayTracingCB._RaytracingNumSamples = qrtidParameters.sampleCount;
|
|
qrtidParameters.shaderVariablesRayTracingCB._RaytracingMaxRecursion = qrtidParameters.bounceCount;
|
|
qrtidParameters.shaderVariablesRayTracingCB._RayTracingDiffuseLightingOnly = 1;
|
|
ConstantBuffer.PushGlobal(cmd, qrtidParameters.shaderVariablesRayTracingCB, HDShaderIDs._ShaderVariablesRaytracing);
|
|
|
|
// Only use the shader variant that has multi bounce if the bounce count > 1
|
|
CoreUtils.SetKeyword(cmd, "MULTI_BOUNCE_INDIRECT", qrtidParameters.bounceCount > 1);
|
|
|
|
// Run the computation
|
|
cmd.DispatchRays(qrtidParameters.indirectDiffuseRT, m_RayGenIndirectDiffuseIntegrationName, (uint)qrtidParameters.texWidth, (uint)qrtidParameters.texHeight, (uint)qrtidParameters.viewCount);
|
|
|
|
// Disable the keywords we do not need anymore
|
|
CoreUtils.SetKeyword(cmd, "MULTI_BOUNCE_INDIRECT", false);
|
|
}
|
|
}
|
|
}
|