diff options
Diffstat (limited to 'source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl')
-rw-r--r-- | source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl new file mode 100644 index 00000000000..5dd7decf663 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl @@ -0,0 +1,416 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +/* Source buffer. */ +layout(std430, binding = 0) buffer src_buffer +{ + float srcVertexBuffer[]; +}; + +/* #DRWPatchMap */ +layout(std430, binding = 1) readonly buffer inputPatchHandles +{ + PatchHandle input_patch_handles[]; +}; + +layout(std430, binding = 2) readonly buffer inputQuadNodes +{ + QuadNode quad_nodes[]; +}; + +layout(std430, binding = 3) readonly buffer inputPatchCoords +{ + BlenderPatchCoord patch_coords[]; +}; + +layout(std430, binding = 4) readonly buffer inputVertOrigIndices +{ + int input_vert_origindex[]; +}; + +/* Patch buffers. */ +layout(std430, binding = 5) buffer patchArray_buffer +{ + OsdPatchArray patchArrayBuffer[]; +}; + +layout(std430, binding = 6) buffer patchIndex_buffer +{ + int patchIndexBuffer[]; +}; + +layout(std430, binding = 7) buffer patchParam_buffer +{ + OsdPatchParam patchParamBuffer[]; +}; + + /* Output buffer(s). */ + +#if defined(FVAR_EVALUATION) +layout(std430, binding = 8) writeonly buffer outputFVarData +{ + vec2 output_fvar[]; +}; +#elif defined(FDOTS_EVALUATION) +/* For face dots, we build the position, normals, and index buffers in one go. */ + +/* vec3 is padded to vec4, but the format used for fdots does not have any padding. */ +struct FDotVert { + float x, y, z; +}; + +/* Same here, do not use vec3. */ +struct FDotNor { + float x, y, z; + float flag; +}; + +layout(std430, binding = 8) writeonly buffer outputVertices +{ + FDotVert output_verts[]; +}; + +layout(std430, binding = 9) writeonly buffer outputNormals +{ + FDotNor output_nors[]; +}; + +layout(std430, binding = 10) writeonly buffer outputFdotsIndices +{ + uint output_indices[]; +}; + +layout(std430, binding = 11) readonly buffer extraCoarseFaceData +{ + uint extra_coarse_face_data[]; +}; +#else +layout(std430, binding = 8) writeonly buffer outputVertexData +{ + PosNorLoop output_verts[]; +}; +#endif + +vec2 read_vec2(int index) +{ + vec2 result; + result.x = srcVertexBuffer[index * 2]; + result.y = srcVertexBuffer[index * 2 + 1]; + return result; +} + +vec3 read_vec3(int index) +{ + vec3 result; + result.x = srcVertexBuffer[index * 3]; + result.y = srcVertexBuffer[index * 3 + 1]; + result.z = srcVertexBuffer[index * 3 + 2]; + return result; +} + +OsdPatchArray GetPatchArray(int arrayIndex) +{ + return patchArrayBuffer[arrayIndex]; +} + +OsdPatchParam GetPatchParam(int patchIndex) +{ + return patchParamBuffer[patchIndex]; +} + +/* ------------------------------------------------------------------------------ + * Patch Coordinate lookup. Return an OsdPatchCoord for the given patch_index and uvs. + * This code is a port of the OpenSubdiv PatchMap lookup code. + */ + +PatchHandle bogus_patch_handle() +{ + PatchHandle ret; + ret.array_index = -1; + ret.vertex_index = -1; + ret.patch_index = -1; + return ret; +} + +int transformUVToQuadQuadrant(float median, inout float u, inout float v) +{ + int uHalf = (u >= median) ? 1 : 0; + if (uHalf != 0) + u -= median; + + int vHalf = (v >= median) ? 1 : 0; + if (vHalf != 0) + v -= median; + + return (vHalf << 1) | uHalf; +} + +int transformUVToTriQuadrant(float median, inout float u, inout float v, inout bool rotated) +{ + + if (!rotated) { + if (u >= median) { + u -= median; + return 1; + } + if (v >= median) { + v -= median; + return 2; + } + if ((u + v) >= median) { + rotated = true; + return 3; + } + return 0; + } + else { + if (u < median) { + v -= median; + return 1; + } + if (v < median) { + u -= median; + return 2; + } + u -= median; + v -= median; + if ((u + v) < median) { + rotated = false; + return 3; + } + return 0; + } +} + +PatchHandle find_patch(int face_index, float u, float v) +{ + if (face_index < min_patch_face || face_index > max_patch_face) { + return bogus_patch_handle(); + } + + QuadNode node = quad_nodes[face_index - min_patch_face]; + + if (!is_set(node.child[0])) { + return bogus_patch_handle(); + } + + float median = 0.5; + bool tri_rotated = false; + + for (int depth = 0; depth <= max_depth; ++depth, median *= 0.5) { + int quadrant = (patches_are_triangular != 0) ? + transformUVToTriQuadrant(median, u, v, tri_rotated) : + transformUVToQuadQuadrant(median, u, v); + + if (is_leaf(node.child[quadrant])) { + return input_patch_handles[get_index(node.child[quadrant])]; + } + + node = quad_nodes[get_index(node.child[quadrant])]; + } +} + +OsdPatchCoord bogus_patch_coord(int face_index, float u, float v) +{ + OsdPatchCoord coord; + coord.arrayIndex = 0; + coord.patchIndex = face_index; + coord.vertIndex = 0; + coord.s = u; + coord.t = v; + return coord; +} + +OsdPatchCoord GetPatchCoord(int face_index, float u, float v) +{ + PatchHandle patch_handle = find_patch(face_index, u, v); + + if (patch_handle.array_index == -1) { + return bogus_patch_coord(face_index, u, v); + } + + OsdPatchCoord coord; + coord.arrayIndex = patch_handle.array_index; + coord.patchIndex = patch_handle.patch_index; + coord.vertIndex = patch_handle.vertex_index; + coord.s = u; + coord.t = v; + return coord; +} + +/* ------------------------------------------------------------------------------ + * Patch evaluation. Note that the 1st and 2nd derivatives are always computed, although we + * only return and use the 1st derivatives if adaptive patches are used. This could + * perhaps be optimized. + */ + +#if defined(FVAR_EVALUATION) +void evaluate_patches_limits(int patch_index, float u, float v, inout vec2 dst) +{ + OsdPatchCoord coord = GetPatchCoord(patch_index, u, v); + OsdPatchArray array = GetPatchArray(coord.arrayIndex); + OsdPatchParam param = GetPatchParam(coord.patchIndex); + + int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc; + + float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20]; + int nPoints = OsdEvaluatePatchBasis( + patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv); + + int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase); + + for (int cv = 0; cv < nPoints; ++cv) { + int index = patchIndexBuffer[indexBase + cv]; + vec2 src_fvar = read_vec2(src_offset + index); + dst += src_fvar * wP[cv]; + } +} +#else +void evaluate_patches_limits( + int patch_index, float u, float v, inout vec3 dst, inout vec3 du, inout vec3 dv) +{ + OsdPatchCoord coord = GetPatchCoord(patch_index, u, v); + OsdPatchArray array = GetPatchArray(coord.arrayIndex); + OsdPatchParam param = GetPatchParam(coord.patchIndex); + + int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc; + + float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20]; + int nPoints = OsdEvaluatePatchBasis( + patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv); + + int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase); + + for (int cv = 0; cv < nPoints; ++cv) { + int index = patchIndexBuffer[indexBase + cv]; + vec3 src_vertex = read_vec3(index); + + dst += src_vertex * wP[cv]; + du += src_vertex * wDu[cv]; + dv += src_vertex * wDv[cv]; + } +} +#endif + +/* ------------------------------------------------------------------------------ + * Entry point. + */ + +#if defined(FVAR_EVALUATION) +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint start_loop_index = quad_index * 4; + + for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) { + vec2 fvar = vec2(0.0); + + BlenderPatchCoord patch_co = patch_coords[loop_index]; + vec2 uv = decode_uv(patch_co.encoded_uv); + + evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, fvar); + output_fvar[dst_offset + loop_index] = fvar; + } +} +#elif defined(FDOTS_EVALUATION) +bool is_face_selected(uint coarse_quad_index) +{ + return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0; +} + +bool is_face_active(uint coarse_quad_index) +{ + return (extra_coarse_face_data[coarse_quad_index] & coarse_face_active_mask) != 0; +} + +float get_face_flag(uint coarse_quad_index) +{ + if (is_face_active(coarse_quad_index)) { + return -1.0; + } + + if (is_face_selected(coarse_quad_index)) { + return 1.0; + } + + return 0.0; +} + +void main() +{ + /* We execute for each coarse quad. */ + uint coarse_quad_index = get_global_invocation_index(); + if (coarse_quad_index >= total_dispatch_size) { + return; + } + + BlenderPatchCoord patch_co = patch_coords[coarse_quad_index]; + vec2 uv = decode_uv(patch_co.encoded_uv); + + vec3 pos = vec3(0.0); + vec3 du = vec3(0.0); + vec3 dv = vec3(0.0); + evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv); + vec3 nor = normalize(cross(du, dv)); + + FDotVert vert; + vert.x = pos.x; + vert.y = pos.y; + vert.z = pos.z; + + FDotNor fnor; + fnor.x = nor.x; + fnor.y = nor.y; + fnor.z = nor.z; + fnor.flag = get_face_flag(coarse_quad_index); + + output_verts[coarse_quad_index] = vert; + output_nors[coarse_quad_index] = fnor; + output_indices[coarse_quad_index] = coarse_quad_index; +} +#else +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint start_loop_index = quad_index * 4; + + for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) { + vec3 pos = vec3(0.0); + vec3 du = vec3(0.0); + vec3 dv = vec3(0.0); + + BlenderPatchCoord patch_co = patch_coords[loop_index]; + vec2 uv = decode_uv(patch_co.encoded_uv); + + evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv); + +# if defined(LIMIT_NORMALS) + vec3 nor = normalize(cross(du, dv)); +# else + /* This will be computed later. */ + vec3 nor = vec3(0.0); +# endif + + int origindex = input_vert_origindex[loop_index]; + uint flag = 0; + if (origindex == -1) { + flag = -1; + } + + PosNorLoop vertex_data; + set_vertex_pos(vertex_data, pos); + set_vertex_nor(vertex_data, nor, flag); + output_verts[loop_index] = vertex_data; + } +} +#endif |