implement tiled lighting part2

This commit is contained in:
turanszkij
2016-09-26 23:00:27 +02:00
parent 6e71c6f624
commit 099bc442e8
6 changed files with 185 additions and 94 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ struct Frustum
float4 ClipToView(float4 clip)
{
// View space position.
float4 view = mul(g_xCamera_InvP, clip);
float4 view = mul(clip, g_xCamera_InvP);
// Perspective projection.
view = view / view.w;
+9 -1
View File
@@ -133,6 +133,14 @@ inline float2 GetScreenResolution() { return g_xWorld_ScreenWidthHeight; }
inline float GetScreenWidth() { return g_xWorld_ScreenWidthHeight.x; }
inline float GetScreenHeight() { return g_xWorld_ScreenWidthHeight.y; }
inline float GetTime() { return g_xFrame_WindTime; }
inline float GetEmissive(float emissive) { return emissive * 10.0f; };
inline float GetEmissive(float emissive) { return emissive * 10.0f; }
struct ComputeShaderInput
{
uint3 groupID : SV_GroupID; // 3D index of the thread group in the dispatch.
uint3 groupThreadID : SV_GroupThreadID; // 3D index of local thread ID in a thread group.
uint3 dispatchThreadID : SV_DispatchThreadID; // 3D index of global thread ID in the dispatch.
uint groupIndex : SV_GroupIndex; // Flattened local index of the thread within a thread group.
};
#endif // _SHADER_GLOBALS_
+137 -59
View File
@@ -1,13 +1,9 @@
#include "globals.hlsli"
#include "cullingShaderHF.hlsli"
groupshared uint minDepthInt;
groupshared uint maxDepthInt;
RWTexture2D<float4> tex : register(u0);
RWTEXTURE2D(DebugTexture, float4, 0);
STRUCTUREDBUFFER(in_Frustums, Frustum, SBSLOT_TILEFRUSTUMS);
groupshared Frustum frustum;
struct LightArrayType
{
@@ -18,6 +14,12 @@ struct LightArrayType
RWSTRUCTUREDBUFFER(lightArray, LightArrayType, SBSLOT_LIGHTARRAY);
#define lightCount ((int)g_xColor.x)
groupshared uint uMinDepth;
groupshared uint uMaxDepth;
groupshared Frustum GroupFrustum;
bool intersects(LightArrayType light, Frustum frustum, float minZ, float maxZ)
{
Sphere sphere;
@@ -31,70 +33,146 @@ groupshared uint visibleLightIndices[1024];
#define BLOCK_SIZE 16
[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)]
void main(
uint3 groupId : SV_GroupID,
uint3 groupThreadId : SV_GroupThreadID,
uint3 dispatchThreadId : SV_DispatchThreadID, //
uint groupIndex : SV_GroupIndex)
void main(ComputeShaderInput IN)
{
float depth = texture_lineardepth.Load(uint3(dispatchThreadId.xy, 0)).r / g_xCamera_ZFarP;
uint depthInt = asuint(depth);
// Calculate min & max depth in threadgroup / tile.
int2 texCoord = IN.dispatchThreadID.xy;
float fDepth = texture_depth.Load(int3(texCoord, 0)).r;
if (groupIndex == 0) // Avoid contention by other threads in the group.
uint uDepth = asuint(fDepth);
if (IN.groupIndex == 0) // Avoid contention by other threads in the group.
{
minDepthInt = 0xffffffff;
maxDepthInt = 0;
uMinDepth = 0xffffffff;
uMaxDepth = 0;
//o_LightCount = 0;
//t_LightCount = 0;
frustum = in_Frustums[groupId.x + (groupId.y * numThreadGroups.x)];
}
//minDepthInt = 0xFFFFFFFF;
//maxDepthInt = 0;
GroupMemoryBarrierWithGroupSync();
InterlockedMin(minDepthInt, depthInt);
InterlockedMax(maxDepthInt, depthInt);
GroupMemoryBarrierWithGroupSync();
float minGroupDepth = asfloat(minDepthInt);
float maxGroupDepth = asfloat(maxDepthInt);
//tex[dispatchThreadId.xy] = minGroupDepth;
uint threadCount = BLOCK_SIZE*BLOCK_SIZE;
uint passCount = (lightCount + threadCount - 1) / threadCount;
for (uint passIt = 0; passIt < passCount; ++passIt)
{
uint lightIndex = passIt*threadCount + groupIndex;
// prevent overrun by clamping to last "null" light
lightIndex = min(lightIndex, lightCount);
if (intersects(lightArray[lightIndex], frustum, minGroupDepth, maxGroupDepth))
{
uint offset;
InterlockedAdd(visibleLightCount, 1, offset);
visibleLightIndices[offset] = lightIndex;
}
GroupFrustum = in_Frustums[IN.groupID.x + (IN.groupID.y * numThreadGroups.x)];
}
GroupMemoryBarrierWithGroupSync();
float4 color = 0;
for (uint lightIt = 0; lightIt < visibleLightCount; ++lightIt)
{
uint lightIndex = visibleLightIndices[lightIt];
LightArrayType light = lightArray[lightIndex];
InterlockedMin(uMinDepth, uDepth);
InterlockedMax(uMaxDepth, uDepth);
color += light.col;
}
color.a = 1;
GroupMemoryBarrierWithGroupSync();
color.rgb = frustum.planes[0].N;
float fMinDepth = asfloat(uMinDepth);
float fMaxDepth = asfloat(uMaxDepth);
tex[dispatchThreadId.xy] = color;
// Convert depth values to view space.
float minDepthVS = ScreenToView(float4(0, 0, fMinDepth, 1)).z;
float maxDepthVS = ScreenToView(float4(0, 0, fMaxDepth, 1)).z;
float nearClipVS = ScreenToView(float4(0, 0, 0, 1)).z;
// Clipping plane for minimum depth value
// (used for testing lights within the bounds of opaque geometry).
Plane minPlane = { float3(0, 0, -1), -minDepthVS };
//// Cull lights
//// Each thread in a group will cull 1 light until all lights have been culled.
//for (uint i = IN.groupIndex; i < NUM_LIGHTS; i += BLOCK_SIZE * BLOCK_SIZE)
//{
// if (Lights[i].Enabled)
// {
// Light light = Lights[i];
// switch (light.Type)
// {
// case POINT_LIGHT:
// {
// Sphere sphere = { light.PositionVS.xyz, light.Range };
// if (SphereInsideFrustum(sphere, GroupFrustum, nearClipVS, maxDepthVS))
// {
// // Add light to light list for transparent geometry.
// t_AppendLight(i);
// if (!SphereInsidePlane(sphere, minPlane))
// {
// // Add light to light list for opaque geometry.
// o_AppendLight(i);
// }
// }
// }
// break;
// case SPOT_LIGHT:
// {
// float coneRadius = tan(radians(light.SpotlightAngle)) * light.Range;
// Cone cone = { light.PositionVS.xyz, light.Range, light.DirectionVS.xyz, coneRadius };
// if (ConeInsideFrustum(cone, GroupFrustum, nearClipVS, maxDepthVS))
// {
// // Add light to light list for transparent geometry.
// t_AppendLight(i);
// if (!ConeInsidePlane(cone, minPlane))
// {
// // Add light to light list for opaque geometry.
// o_AppendLight(i);
// }
// }
// }
// break;
// case DIRECTIONAL_LIGHT:
// {
// // Directional lights always get added to our light list.
// // (Hopefully there are not too many directional lights!)
// t_AppendLight(i);
// o_AppendLight(i);
// }
// break;
// }
// }
//}
//// Wait till all threads in group have caught up.
//GroupMemoryBarrierWithGroupSync();
//// Update global memory with visible light buffer.
//// First update the light grid (only thread 0 in group needs to do this)
//if (IN.groupIndex == 0)
//{
// // Update light grid for opaque geometry.
// InterlockedAdd(o_LightIndexCounter[0], o_LightCount, o_LightIndexStartOffset);
// o_LightGrid[IN.groupID.xy] = uint2(o_LightIndexStartOffset, o_LightCount);
// // Update light grid for transparent geometry.
// InterlockedAdd(t_LightIndexCounter[0], t_LightCount, t_LightIndexStartOffset);
// t_LightGrid[IN.groupID.xy] = uint2(t_LightIndexStartOffset, t_LightCount);
//}
//GroupMemoryBarrierWithGroupSync();
//// Now update the light index list (all threads).
//// For opaque goemetry.
//for (i = IN.groupIndex; i < o_LightCount; i += BLOCK_SIZE * BLOCK_SIZE)
//{
// o_LightIndexList[o_LightIndexStartOffset + i] = o_LightList[i];
//}
//// For transparent geometry.
//for (i = IN.groupIndex; i < t_LightCount; i += BLOCK_SIZE * BLOCK_SIZE)
//{
// t_LightIndexList[t_LightIndexStartOffset + i] = t_LightList[i];
//}
//// Update the debug texture output.
//if (IN.groupThreadID.x == 0 || IN.groupThreadID.y == 0)
//{
// DebugTexture[texCoord] = float4(0, 0, 0, 0.9f);
//}
//else if (IN.groupThreadID.x == 1 || IN.groupThreadID.y == 1)
//{
// DebugTexture[texCoord] = float4(1, 1, 1, 0.5f);
//}
//else if (o_LightCount > 0)
//{
// float normalizedLightCount = o_LightCount / 50.0f;
// float4 lightCountHeatMapColor = LightCountHeatMap.SampleLevel(LinearClampSampler, float2(normalizedLightCount, 0), 0);
// DebugTexture[texCoord] = lightCountHeatMapColor;
//}
//else
//{
// DebugTexture[texCoord] = float4(0, 0, 0, 1);
//}
//DebugTexture[texCoord] = float4(GroupFrustum.planes[0].N,1);
}
+9 -12
View File
@@ -6,26 +6,22 @@ RWSTRUCTUREDBUFFER(out_Frustums, Frustum, SBSLOT_TILEFRUSTUMS);
#define BLOCK_SIZE 16
[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)]
void main(
uint3 groupId : SV_GroupID,
uint3 groupThreadId : SV_GroupThreadID,
uint3 dispatchThreadId : SV_DispatchThreadID, //
uint groupIndex : SV_GroupIndex)
void main(ComputeShaderInput IN)
{
// View space eye position is always at the origin.
const float3 eyePos = float3(0, 0, 0);
// Compute the 4 corner points on the far clipping plane to use as the
// Compute 4 points on the far clipping plane to use as the
// frustum vertices.
float4 screenSpace[4];
// Top left point
screenSpace[0] = float4(dispatchThreadId.xy * BLOCK_SIZE, 1.0f, 1.0f);
screenSpace[0] = float4(IN.dispatchThreadID.xy * BLOCK_SIZE, 1.0f, 1.0f);
// Top right point
screenSpace[1] = float4(float2(dispatchThreadId.x + 1, dispatchThreadId.y) * BLOCK_SIZE, 1.0f, 1.0f);
screenSpace[1] = float4(float2(IN.dispatchThreadID.x + 1, IN.dispatchThreadID.y) * BLOCK_SIZE, 1.0f, 1.0f);
// Bottom left point
screenSpace[2] = float4(float2(dispatchThreadId.x, dispatchThreadId.y + 1) * BLOCK_SIZE, 1.0f, 1.0f);
screenSpace[2] = float4(float2(IN.dispatchThreadID.x, IN.dispatchThreadID.y + 1) * BLOCK_SIZE, 1.0f, 1.0f);
// Bottom right point
screenSpace[3] = float4(float2(dispatchThreadId.x + 1, dispatchThreadId.y + 1) * BLOCK_SIZE, 1.0f, 1.0f);
screenSpace[3] = float4(float2(IN.dispatchThreadID.x + 1, IN.dispatchThreadID.y + 1) * BLOCK_SIZE, 1.0f, 1.0f);
float3 viewSpace[4];
// Now convert the screen space points to view space
@@ -47,9 +43,10 @@ void main(
frustum.planes[3] = ComputePlane(eyePos, viewSpace[3], viewSpace[2]);
// Store the computed frustum in global memory (if our thread ID is in bounds of the grid).
if (dispatchThreadId.x < numThreads.x && dispatchThreadId.y < numThreads.y)
if (IN.dispatchThreadID.x < numThreads.x && IN.dispatchThreadID.y < numThreads.y)
{
uint index = dispatchThreadId.x + (dispatchThreadId.y * numThreads.x);
uint index = IN.dispatchThreadID.x + (IN.dispatchThreadID.y * numThreads.x);
out_Frustums[index] = frustum;
}
//out_Frustums[0].planes[0].N = float3(1, 0, 1);
}
+23 -19
View File
@@ -246,6 +246,7 @@ void wiRenderer::SetUpStaticComponents()
GetDevice()->LOCK();
BindPersistentState(GRAPHICSTHREAD_IMMEDIATE);
UpdateWorldCB(GRAPHICSTHREAD_IMMEDIATE);
GetDevice()->UNLOCK();
//t1.join();
@@ -1426,13 +1427,16 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID)
static ShaderBoneType *bonebuf[GRAPHICSTHREAD_COUNT] = { 0 };
if (bonebuf[threadID] == nullptr)
{
bonebuf[threadID] = new ShaderBoneType[maxBoneCount];
bonebuf[threadID] = (ShaderBoneType*)_mm_malloc(sizeof(ShaderBoneType)*maxBoneCount, 16);
}
if (mesh->armature->boneCollection.size() > maxBoneCount)
{
maxBoneCount = (int)mesh->armature->boneCollection.size() * 2;
SAFE_DELETE_ARRAY(bonebuf[threadID]);
bonebuf[threadID] = new ShaderBoneType[maxBoneCount];
if (bonebuf[threadID] != nullptr)
{
_mm_free(bonebuf[threadID]);
}
bonebuf[threadID] = (ShaderBoneType*)_mm_malloc(sizeof(ShaderBoneType)*maxBoneCount, 16);
}
for (unsigned int k = 0; k < mesh->armature->boneCollection.size(); k++) {
bonebuf[threadID][k].pose = mesh->armature->boneCollection[k]->boneRelativity;
@@ -3309,10 +3313,22 @@ Texture2D* wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
int _width = device->GetScreenWidth();
int _height = device->GetScreenHeight();
int tileCount = (int)(ceilf((float)_width / 16.f) * ceilf((float)_height / 16.f));
// Calc dispatchparams
int _B = 16;
DispatchParamsCB dispatchParams;
dispatchParams.numThreads[0] = (UINT)ceilf((float)_width / _B);
dispatchParams.numThreads[1] = (UINT)ceilf((float)_height / _B);
dispatchParams.numThreads[2] = 1;
dispatchParams.numThreadGroups[0] = (UINT)ceilf((float)dispatchParams.numThreads[0] / _B);
dispatchParams.numThreadGroups[1] = (UINT)ceilf((float)dispatchParams.numThreads[1] / _B);
dispatchParams.numThreadGroups[2] = 1;
device->UpdateBuffer(constantBuffers[CBTYPE_DISPATCHPARAMS], &dispatchParams, threadID);
device->BindConstantBufferCS(constantBuffers[CBTYPE_DISPATCHPARAMS], CB_GETBINDSLOT(DispatchParamsCB), threadID);
static GPUBuffer* frustumBuffer = nullptr;
if(frustumBuffer == nullptr)
if (frustumBuffer == nullptr)
{
frustumBuffer = new GPUBuffer;
@@ -3320,7 +3336,7 @@ Texture2D* wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
GPUBufferDesc bd;
ZeroMemory(&bd, sizeof(bd));
bd.ByteWidth = _stride * tileCount; // storing 4 planes for every tile
bd.ByteWidth = _stride * dispatchParams.numThreads[0] * dispatchParams.numThreads[1] * dispatchParams.numThreads[2]; // storing 4 planes for every tile
bd.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
bd.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
bd.Usage = USAGE_DEFAULT;
@@ -3330,18 +3346,6 @@ Texture2D* wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
}
// Calc dispatchparams
int _B = 16;
DispatchParamsCB dispatchParams;
dispatchParams.numThreads[0] = (uint32_t)ceilf((float)_width / _B);
dispatchParams.numThreads[1] = (uint32_t)ceilf((float)_height / _B);
dispatchParams.numThreads[2] = 1;
dispatchParams.numThreadGroups[0] = (uint32_t)ceilf((float)dispatchParams.numThreads[0] / _B);
dispatchParams.numThreadGroups[1] = (uint32_t)ceilf((float)dispatchParams.numThreads[1] / _B);
dispatchParams.numThreadGroups[0] = 1;
device->UpdateBuffer(constantBuffers[CBTYPE_DISPATCHPARAMS], &dispatchParams, threadID);
device->BindConstantBufferCS(constantBuffers[CBTYPE_DISPATCHPARAMS], CB_GETBINDSLOT(DispatchParamsCB), threadID);
// calculate the per-tile frustums once:
static bool frustumsComplete = false;
if(!frustumsComplete)
@@ -3349,7 +3353,7 @@ Texture2D* wiRenderer::ComputeTiledLightCulling(GRAPHICSTHREAD threadID)
frustumsComplete = true;
device->BindUnorderedAccessResourceCS(frustumBuffer, SBSLOT_TILEFRUSTUMS, threadID);
device->BindCS(computeShaders[CSTYPE_TILEFRUSTUMS], threadID);
device->Dispatch(dispatchParams.numThreads[0], dispatchParams.numThreads[1], dispatchParams.numThreads[2], threadID);
device->Dispatch(dispatchParams.numThreadGroups[0], dispatchParams.numThreadGroups[1], dispatchParams.numThreadGroups[2], threadID);
device->UnBindUnorderedAccessResources(SBSLOT_TILEFRUSTUMS, 1, threadID);
}
+6 -2
View File
@@ -257,8 +257,8 @@ public:
};
GFX_STRUCT DispatchParamsCB
{
uint32_t numThreadGroups[3]; uint32_t pad0;
uint32_t numThreads[3]; uint32_t pad1;
UINT numThreadGroups[3]; UINT pad0;
UINT numThreads[3]; UINT pad1;
CB_SETBINDSLOT(CBSLOT_RENDERER_DISPATCHPARAMS)
@@ -271,6 +271,8 @@ public:
XMFLOAT4X4 pose, prev;
STRUCTUREDBUFFER_SETBINDSLOT(SBSLOT_BONE)
ALIGN_16
};
GFX_STRUCT LightArrayType
@@ -280,6 +282,8 @@ public:
XMFLOAT4 col;
STRUCTUREDBUFFER_SETBINDSLOT(SBSLOT_LIGHTARRAY)
ALIGN_16
};
protected: