Partial support for mesh shaders

This commit is contained in:
mcrcortex
2024-03-11 10:18:48 +10:00
parent 061058804d
commit 283084cfa8
24 changed files with 708 additions and 20 deletions

View File

@@ -17,6 +17,8 @@
"voxy.config.general.maxSections.tooltip": "The max number of sections the renderer can contain",
"voxy.config.general.renderDistance": "Render Distance",
"voxy.config.general.renderDistance.tooltip": "The render distance in chunks (set to -1 to disable chunk unloading)",
"voxy.config.general.nvmesh": "Use nvidia mesh shaders",
"voxy.config.general.nvmesh.tooltip": "Use nvidia mesh shaders if possible to render LoDs",
"voxy.config.threads.ingest": "Ingest",
"voxy.config.threads.ingest.tooltip": "How many threads voxy will use for ingesting new chunks",

View File

@@ -3,10 +3,10 @@
layout(local_size_x = 128) in;
#import <voxy:lod/gl46/quad_format.glsl>
#import <voxy:lod/quad_format.glsl>
#import <voxy:lod/gl46/bindings.glsl>
#import <voxy:lod/gl46/frustum.glsl>
#import <voxy:lod/gl46/section.glsl>
#import <voxy:lod/section.glsl>
#line 11
//https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_shader_16bit_storage.txt

View File

@@ -2,7 +2,7 @@
#extension GL_ARB_gpu_shader_int64 : enable
#define VISIBILITY_ACCESS writeonly
#import <voxy:lod/gl46/bindings.glsl>
#import <voxy:lod/gl46/section.glsl>
#import <voxy:lod/section.glsl>
flat out uint id;
flat out uint value;

View File

@@ -1,9 +1,9 @@
#version 460 core
#extension GL_ARB_gpu_shader_int64 : enable
#import <voxy:lod/gl46/quad_format.glsl>
#import <voxy:lod/quad_format.glsl>
#import <voxy:lod/gl46/bindings.glsl>
#import <voxy:lod/gl46/block_model.glsl>
#import <voxy:lod/block_model.glsl>
#line 8
layout(location = 0) out vec2 uv;

View File

@@ -0,0 +1,64 @@
struct SectionMeta {
uint posA;
uint posB;
uint AABB;
uint ptr;
uint cntA;
uint cntB;
uint cntC;
uint cntD;
};
struct BlockModel {
uint faceData[6];
uint flagsA;
uint colourTint;
uint _pad[8];
};
layout(binding = 0) uniform sampler2D blockModelAtlas;
layout(binding = 0, std140) uniform SceneUniform {
mat4 MVP;
ivec3 baseSectionPos;
int sectionCount;
vec3 cameraSubPos;
uint frameId;
};
#define Quad uint64_t
layout(binding = 1, std430) readonly restrict buffer QuadBuffer {
Quad quadData[];
};
layout(binding = 2, std430) readonly restrict buffer SectionBuffer {
SectionMeta sectionData[];
};
#ifndef VISIBILITY_ACCESS
#define VISIBILITY_ACCESS readonly
#endif
layout(binding = 3, std430) VISIBILITY_ACCESS restrict buffer VisibilityBuffer {
uint visibilityData[];
};
layout(binding = 4, std430) readonly restrict buffer ModelBuffer {
BlockModel modelData[];
};
layout(binding = 5, std430) readonly restrict buffer ModelColourBuffer {
uint colourData[];
};
layout(binding = 6, std430) readonly restrict buffer LightingBuffer {
uint lightData[];
};
vec4 getLighting(uint index) {
uvec4 arr = uvec4(lightData[index]);
arr = arr>>uvec4(16,8,0,24);
arr = arr & uvec4(0xFF);
return vec4(arr)*vec4(1.0f/255.0f);
}

View File

