Hi! I have black screen using tessellation shaders on nVidia GT 1030.
Windows 10 X64, last drivers 496.49
AMD RX 560:
I attached full demo with source HLSL files and spir-v result: VulkanDemoTerrainTesselation
Shader from VulkanDemoTerrainTesselation:
vs.vert - Vertex shader
#define location(x) [[vk::location(x)]]
struct Output {
float4 pos : SV_POSITION;
location(0) float2 texCoord : TEXCOORD0;
location(1) float3 Normal : NORMAL;
};
struct Input {
location(0) float4 pos: SV_POSITION;
location(8) float2 uv : TEXCOORD0;
location(2) float3 Normal : NORMAL;
};
Output vsMain(in Input input) {
Output output;
output.pos = float4(input.pos.xyz, 1.0f);
output.Normal = input.Normal;
output.texCoord = input.uv;
return output;
}
hs.tesc - Hull shader
#define location(x) [[vk::location(x)]]
#define binding(x) [[vk::binding(x)]]
#define MAX_TF 20.0f
struct ConstantsHSOutput {
float Edges[4] : SV_TessFactor;
float Inside[2] : SV_InsideTessFactor;
};
struct Input{
float4 pos : SV_POSITION;
location(0) float2 uv : TEXCOORD0;
location(1) float3 Normal : NORMAL;
};
#define MAX_TF 20.0f
binding(0) cbuffer b0: register(b0) {
row_major float4x4 view;
row_major float4x4 proj;
float4 cameraPosition;
float LodDistance;
float tessellationFactor;
float tessellatedEdgeSize;
float2 viewportDim;
uint numLods;
};
float distSq(float3 p0, float3 p1) {
float3 d = p0 - p1;
return dot(d, d);
}
float screenSpaceTessFactor(float4 p0, float4 p1) {
float4 midPoint = 0.5f * (p0 + p1);
float radius = distance(p0, p1) * 0.5f;
float4 v0 = mul(midPoint, view); float4 clip0 = mul(float4(v0.x - radius,
v0.yzw), proj);
float4 clip1 = mul(float4(v0.x + radius, v0.yzw), proj);
clip0 /= clip0.w;
clip1 /= clip1.w;
clip0.xy *= viewportDim;
clip1.xy *= viewportDim;
#ifdef D3D12
return max(distance(clip0, clip1) / tessellatedEdgeSize * tessellationFactor, 1.0f);
#else
return clamp(distance(clip0, clip1) / tessellatedEdgeSize * tessellationFactor, 1.0f, MAX_TF);
#endif
}
float CalculateTessFactor(float4 p0, float4 p1) {
#ifdef USE_SS_TESS_FACTOR_CALC
return screenSpaceTessFactor(p0, p1);
#else
float3 center = (p0 + p1).xyz * 0.5f;
float factor = LodDistance / distSq(center, cameraPosition);
return clamp(factor, 1.0f, numLods);
#endif
}
ConstantsHSOutput ConstantsHS(InputPatch<Input, 4> ip, uint PatchID : SV_PrimitiveID) {
ConstantsHSOutput hsOut;
hsOut.Edges[0] = CalculateTessFactor(ip[0].pos, ip[3].pos);
hsOut.Edges[1] = CalculateTessFactor(ip[1].pos, ip[0].pos);
hsOut.Edges[2] = CalculateTessFactor(ip[2].pos, ip[1].pos);
hsOut.Edges[3] = CalculateTessFactor(ip[3].pos, ip[2].pos);
hsOut.Inside[0] = lerp(hsOut.Edges[0], hsOut.Edges[3], 0.5f);
hsOut.Inside[1] = lerp(hsOut.Edges[1], hsOut.Edges[2], 0.5f);
return hsOut;
}
[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(4)]
[patchconstantfunc("ConstantsHS")]
[maxtessfactor(MAX_TF)]
Input hMain(InputPatch<Input, 4> ip, uint i : SV_OutputControlPointID, uint PatchID : SV_PrimitiveID) {
Input output;
output.pos = float4(ip[i].pos.xyz, 1.0f);
output.uv = ip[i].uv;
output.Normal = ip[i].Normal;
return output;
}
ds.tese - Domain shader
#define location(x) [[vk::location(x)]]
#define binding(x) [[vk::binding(x)]]
#define MULTIPLE_LIGHTS 1
struct ConstantsHSOutput {
float Edges[4] : SV_TessFactor;
float Inside[2] : SV_InsideTessFactor;
};
struct Output{
location(0) float4 pos : POSITION;
location(1) float2 texCoord : TEXCOORD0;
location(2) float3 Normal : NORMAL;
location(3) float3 lightDir : TEXCOORD1;
location(4) float4 shadowCrd : TEXCOORD2;
location(5) float4 lightProjSpaceLokup : TEXCOORD3;
location(6) float3 vVec : TEXCOORD4;
location(7) float3 viewDir : TEXCOORD5;
};
binding(1) cbuffer b0 : register(b0) {
row_major float4x4 ModelViewProjection;
row_major float4x4 proj;
float4 cameraPosition;
float4 LightDir;
row_major float4x4 MatTexture;
row_major float4x4 ViewMatrix;
float scaleHeight;
float2 uvScale;
};
binding(2) Texture2D HeightMap : register(t0);
binding(2) SamplerState Sampler : register(s0);
struct Input {
location(0) float4 pos: SV_POSITION;
location(8) float2 uv : TEXCOORD0;
location(2) float3 Normal : NORMAL;
};
float4 CalcLightProjSpaceLookup(float4 projectSpace) { projectSpace.xy = (projectSpace.xy + float2(projectSpace.w, projectSpace.w)) * 0.5; return projectSpace;}
Output vsMain(in Input input) {
Output output;
float4 Pos = float4(input.pos.xyz, 1.0f);
output.pos = mul(Pos, ModelViewProjection);
#ifdef MULTIPLE_LIGHTS
output.lightProjSpaceLokup = CalcLightProjSpaceLookup(output.pos);
#ifdef NO_LIGHT_VIEW_SPACE
output.vVec = pos.xyz;
#else
output.vVec = mul(Pos, ViewMatrix).xyz;
output.viewDir = cameraPosition.xyz - Pos.xyz;
#endif
#endif
output.shadowCrd = mul(Pos, MatTexture);
output.texCoord = input.uv;
output.Normal = mul(input.Normal, (float3x3)ViewMatrix);
output.lightDir = -LightDir.xyz;
return output;
}
[domain("quad")]
Output dMain(in ConstantsHSOutput input, float2 domain : SV_DomainLocation, const OutputPatch<Input, 4> patch) {
Output dsOutput;
Input vsIn;
vsIn.pos = lerp(lerp(patch[0].pos, patch[1].pos, domain.x), lerp(patch[3].pos, patch[2].pos, domain.x), domain.y);
float2 uv = vsIn.pos.xz * uvScale;
vsIn.pos.y = HeightMap.SampleLevel(Sampler, uv, 0.0).r * scaleHeight;
vsIn.uv = lerp(lerp(patch[0].uv, patch[1].uv, domain.x), lerp(patch[3].uv, patch[2].uv, domain.x), domain.y);
vsIn.Normal = lerp(lerp(patch[0].Normal, patch[1].Normal, domain.x), lerp(patch[3].Normal, patch[2].Normal, domain.x), domain.y);
dsOutput = vsMain(vsIn);
return dsOutput;
}
ps.frag - Pixel shader
//
#define location(x) layout(location = x)
#define binding(x) [[vk::binding(x)]]
#define SIMPLE_POINT_LIGHT
#defne MULTIPLE_LIGHTS
//
struct PSOutput {
location(0) float4 pos : SV_POSITION;
location(1) float2 texCoord : TEXCOORD0;
location(2) float3 Normal : NORMAL;
location(3) float3 lightDir : TEXCOORD1;
location(4) float4 shadowCrd: TEXCOORD2;
#ifdef MULTIPLE_LIGHTS
location(5) float4 lightProjSpaceLokup : TEXCOORD3;
location(6) float3 vVec : TEXCOORD4;
location(7) float3 viewDir : TEXCOORD5;
#endif
};
binding(3) Texture2D tex1 : register(t0);
binding(3) SamplerState samLinear1 : register(s0);
binding(4) Texture2D tex2 : register(t1);
binding(4) SamplerState samLinear2 : register(s1);
binding(5) Texture2D ShadowMap : register(t2);
binding(5) SamplerState sShadowMap : register(s2);
#ifdef MULTIPLE_LIGHTS
binding(6) Texture2D BitPlane : register(t3);
binding(6) SamplerState sBitPlane : register(s3);
#endif
struct Light {
float4 posRange;
float4 colorLightType;
#ifndef SIMPLE_POINT_LIGHT
float4 directionFalloff;
float4 lighTypeAttenuation;
float4 ThetaPhi;
#endif
};
#ifdef MULTIPLE_LIGHTS
binding(7) cbuffer b0: register(b0) {
Light lights[NUM_LIGHTS];
};
#define NEW_MULTI_LIGHTING
#ifdef NEW_MULTI_LIGHTING
float4 CalculateLighting(float4 Color, float3 worldPos, float3 Normal, float3 viewDir, float4 lightIndex)
{
float3 ambient_color = float3(0.0f, 0.0f, 0.0f);
float3 color = float3(0.0f, 0.0f, 0.0f);
float3 n = normalize(Normal);
float3 v = normalize(viewDir);
#ifndef NO_LIGHT_BUFFER
for (int i = 0; i < 4; ++i)
{
float lIndex = 256.0f * lightIndex[i];
Light light = lights[int(lIndex)];
#else
for (int i = 0; i < 255; ++i)
{
Light light = lights[i];
#endif
float3 l = (light.posRange.xyz - worldPos) * light.posRange.w;
float atten = saturate(1.0f - dot(l, l));
l = normalize(l);
float3 h = normalize(l + v);
float nDotL = saturate(dot(n, l));
float nDotH = saturate(dot(n, h));
float power = (nDotL == 0.0f) ? 0.0f : pow(nDotH, 16.0f);
color += (light.colorLightType.xyz * nDotL * atten) + power * atten;
}
color += ambient_color;
return float4(color.xyz, Color.a);
}
#else
float4 CalculateLighting(float4 color, float3 vVec, float3 Normal, float4 lightIndex)
{
float3 ambient_color = float3(0.2f, 0.2f, 0.2f);
float3 lighting = float3(0.0f, 0.0f, 0.0f);
for (int i = 0; i < 4; ++i) {
float lIndex = 255.0f * lightIndex[i];
Light light = lights[int(lIndex)];
if (!light.posRange.w) {
//return float4(0.0f, 0.0f, 0.0f, 0.0f);
//continue;
}
// Get the vector from the light center to the surface
float3 lightVec = light.posRange.xyz - vVec;
#if 1
#if 1
// Scale based on the light radius
float3 lVec = lightVec * light.posRange.a;
float atten = 1.0f - saturate(dot(lVec, lVec));
#else
float d = length(lightVec) / light.posRange.a;
float atten = 1.0f - saturate(d);
#endif
#else
float d = length(lightVec) * light.posRange.a;
const float3 ConstantAtten = float3(0.4f, 0.01f, 0.01f);
float atten = 1.0f / (ConstantAtten.x + ConstantAtten.y * d + ConstantAtten.z * d * d);
#endif
lightVec = normalize(lightVec);
float3 H = normalize(lightVec + vVec);
float diffuse = saturate(dot(lightVec, Normal));
float specular = pow(saturate(dot(lightVec, H)), 16.0);
lighting += atten * (diffuse * light.colorLightType.xyz * color.xyz + color.xyz * ambient_color + light.colorLightType.xyz * specular);
}
//lighting = max(lighting, 0.0f);
return float4(lighting.xyz, color.a);
//return float4(color.xyz, color.a);
}
#endif // NEW_MULTI_LIGHTING
#endif // MULTIPLE_LIGHTS
float4 psMain(in PSOutput In) : SV_Target {
float4 color = tex1.Sample(samLinear1, In.texCoord);
float4 color2 = tex2.Sample(samLinear2, In.texCoord);
color *= color2;
float4 shadowCrd = In.shadowCrd;
float shadowColor = 0.5f;
#ifdef PCF
float sh = PCFFilter(4.0, ShadowMap, shadowCrd, shadowColor);
#else
shadowCrd.xyz /= shadowCrd.w;
float shadow = ShadowMap.Sample(sShadowMap, shadowCrd.xy).r;
float sh = shadow < shadowCrd.z - 0.001f ? shadowColor : 1.0f;
#endif
float3 normal = normalize(In.Normal);
#ifdef MULTIPLE_LIGHTS
float4 lightIndex = GetLightIndex(BitPlane, In.lightProjSpaceLokup);
#ifdef NEW_MULTI_LIGHTING
float3 viewDir = normalize(In.viewDir);
float4 Albedo = CalculateLighting(color, In.vVec, normal, viewDir, lightIndex);
#else
float4 Albedo = CalculateLighting(color, In.vVec, normal, lightIndex);
#endif
#endif
float3 lightDir = normalize(In.lightDir);
float I = saturate(dot(lightDir, normal));
const float3 ambient = float3(0.2f, 0.2f, 0.2f);
#ifdef MULTIPLE_LIGHTS
color.xyz += Albedo.zyz;
#endif
color.xyz += ambient;
color.xyz *= I;
color.xyz *= sh;
return color;
}
The Direct3D12 version of the same shaders shows correct result.
Do we have nVidia driver bug or DXC/glslang translation from HLSL to SPIR-V bug ?