@@ -0,0 +1,14 @@
#version 460 core
#extension GL_ARB_gpu_shader_int64 : enable
#define VISIBILITY_ACCESS writeonly
#import <voxy:lod/nvmesh/bindings.glsl>
layout(early_fragment_tests) in;
flat in uint id;
flat in uint value;
//out vec4 colour;
void main() {
visibilityData[id] = value;
//colour = vec4(float(id&7u)/7, float((id>>3)&7u)/7, float((id>>6)&7u)/7, 1);
}

View File

@@ -0,0 +1,30 @@
#version 460 core
#extension GL_ARB_gpu_shader_int64 : enable
#define VISIBILITY_ACCESS writeonly
#import <voxy:lod/nvmesh/bindings.glsl>
#import <voxy:lod/section.glsl>
flat out uint id;
flat out uint value;
void main() {
uint sid = gl_InstanceID;
SectionMeta section = sectionData[sid];
uint detail = extractDetail(section);
ivec3 ipos = extractPosition(section);
ivec3 aabbOffset = extractAABBOffset(section);
ivec3 size = extractAABBSize(section);
//Transform ipos with respect to the vertex corner
ivec3 pos = (((ipos<<detail)-baseSectionPos)<<5);
pos += (aabbOffset-1)*(1<<detail);
pos += (ivec3(gl_VertexID&1, (gl_VertexID>>2)&1, (gl_VertexID>>1)&1)*(size+2))*(1<<detail);
gl_Position = MVP * vec4(vec3(pos)-cameraSubPos,1);
//Write to this id
id = sid;
value = frameId;
}

View File

@@ -1 +1,30 @@
#version 460 core
layout(binding = 0) uniform sampler2D blockModelAtlas;
layout(location=1) in Interpolants {
vec2 uv;
};
layout(location=2) perprimitiveNV in PerPrimData {
vec2 baseUV;
vec4 tinting;
vec4 addin;
uint flags;
vec4 conditionalTinting;
};
layout(location = 0) out vec4 outColour;
void main() {
vec2 uv = mod(uv, vec2(1.0))*(1.0/(vec2(3.0,2.0)*256.0));
vec4 colour = texture(blockModelAtlas, uv + baseUV, ((flags>>1)&1u)*-4.0);
if ((flags&1u) == 1 && colour.a <= 0.25f) {
discard;
}
//Conditional tinting, TODO: FIXME: REPLACE WITH MASK OR SOMETHING, like encode data into the top bit of alpha
if ((flags&(1u<<2)) != 0 && abs(colour.r-colour.g) < 0.02f && abs(colour.g-colour.b) < 0.02f) {
colour *= conditionalTinting;
}
outColour = (colour * tinting) + addin;
}

View File

@@ -0,0 +1,243 @@
#version 460
#extension GL_ARB_shading_language_include : enable
#pragma optionNV(unroll all)
#define UNROLL_LOOP
#extension GL_NV_mesh_shader : require
#extension GL_NV_gpu_shader5 : require
#extension GL_ARB_gpu_shader_int64 : require
#import <voxy:lod/nvmesh/bindings.glsl>
#import <voxy:lod/block_model.glsl>
#import <voxy:lod/quad_format.glsl>
#line 13
layout(local_size_x = 16) in;
layout(triangles, max_vertices=64, max_primitives=32) out;
layout(location=1) out Interpolants {
vec2 uv;
} i_out[];
layout(location=2) perprimitiveNV out PerPrimData {
vec2 baseUV;
vec4 tinting;
vec4 addin;
uint flags;
vec4 conditionalTinting;
} per_prim_out[];
void emitIndicies() {
uint primBase = gl_LocalInvocationID.x * 6;
uint vertBase = gl_LocalInvocationID.x<<2;
gl_PrimitiveIndicesNV[primBase+0] = vertBase+0;
gl_PrimitiveIndicesNV[primBase+1] = vertBase+1;
gl_PrimitiveIndicesNV[primBase+2] = vertBase+2;
gl_PrimitiveIndicesNV[primBase+3] = vertBase+2;
gl_PrimitiveIndicesNV[primBase+4] = vertBase+3;
gl_PrimitiveIndicesNV[primBase+5] = vertBase+0;
}
vec4 uint2vec4RGBA(uint colour) {
return vec4((uvec4(colour)>>uvec4(24,16,8,0))&uvec4(0xFF))/255.0;
}
//Gets the face offset with respect to the face direction (e.g. some will be + some will be -)
float getDepthOffset(uint faceData, uint face) {
float offset = extractFaceIndentation(faceData);
return offset * (1.0-((int(face)&1)*2.0));
}
vec4 getFaceSize(uint faceData) {
float EPSILON = 0.001f;
vec4 faceOffsetsSizes = extractFaceSizes(faceData);
//Expand the quads by a very small amount
faceOffsetsSizes.xz -= vec2(EPSILON);
faceOffsetsSizes.yw += vec2(EPSILON);
//Make the end relative to the start
faceOffsetsSizes.yw -= faceOffsetsSizes.xz;
return faceOffsetsSizes;
}
//TODO: make branchless by using ternaries i think
vec3 swizzelDataAxis(uint axis, vec3 data) {
if (axis == 0) { //Up/down
data = data.xzy;
}
//Not needed, here for readability
//if (axis == 1) {//north/south
// offset = offset.xyz;
//}
if (axis == 2) { //west/east
data = data.zxy;
}
return data;
}
taskNV in Task {
vec3 origin;//Offset to camera in world space (already multiplied by lod level)
uint baseOffset;//Base offset into the quad data buffer
//Binary search indexs and data
uvec4 binIa;
uvec4 binIb;
uvec4 binVa;
uvec4 binVb;
uint meta;//First 4 bits is lod level, remaining is quadCount
};
uint getQuadIndex() {
uint gii = gl_GlobalInvocationID.x;
//TODO: replace this with binary search
if (gii < binIa.x) {
return binVa.x + gii + baseOffset;
} else if (gii < binIa.y) {
return binVa.y + (gii - binIa.x) + baseOffset;
} else if (gii < binIa.z) {
return binVa.z + (gii - binIa.y) + baseOffset;
} else if (gii < binIa.w) {
return binVa.w + (gii - binIa.z) + baseOffset;
} else if (gii < binIb.x) {
return binVb.x + (gii - binIa.w) + baseOffset;
} else if (gii < binIb.y) {
return binVb.y + (gii - binIb.x) + baseOffset;
} else if (gii < binIb.z) {
return binVb.z + (gii - binIb.y) + baseOffset;
} else if (gii < binIb.w) {
return binVb.w + (gii - binIb.z) + baseOffset;
} else {
return uint(-1);
}
}
void main() {
uint idx = getQuadIndex();
//If its over, dont render
if (idx == uint(-1)) {
return;
}
emitIndicies();
uint A = gl_LocalInvocationID.x<<1;
uint B = (gl_LocalInvocationID.x<<1)|1u;
uint V = (gl_LocalInvocationID.x<<2);
uint lodLvl = meta&0xf;
float lodScale = (1<<lodLvl);
Quad quad = quadData[idx];
uint face = extractFace(quad);
uint modelId = extractStateId(quad);
BlockModel model = modelData[modelId];
uint faceData = model.faceData[face];
bool isTranslucent = modelIsTranslucent(model);
bool hasAO = modelHasMipmaps(model);//TODO: replace with per face AO flag
bool isShaded = hasAO;//TODO: make this a per face flag
ivec2 quadSize = extractSize(quad);
//Compute the uv coordinates
vec2 modelUV = vec2(modelId&0xFFu, (modelId>>8)&0xFFu)*(1.0/(256.0));
vec2 baseUV = modelUV + (vec2(face>>1, face&1u) * (1.0/(vec2(3.0, 2.0)*256.0)));
//Write out baseUV
per_prim_out[A].baseUV = baseUV;
per_prim_out[B].baseUV = baseUV;
uint flags = faceHasAlphaCuttout(faceData);
//We need to have a conditional override based on if the model size is < a full face + quadSize > 1
flags |= uint(any(greaterThan(quadSize, ivec2(1)))) & faceHasAlphaCuttoutOverride(faceData);
flags |= uint(!modelHasMipmaps(model))<<1;
//Compute lighting
vec4 tinting = getLighting(extractLightId(quad));
//Apply model colour tinting
uint tintColour = model.colourTint;
if (modelHasBiomeLUT(model)) {
tintColour = colourData[tintColour + extractBiomeId(quad)];
}
vec4 conditionalTinting = vec4(0);
if (tintColour != uint(-1)) {
flags |= 1u<<2;
conditionalTinting = uint2vec4RGBA(tintColour).yzwx;
}
vec4 addin = vec4(0.0);
if (!isTranslucent) {
tinting.w = 0.0;
//Encode the face, the lod level and
uint encodedData = 0;
encodedData |= face;
encodedData |= (lodLvl<<3);
encodedData |= uint(hasAO)<<6;
addin.w = float(encodedData)/255.0;
}
//Apply face tint
if (isShaded) {
//TODO: make branchless, infact apply ahead of time to the texture itself in ModelManager since that is
// per face
if ((face>>1) == 1) {
tinting.xyz *= 0.8f;
} else if ((face>>1) == 2) {
tinting.xyz *= 0.6f;
} else if (face == 0){
tinting.xyz *= 0.5f;
}
}
//Write out everything
per_prim_out[A].tinting = tinting;
per_prim_out[A].addin = addin;
per_prim_out[A].flags = flags;
per_prim_out[A].conditionalTinting = conditionalTinting;
per_prim_out[B].tinting = tinting;
per_prim_out[B].addin = addin;
per_prim_out[B].flags = flags;
per_prim_out[B].conditionalTinting = conditionalTinting;
vec4 faceSize = getFaceSize(faceData);
vec2 cQuadSize = faceSize.yw + quadSize - 1;
vec2 uv0 = faceSize.xz;
i_out[V|0].uv = uv0;
i_out[V|1].uv = uv0 + vec2(0, cQuadSize.y);
i_out[V|2].uv = uv0 + cQuadSize;
i_out[V|3].uv = uv0 + vec2(cQuadSize.x, 0);
//Corner position of quad relative to section corner (in 0->32 scale)
vec3 cornerPos = extractPos(quad);
float depthOffset = extractFaceIndentation(faceData);
cornerPos += swizzelDataAxis(face>>1, vec3(faceSize.xz, mix(depthOffset, 1-depthOffset, float(face&1u))));
gl_MeshVerticesNV[V|0].gl_Position = MVP*vec4(cornerPos*lodScale+origin, 1.0);
gl_MeshVerticesNV[V|1].gl_Position = MVP*vec4((cornerPos+swizzelDataAxis(face>>1,vec3(0,cQuadSize.y,0)))*lodScale+origin, 1.0);
gl_MeshVerticesNV[V|2].gl_Position = MVP*vec4((cornerPos+swizzelDataAxis(face>>1,vec3(cQuadSize, 0)))*lodScale+origin, 1.0);
gl_MeshVerticesNV[V|3].gl_Position = MVP*vec4((cornerPos+swizzelDataAxis(face>>1,vec3(cQuadSize.x,0,0)))*lodScale+origin, 1.0);
if (gl_LocalInvocationID.x == 0) {
//Remaining quads in workgroup
gl_PrimitiveCountNV = min(uint(int(meta>>4)-int(gl_WorkGroupID.x<<4))<<1, 32);//2 primatives per quad
}
}

View File

@@ -0,0 +1,118 @@
#version 460
#extension GL_ARB_shading_language_include : enable
#pragma optionNV(unroll all)
#define UNROLL_LOOP
#extension GL_NV_mesh_shader : require
#extension GL_NV_gpu_shader5 : require
#extension GL_ARB_gpu_shader_int64 : require
#import <voxy:lod/nvmesh/bindings.glsl>
#import <voxy:lod/section.glsl>
#line 12
#define MESH_WORKLOAD_PER_INVOCATION 16
layout(local_size_x=1) in;
taskNV out Task {
vec3 origin;//Offset to camera in world space (already multiplied by lod level)
uint baseOffset;//Base offset into the quad data buffer
//Binary search indexs and data
uvec4 binIa;
uvec4 binIb;
uvec4 binVa;
uvec4 binVb;
uint meta;//First 4 bits is lod level, remaining is quadCount
} task;
void putBinData(inout uint idx, inout uint lastIndex, uint offset, uint cnt) {
uint id = idx++;
if (id < 4) {
task.binIa[id] = lastIndex + cnt;
task.binVa[id] = offset;
} else {
task.binIb[id - 4] = lastIndex + cnt;
task.binVb[id - 4] = offset;
}
lastIndex += cnt;
}
void main() {
uint sectionId = gl_WorkGroupID.x;
bool visibleLastFrame = visibilityData[sectionId] == (frameId-1);
//If it wasnt visible last frame then dont render this frame ** (do temporal coherance)
if (!visibleLastFrame) {
gl_TaskCountNV = 0;
return;
}
SectionMeta meta = sectionData[sectionId];
uint lodLvl = extractDetail(meta);
ivec3 lodPos= extractPosition(meta);
//Relative position to camera with resepct to lod level to check for visibility bits
ivec3 cpos = lodPos-(baseSectionPos>>lodLvl);
//Relative position to camera
task.origin = vec3(((lodPos<<lodLvl)-baseSectionPos)<<5)-cameraSubPos;
task.baseOffset = extractQuadStart(meta);
task.meta = lodLvl&0xFu;
uint idx = 0;
uint lastIndex = 0;
uint offset = meta.cntA&0xFFFF;//Skip translucency
task.binIa = uvec4(0);
task.binIb = uvec4(0);
uint cnt = (meta.cntA>>16)&0xFFFF;
if (cnt!=0) {
putBinData(idx, lastIndex, offset, cnt);
}
offset += cnt;
cnt = meta.cntB &0xFFFF;
if ((cnt!=0) && (cpos.y>-1)) {
putBinData(idx, lastIndex, offset, cnt);
}
offset += cnt;
cnt = (meta.cntB>>16)&0xFFFF;
if((cnt!=0) && (cpos.y<1 )){
putBinData(idx, lastIndex, offset, cnt);
}
offset += cnt;
cnt = meta.cntC &0xFFFF;
if((cnt!=0) && (cpos.z>-1)){
putBinData(idx, lastIndex, offset, cnt);
}
offset += cnt;
cnt = (meta.cntC>>16)&0xFFFF;
if((cnt!=0) && (cpos.z<1 )){
putBinData(idx, lastIndex, offset, cnt);
}
offset += cnt;
cnt = meta.cntD &0xFFFF;
if((cnt!=0) && (cpos.x>-1)){
putBinData(idx, lastIndex, offset, cnt);
}
offset += cnt;
cnt = (meta.cntD>>16)&0xFFFF;
if((cnt!=0) && (cpos.x<1 )){
putBinData(idx, lastIndex, offset, cnt);
}
offset += cnt;
task.meta |= lastIndex<<4;
gl_TaskCountNV = (lastIndex+MESH_WORKLOAD_PER_INVOCATION-1)/MESH_WORKLOAD_PER_INVOCATION;
}

View File

@@ -19,11 +19,11 @@ vec4 reDeProject(vec3 pos) {
vec2 UV = clamp(view.xy*0.5+0.5, 0.0, 1.0);
//TODO: sample the colour texture and check if the alpha has the hasAO flag
float depth = texture(depthTex, UV, -4.0f).x;
float depth = texture(depthTex, UV).x;
if (depth == 1.0f) {
return vec4(-1.0f);
}
uint meta = uint(255.0f*texture(colourTex, UV, -4.0f).w);
uint meta = uint(255.0f*texture(colourTex, UV).w);
if ((meta>>6)==0) {
return vec4(-1.0f);
}