diff options
Diffstat (limited to 'source/blender/draw/intern/shaders')
29 files changed, 2141 insertions, 60 deletions
diff --git a/source/blender/draw/intern/shaders/common_debug_lib.glsl b/source/blender/draw/intern/shaders/common_debug_lib.glsl new file mode 100644 index 00000000000..396bbb759ec --- /dev/null +++ b/source/blender/draw/intern/shaders/common_debug_lib.glsl @@ -0,0 +1,131 @@ + +/** + * Debugging drawing library + * + * Quick way to draw debug geometry. All input should be in world space and + * will be rendered in the default view. No additional setup required. + **/ +#define DEBUG_DRAW + +/* Keep in sync with buffer creation. */ +#define DEBUG_VERT_MAX 16 * 4096 + +struct DebugVert { + vec3 pos; + uint color; +}; + +layout(std430, binding = 7) restrict buffer debugBuf +{ + /** Start the buffer with a degenerate vertice. */ + uint _pad0; + uint _pad1; + uint _pad2; + uint v_count; + DebugVert verts[]; +} +drw_debug_verts; + +bool drw_debug_draw_enable = true; + +uint drw_debug_color_pack(vec4 color) +{ + color = clamp(color, 0.0, 1.0); + uint result = 0; + result |= uint(color.x * 255.0) << 0u; + result |= uint(color.y * 255.0) << 8u; + result |= uint(color.z * 255.0) << 16u; + result |= uint(color.w * 255.0) << 24u; + return result; +} + +void drw_debug_line_do(inout uint vertid, vec3 v1, vec3 v2, uint color) +{ + drw_debug_verts.verts[vertid++] = DebugVert(v1, color); + drw_debug_verts.verts[vertid++] = DebugVert(v2, color); +} + +void drw_debug_line(vec3 v1, vec3 v2, vec4 color) +{ + if (!drw_debug_draw_enable) { + return; + } + const uint vneeded = 2; + uint vertid = atomicAdd(drw_debug_verts.v_count, vneeded); + if (vertid + vneeded < DEBUG_VERT_MAX + 1) { + drw_debug_line_do(vertid, v1, v2, drw_debug_color_pack(color)); + } +} + +void drw_debug_quad(vec3 v1, vec3 v2, vec3 v3, vec3 v4, vec4 color) +{ + if (!drw_debug_draw_enable) { + return; + } + const uint vneeded = 8; + uint vertid = atomicAdd(drw_debug_verts.v_count, vneeded); + if (vertid + vneeded < DEBUG_VERT_MAX + 1) { + uint pcolor = drw_debug_color_pack(color); + drw_debug_line_do(vertid, v1, v2, pcolor); + drw_debug_line_do(vertid, v2, v3, pcolor); + drw_debug_line_do(vertid, v3, v4, pcolor); + drw_debug_line_do(vertid, v4, v1, pcolor); + } +} + +/* Draw an octahedron. */ +void drw_debug_point(vec3 p, float radius, vec4 color) +{ + if (!drw_debug_draw_enable) { + return; + } + vec3 c = vec3(radius, -radius, 0); + vec3 v1 = p + c.xzz; + vec3 v2 = p + c.zxz; + vec3 v3 = p + c.yzz; + vec3 v4 = p + c.zyz; + vec3 v5 = p + c.zzx; + vec3 v6 = p + c.zzy; + + const uint vneeded = 12 * 2; + uint vertid = atomicAdd(drw_debug_verts.v_count, vneeded); + if (vertid + vneeded < DEBUG_VERT_MAX + 1) { + uint pcolor = drw_debug_color_pack(color); + drw_debug_line_do(vertid, v1, v2, pcolor); + drw_debug_line_do(vertid, v2, v3, pcolor); + drw_debug_line_do(vertid, v3, v4, pcolor); + drw_debug_line_do(vertid, v4, v1, pcolor); + drw_debug_line_do(vertid, v1, v5, pcolor); + drw_debug_line_do(vertid, v2, v5, pcolor); + drw_debug_line_do(vertid, v3, v5, pcolor); + drw_debug_line_do(vertid, v4, v5, pcolor); + drw_debug_line_do(vertid, v1, v6, pcolor); + drw_debug_line_do(vertid, v2, v6, pcolor); + drw_debug_line_do(vertid, v3, v6, pcolor); + drw_debug_line_do(vertid, v4, v6, pcolor); + } +} + +void drw_debug_matrix(mat4 mat, vec4 color, const bool do_project) +{ + vec4 p[8] = vec4[8](vec4(-1, -1, -1, 1), + vec4(1, -1, -1, 1), + vec4(1, 1, -1, 1), + vec4(-1, 1, -1, 1), + vec4(-1, -1, 1, 1), + vec4(1, -1, 1, 1), + vec4(1, 1, 1, 1), + vec4(-1, 1, 1, 1)); + for (int i = 0; i < 8; i++) { + p[i] = mat * p[i]; + if (do_project) { + p[i].xyz /= p[i].w; + } + } + drw_debug_quad(p[0].xyz, p[1].xyz, p[2].xyz, p[3].xyz, color); + drw_debug_line(p[0].xyz, p[4].xyz, color); + drw_debug_line(p[1].xyz, p[5].xyz, color); + drw_debug_line(p[2].xyz, p[6].xyz, color); + drw_debug_line(p[3].xyz, p[7].xyz, color); + drw_debug_quad(p[4].xyz, p[5].xyz, p[6].xyz, p[7].xyz, color); +} diff --git a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl index 8a7fb97d98c..53ec38fea0b 100644 --- a/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl +++ b/source/blender/draw/intern/shaders/common_fullscreen_vert.glsl @@ -1,5 +1,7 @@ +#ifndef USE_GPU_SHADER_CREATE_INFO out vec4 uvcoordsvar; +#endif void main() { diff --git a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl index 0ecfc397e95..bf59972fbaa 100644 --- a/source/blender/draw/intern/shaders/common_fxaa_lib.glsl +++ b/source/blender/draw/intern/shaders/common_fxaa_lib.glsl @@ -296,7 +296,7 @@ NOTE the other tuning knobs are now in the shader function inputs! /* (#B1#) */ float FxaaLuma(vec4 rgba) { - /* note: sqrt because the sampled colors are in a linear colorspace! + /* NOTE: sqrt because the sampled colors are in a linear colorspace! * this approximates a perceptual conversion, which is good enough for the * algorithm */ return sqrt(dot(rgba.rgb, vec3(0.2126, 0.7152, 0.0722))); diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl index 3c76c8a5b28..77b34543989 100644 --- a/source/blender/draw/intern/shaders/common_globals_lib.glsl +++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl @@ -7,8 +7,6 @@ layout(std140) uniform globalsBlock vec4 colorWireEdit; vec4 colorActive; vec4 colorSelect; - vec4 colorDupliSelect; - vec4 colorDupli; vec4 colorLibrarySelect; vec4 colorLibrary; vec4 colorTransform; diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl index b25057c06b6..25e4abc5ebc 100644 --- a/source/blender/draw/intern/shaders/common_hair_lib.glsl +++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl @@ -5,6 +5,9 @@ * of data the CPU has to precompute and transfer for each update. */ +/* TODO(fclem): Keep documentation but remove the uniform declaration. */ +#ifndef USE_GPU_SHADER_CREATE_INFO + /** * hairStrandsRes: Number of points per hair strand. * 2 - no subdivision @@ -33,8 +36,6 @@ uniform int hairStrandOffset = 0; /* -- Per control points -- */ uniform samplerBuffer hairPointBuffer; /* RGBA32F */ -#define point_position xyz -#define point_time w /* Position along the hair length */ /* -- Per strands data -- */ uniform usamplerBuffer hairStrandBuffer; /* R32UI */ @@ -43,6 +44,10 @@ uniform usamplerBuffer hairStrandSegBuffer; /* R16UI */ /* Not used, use one buffer per uv layer */ // uniform samplerBuffer hairUVBuffer; /* RG32F */ // uniform samplerBuffer hairColBuffer; /* RGBA16 linear color */ +#endif + +#define point_position xyz +#define point_time w /* Position along the hair length */ /* -- Subdivision stage -- */ /** diff --git a/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl b/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl index 4dcde4b0245..6a3a7815cdc 100644 --- a/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl +++ b/source/blender/draw/intern/shaders/common_hair_refine_comp.glsl @@ -1,4 +1,6 @@ +#pragma BLENDER_REQUIRE(common_hair_lib.glsl) +#ifndef USE_GPU_SHADER_CREATE_INFO /* * To be compiled with common_hair_lib.glsl. */ @@ -9,6 +11,7 @@ layout(std430, binding = 0) writeonly buffer hairPointOutputBuffer vec4 posTime[]; } out_vertbuf; +#endif void main(void) { @@ -20,5 +23,5 @@ void main(void) vec4 result = hair_interp_data(data0, data1, data2, data3, weights); uint index = uint(hair_get_id() * hairStrandsRes) + gl_GlobalInvocationID.y; - out_vertbuf.posTime[index] = result; + posTime[index] = result; } diff --git a/source/blender/draw/intern/shaders/common_intersection_lib.glsl b/source/blender/draw/intern/shaders/common_intersection_lib.glsl new file mode 100644 index 00000000000..c8a97808247 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_intersection_lib.glsl @@ -0,0 +1,209 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) + +/** Require/include common_debug_lib.glsl before this file to debug draw intersections volumes. */ + +#if defined(DEBUG_DRAW_ISECT) && !defined(DEBUG_DRAW) +# error "You must include common_debug_lib.glsl before this file to enabled debug draw" +#endif + +/* ---------------------------------------------------------------------- */ +/** \name Plane extraction functions. + * \{ */ + +/** \a v1 and \a v2 are vectors on the plane. \a p is a point on the plane. */ +vec4 plane_setup(vec3 p, vec3 v1, vec3 v2) +{ + vec3 normal_to_plane = normalize(cross(v1, v2)); + return vec4(normal_to_plane, -dot(normal_to_plane, p)); +} + +void planes_setup(Pyramid shape, out vec4 planes[5]) +{ + vec3 A1 = shape.corners[1] - shape.corners[0]; + vec3 A2 = shape.corners[2] - shape.corners[0]; + vec3 A3 = shape.corners[3] - shape.corners[0]; + vec3 A4 = shape.corners[4] - shape.corners[0]; + vec3 S1 = shape.corners[4] - shape.corners[1]; + vec3 S2 = shape.corners[2] - shape.corners[1]; + + planes[0] = plane_setup(shape.corners[0], A2, A1); + planes[1] = plane_setup(shape.corners[0], A3, A2); + planes[2] = plane_setup(shape.corners[0], A4, A3); + planes[3] = plane_setup(shape.corners[0], A1, A4); + planes[4] = plane_setup(shape.corners[1], S2, S1); +} + +void planes_setup(Box shape, out vec4 planes[6]) +{ + vec3 A1 = shape.corners[1] - shape.corners[0]; + vec3 A3 = shape.corners[3] - shape.corners[0]; + vec3 A4 = shape.corners[4] - shape.corners[0]; + + planes[0] = plane_setup(shape.corners[0], A1, A3); + planes[1] = plane_setup(shape.corners[0], A3, A4); + planes[2] = plane_setup(shape.corners[0], A4, A1); + planes[3] = vec4(-planes[0].xyz, -dot(-planes[0].xyz, shape.corners[6])); + planes[4] = vec4(-planes[1].xyz, -dot(-planes[1].xyz, shape.corners[6])); + planes[5] = vec4(-planes[2].xyz, -dot(-planes[2].xyz, shape.corners[6])); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Intersection functions. + * \{ */ + +#define TEST_ENABLED 1 +#define FALSE_POSITIVE_REJECTION 1 + +bool intersect_view(Pyramid pyramid) +{ + /** + * Frustum vs. Pyramid test from + * https://www.yosoygames.com.ar/wp/2016/12/frustum-vs-pyramid-intersection-also-frustum-vs-frustum/ + */ + bool intersects = true; + + /* Do Pyramid vertices vs Frustum planes. */ + for (int p = 0; p < 6 && intersects; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 5 && !is_any_vertex_on_positive_side; ++v) { + if (dot(frustum_planes[p], vec4(pyramid.corners[v], 1.0)) > 0.0) { + is_any_vertex_on_positive_side = true; + } + } + if (!is_any_vertex_on_positive_side) { + intersects = false; + } + } + + if (intersects) { + vec4 pyramid_planes[5]; + planes_setup(pyramid, pyramid_planes); + /* Now do Frustum vertices vs Pyramid planes. */ + for (int p = 0; p < 5 && intersects; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8 && !is_any_vertex_on_positive_side; ++v) { + if (dot(pyramid_planes[p], vec4(frustum_corners[v], 1.0)) > 0.0) { + is_any_vertex_on_positive_side = true; + } + } + if (!is_any_vertex_on_positive_side) { + intersects = false; + } + } + } + +#if defined(DEBUG_DRAW) && defined(DEBUG_DRAW_ISECT) + drw_debug(pyramid, intersects ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1)); +#endif + return intersects; +} + +bool intersect_view(Box box) +{ + bool intersects = true; + + /* Do Box vertices vs Frustum planes. */ + for (int p = 0; p < 6 && intersects; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8 && !is_any_vertex_on_positive_side; ++v) { + if (dot(frustum_planes[p], vec4(box.corners[v], 1.0)) > 0.0) { + is_any_vertex_on_positive_side = true; + } + } + if (!is_any_vertex_on_positive_side) { + intersects = false; + } + } + + if (intersects) { + vec4 box_planes[6]; + planes_setup(box, box_planes); + /* Now do Frustum vertices vs Box planes. */ + for (int p = 0; p < 6 && intersects; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8 && !is_any_vertex_on_positive_side; ++v) { + if (dot(box_planes[p], vec4(frustum_corners[v], 1.0)) > 0.0) { + is_any_vertex_on_positive_side = true; + } + } + if (!is_any_vertex_on_positive_side) { + intersects = false; + } + } + } + +#if defined(DEBUG_DRAW) && defined(DEBUG_DRAW_ISECT) + if (intersects) { + drw_debug(box, intersects ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1)); + } +#endif + return intersects; +} + +bool intersect_view(Sphere sph) +{ + bool intersects = true; + + for (int p = 0; p < 6 && intersects; ++p) { + float dist_to_plane = dot(frustum_planes[p], vec4(sph.center, 1.0)); + if (dist_to_plane < -sph.radius) { + intersects = false; + } + } + + /* TODO reject false positive. */ + +#if defined(DEBUG_DRAW) && defined(DEBUG_DRAW_ISECT) + if (intersects) { + drw_debug(sph, intersects ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1)); + } +#endif + return intersects; +} + +bool intersect(Pyramid pyramid, Box box) +{ + bool intersects = true; + + vec4 box_planes[6]; + planes_setup(box, box_planes); + /* Do Pyramid vertices vs Box planes. */ + for (int p = 0; p < 6 && intersects; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 5 && !is_any_vertex_on_positive_side; ++v) { + if (dot(box_planes[p], vec4(pyramid.corners[v], 1.0)) > 0.0) { + is_any_vertex_on_positive_side = true; + } + } + if (!is_any_vertex_on_positive_side) { + intersects = false; + } + } + + if (intersects) { + vec4 pyramid_planes[5]; + planes_setup(pyramid, pyramid_planes); + /* Now do Box vertices vs Pyramid planes. */ + for (int p = 0; p < 5 && intersects; ++p) { + bool is_any_vertex_on_positive_side = false; + for (int v = 0; v < 8 && !is_any_vertex_on_positive_side; ++v) { + if (dot(pyramid_planes[p], vec4(box.corners[v], 1.0)) > 0.0) { + is_any_vertex_on_positive_side = true; + } + } + if (!is_any_vertex_on_positive_side) { + intersects = false; + } + } + } + return intersects; +} + +#undef TEST_ENABLED +#undef FALSE_POSITIVE_REJECTION + +/** \} */ diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl index fa2e32f6363..6c6ee599168 100644 --- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl @@ -108,7 +108,7 @@ void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B) * Using Method #4: Spheremap Transform */ vec2 normal_encode(vec3 n) { - float p = sqrt(n.z * 8.0 + 8.0); + float p = safe_sqrt(n.z * 8.0 + 8.0); return n.xy / p + 0.5; } @@ -116,7 +116,7 @@ vec3 normal_decode(vec2 enc) { vec2 fenc = enc * 4.0 - 2.0; float f = dot(fenc, fenc); - float g = sqrt(1.0 - f / 4.0); + float g = safe_sqrt(1.0 - f / 4.0); vec3 n; n.xy = fenc * g; n.z = 1 - f / 2; @@ -134,3 +134,114 @@ vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B) } /** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Shapes + * \{ */ + +struct Sphere { + vec3 center; + float radius; +}; + +struct Box { + vec3 corners[8]; +}; + +struct Pyramid { + /* Apex is the first. Base vertices are in clockwise order from front view. */ + vec3 corners[5]; +}; + +#if defined(DEBUG_DRAW) + +void drw_debug(Box shape, vec4 color) +{ + drw_debug_quad(shape.corners[0], shape.corners[1], shape.corners[2], shape.corners[3], color); + drw_debug_line(shape.corners[0], shape.corners[4], color); + drw_debug_line(shape.corners[1], shape.corners[5], color); + drw_debug_line(shape.corners[2], shape.corners[6], color); + drw_debug_line(shape.corners[3], shape.corners[7], color); + drw_debug_quad(shape.corners[4], shape.corners[5], shape.corners[6], shape.corners[7], color); +} + +void drw_debug(Pyramid shape, vec4 color) +{ + drw_debug_line(shape.corners[0], shape.corners[1], color); + drw_debug_line(shape.corners[0], shape.corners[2], color); + drw_debug_line(shape.corners[0], shape.corners[3], color); + drw_debug_line(shape.corners[0], shape.corners[4], color); + drw_debug_quad(shape.corners[1], shape.corners[2], shape.corners[3], shape.corners[4], color); +} + +void drw_debug(Sphere shape, vec4 color) +{ + /* TODO(fclem): Counld be better. */ + drw_debug_point(shape.center, shape.radius, color); +} + +#endif + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Axis Aligned Bound Box + * \{ */ + +struct AABB { + vec3 min, max; +}; + +AABB init_min_max() +{ + AABB aabb; + aabb.min = vec3(1.0e30); + aabb.max = vec3(-1.0e30); + return aabb; +} + +void merge(inout AABB aabb, vec3 v) +{ + /* Fix for perspective where */ + aabb.min = min(aabb.min, v); + aabb.max = max(aabb.max, v); +} + +bool intersect(AABB a, AABB b) +{ + return all(greaterThanEqual(min(a.max, b.max), max(a.min, b.min))); +} + +bool intersect(AABB a, AABB b, out AABB c) +{ + bool isect = intersect(a, b); + c.min = max(a.min, b.min); + c.max = min(a.max, b.max); + return isect; +} + +Box to_box(AABB aabb) +{ + Box box; + box.corners[0] = aabb.min; + box.corners[1] = vec3(aabb.max.x, aabb.min.y, aabb.min.z); + box.corners[2] = vec3(aabb.max.x, aabb.max.y, aabb.min.z); + box.corners[3] = vec3(aabb.min.x, aabb.max.y, aabb.min.z); + box.corners[4] = vec3(aabb.min.x, aabb.min.y, aabb.max.z); + box.corners[5] = vec3(aabb.max.x, aabb.min.y, aabb.max.z); + box.corners[6] = aabb.max; + box.corners[7] = vec3(aabb.min.x, aabb.max.y, aabb.max.z); + return box; +} + +#if defined(DEBUG_DRAW) + +void drw_debug(AABB shape, vec4 color) +{ + Box box = to_box(shape); + drw_debug(box, color); +} + +#endif + +/** \} */ diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index 9e5e5b39ea7..e2941f1b049 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -104,6 +104,12 @@ float pow8(float x) { return sqr(sqr(sqr(x))); } float len_squared(vec3 a) { return dot(a, a); } float len_squared(vec2 a) { return dot(a, a); } +bool flag_test(uint flag, uint val) { return (flag & val) != 0u; } +bool flag_test(int flag, int val) { return (flag & val) != 0; } + +void set_flag_from_test(inout uint value, bool test, uint flag) { if (test) { value |= flag; } else { value &= ~flag; } } +void set_flag_from_test(inout int value, bool test, int flag) { if (test) { value |= flag; } else { value &= ~flag; } } + #define weighted_sum(val0, val1, val2, val3, weights) ((val0 * weights[0] + val1 * weights[1] + val2 * weights[2] + val3 * weights[3]) * safe_rcp(sum(weights))); #define weighted_sum_array(val, weights) ((val[0] * weights[0] + val[1] * weights[1] + val[2] * weights[2] + val[3] * weights[3]) * safe_rcp(sum(weights))); @@ -111,6 +117,38 @@ float len_squared(vec2 a) { return dot(a, a); } #define saturate(a) clamp(a, 0.0, 1.0) +#define in_range_inclusive(val, min_v, max_v) \ + (all(greaterThanEqual(val, min_v)) && all(lessThanEqual(val, max_v))) +#define in_range_exclusive(val, min_v, max_v) \ + (all(greaterThan(val, min_v)) && all(lessThan(val, max_v))) + +uint divide_ceil_u(uint visible_count, uint divisor) +{ + return (visible_count + (divisor - 1u)) / divisor; +} + +int divide_ceil_i(int visible_count, int divisor) +{ + return (visible_count + (divisor - 1)) / divisor; +} + +uint bit_field_mask(uint bit_width, uint bit_min) +{ + /* Cannot bit shift more than 31 positions. */ + uint mask = (bit_width > 31u) ? 0x0u : (0xFFFFFFFFu << bit_width); + return ~mask << bit_min; +} + +uvec2 unpackUvec2x16(uint data) +{ + return uvec2(data >> 16u, data & 0xFFFFu); +} + +uint packUvec2x16(uvec2 data) +{ + return (data.x << 16u) | (data.y & 0xFFFFu); +} + float distance_squared(vec2 a, vec2 b) { a -= b; @@ -216,3 +254,8 @@ vec3 heatmap_gradient(float t) smoothstep(0.5, 1.0, t), max(1.0 - t * 1.7, t * 7.0 - 6.0))); } +vec3 hue_gradient(float t) +{ + vec3 p = abs(fract(t + vec3(1.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0); + return (clamp(p - 1.0, 0.0, 1.0)); +} diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl index 74b989441a2..dd725ad327f 100644 --- a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl +++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl @@ -2,6 +2,8 @@ /* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */ #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#ifndef DRW_SHADER_SHARED_H + in vec4 pos; /* Position and radius. */ /* ---- Instanced attribs ---- */ @@ -9,6 +11,8 @@ in vec4 pos; /* Position and radius. */ in vec3 pos_inst; in vec3 nor; +#endif + mat3 pointcloud_get_facing_matrix(vec3 p) { mat3 facing_mat; @@ -18,13 +22,22 @@ mat3 pointcloud_get_facing_matrix(vec3 p) return facing_mat; } +/* Returns world center position and radius. */ +void pointcloud_get_pos_and_radius(out vec3 outpos, out float outradius) +{ + outpos = point_object_to_world(pos.xyz); + outradius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0)); +} + /* Return world position and normal. */ void pointcloud_get_pos_and_nor(out vec3 outpos, out vec3 outnor) { - vec3 p = point_object_to_world(pos.xyz); + vec3 p; + float radius; + pointcloud_get_pos_and_radius(p, radius); + mat3 facing_mat = pointcloud_get_facing_matrix(p); - float radius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0)); /* TODO(fclem): remove multiplication here. Here only for keeping the size correct for now. */ radius *= 0.01; outpos = p + (facing_mat * pos_inst) * radius; diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl index 36ffb4d8b32..73f65fb0799 100644 --- a/source/blender/draw/intern/shaders/common_smaa_lib.glsl +++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl @@ -736,9 +736,11 @@ float2 SMAALumaEdgeDetectionPS(float2 texcoord, float2 edges = step(threshold, delta.xy); # ifndef SMAA_NO_DISCARD +# ifdef GPU_FRAGMENT_SHADER // Then discard if there is no edge: if (dot(edges, float2(1.0, 1.0)) == 0.0) discard; +# endif # endif // Calculate right and bottom deltas: @@ -804,9 +806,11 @@ float2 SMAAColorEdgeDetectionPS(float2 texcoord, float2 edges = step(threshold, delta.xy); # ifndef SMAA_NO_DISCARD +# ifdef GPU_FRAGMENT_SHADER // Then discard if there is no edge: if (dot(edges, float2(1.0, 1.0)) == 0.0) discard; +# endif # endif // Calculate right and bottom deltas: @@ -851,8 +855,10 @@ float2 SMAADepthEdgeDetectionPS(float2 texcoord, float4 offset[3], SMAATexture2D float2 delta = abs(neighbours.xx - float2(neighbours.y, neighbours.z)); float2 edges = step(SMAA_DEPTH_THRESHOLD, delta); +# ifdef GPU_FRAGMENT_SHADER if (dot(edges, float2(1.0, 1.0)) == 0.0) discard; +# endif return edges; } diff --git a/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl new file mode 100644 index 00000000000..36c3970d9a0 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl @@ -0,0 +1,230 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 1) readonly restrict buffer sourceBuffer +{ +#ifdef GPU_FETCH_U16_TO_FLOAT + uint src_data[]; +#else + float src_data[]; +#endif +}; + +layout(std430, binding = 2) readonly restrict buffer facePTexOffset +{ + uint face_ptex_offset[]; +}; + +layout(std430, binding = 3) readonly restrict buffer patchCoords +{ + BlenderPatchCoord patch_coords[]; +}; + +layout(std430, binding = 4) readonly restrict buffer extraCoarseFaceData +{ + uint extra_coarse_face_data[]; +}; + +layout(std430, binding = 5) writeonly restrict buffer destBuffer +{ +#ifdef GPU_FETCH_U16_TO_FLOAT + uint dst_data[]; +#else + float dst_data[]; +#endif +}; + +struct Vertex { + float vertex_data[DIMENSIONS]; +}; + +void clear(inout Vertex v) +{ + for (int i = 0; i < DIMENSIONS; i++) { + v.vertex_data[i] = 0.0; + } +} + +Vertex read_vertex(uint index) +{ + Vertex result; +#ifdef GPU_FETCH_U16_TO_FLOAT + uint base_index = index * 2; + if (DIMENSIONS == 4) { + uint xy = src_data[base_index]; + uint zw = src_data[base_index + 1]; + + float x = float((xy >> 16) & 0xffff) / 65535.0; + float y = float(xy & 0xffff) / 65535.0; + float z = float((zw >> 16) & 0xffff) / 65535.0; + float w = float(zw & 0xffff) / 65535.0; + + result.vertex_data[0] = x; + result.vertex_data[1] = y; + result.vertex_data[2] = z; + result.vertex_data[3] = w; + } + else { + /* This case is unsupported for now. */ + clear(result); + } +#else + uint base_index = index * DIMENSIONS; + for (int i = 0; i < DIMENSIONS; i++) { + result.vertex_data[i] = src_data[base_index + i]; + } +#endif + return result; +} + +void write_vertex(uint index, Vertex v) +{ +#ifdef GPU_FETCH_U16_TO_FLOAT + uint base_index = dst_offset + index * 2; + if (DIMENSIONS == 4) { + uint x = uint(v.vertex_data[0] * 65535.0); + uint y = uint(v.vertex_data[1] * 65535.0); + uint z = uint(v.vertex_data[2] * 65535.0); + uint w = uint(v.vertex_data[3] * 65535.0); + + uint xy = x << 16 | y; + uint zw = z << 16 | w; + + dst_data[base_index] = xy; + dst_data[base_index + 1] = zw; + } + else { + /* This case is unsupported for now. */ + dst_data[base_index] = 0; + } +#else + uint base_index = dst_offset + index * DIMENSIONS; + for (int i = 0; i < DIMENSIONS; i++) { + dst_data[base_index + i] = v.vertex_data[i]; + } +#endif +} + +Vertex interp_vertex(Vertex v0, Vertex v1, Vertex v2, Vertex v3, vec2 uv) +{ + Vertex result; + for (int i = 0; i < DIMENSIONS; i++) { + float e = mix(v0.vertex_data[i], v1.vertex_data[i], uv.x); + float f = mix(v2.vertex_data[i], v3.vertex_data[i], uv.x); + result.vertex_data[i] = mix(e, f, uv.y); + } + return result; +} + +void add_with_weight(inout Vertex v0, Vertex v1, float weight) +{ + for (int i = 0; i < DIMENSIONS; i++) { + v0.vertex_data[i] += v1.vertex_data[i] * weight; + } +} + +Vertex average(Vertex v0, Vertex v1) +{ + Vertex result; + for (int i = 0; i < DIMENSIONS; i++) { + result.vertex_data[i] = (v0.vertex_data[i] + v1.vertex_data[i]) * 0.5; + } + return result; +} + +uint get_vertex_count(uint coarse_polygon) +{ + uint number_of_patches = face_ptex_offset[coarse_polygon + 1] - face_ptex_offset[coarse_polygon]; + if (number_of_patches == 1) { + /* If there is only one patch for the current coarse polygon, then it is a quad. */ + return 4; + } + /* Otherwise, the number of patches is the number of vertices. */ + return number_of_patches; +} + +uint get_polygon_corner_index(uint coarse_polygon, uint patch_index) +{ + uint patch_offset = face_ptex_offset[coarse_polygon]; + return patch_index - patch_offset; +} + +uint get_loop_start(uint coarse_polygon) +{ + return extra_coarse_face_data[coarse_polygon] & coarse_face_loopstart_mask; +} + +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; + + /* Find which coarse polygon we came from. */ + uint coarse_polygon = coarse_polygon_index_from_subdiv_quad_index(quad_index, coarse_poly_count); + uint loop_start = get_loop_start(coarse_polygon); + + /* Find the number of vertices for the coarse polygon. */ + Vertex v0, v1, v2, v3; + clear(v0); + clear(v1); + clear(v2); + clear(v3); + + uint number_of_vertices = get_vertex_count(coarse_polygon); + if (number_of_vertices == 4) { + /* Interpolate the src data. */ + v0 = read_vertex(loop_start + 0); + v1 = read_vertex(loop_start + 1); + v2 = read_vertex(loop_start + 2); + v3 = read_vertex(loop_start + 3); + } + else { + /* Interpolate the src data for the center. */ + uint loop_end = loop_start + number_of_vertices - 1; + Vertex center_value; + clear(center_value); + + float weight = 1.0 / float(number_of_vertices); + + for (uint l = loop_start; l < loop_end; l++) { + add_with_weight(center_value, read_vertex(l), weight); + } + + /* Interpolate between the previous and next corner for the middle values for the edges. */ + uint patch_index = uint(patch_coords[start_loop_index].patch_index); + uint current_coarse_corner = get_polygon_corner_index(coarse_polygon, patch_index); + uint next_coarse_corner = (current_coarse_corner + 1) % number_of_vertices; + uint prev_coarse_corner = (current_coarse_corner + number_of_vertices - 1) % + number_of_vertices; + + v0 = read_vertex(loop_start); + v1 = average(v0, read_vertex(loop_start + next_coarse_corner)); + v3 = average(v0, read_vertex(loop_start + prev_coarse_corner)); + + /* Interpolate between the current value, and the ones for the center and mid-edges. */ + v2 = center_value; + } + + /* Do a linear interpolation of the data based on the UVs for each loop of this subdivided quad. + */ + for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) { + BlenderPatchCoord co = patch_coords[loop_index]; + vec2 uv = decode_uv(co.encoded_uv); + /* NOTE: v2 and v3 are reversed to stay consistent with the interpolation weight on the x-axis: + * + * v3 +-----+ v2 + * | | + * | | + * v0 +-----+ v1 + * + * otherwise, weight would be `1.0 - uv.x` for `v2 <-> v3`, but `uv.x` for `v0 <-> v1`. + */ + Vertex result = interp_vertex(v0, v1, v3, v2, uv); + write_vertex(loop_index, result); + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl new file mode 100644 index 00000000000..f11c0f6427e --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl @@ -0,0 +1,57 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputEdgeOrigIndex +{ + int input_origindex[]; +}; + +layout(std430, binding = 1) writeonly buffer outputLinesIndices +{ + uint output_lines[]; +}; + +#ifndef LINES_LOOSE +void emit_line(uint line_offset, uint start_loop_index, uint corner_index) +{ + uint vertex_index = start_loop_index + corner_index; + + if (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display) { + output_lines[line_offset + 0] = 0xffffffff; + output_lines[line_offset + 1] = 0xffffffff; + } + else { + /* Mod 4 so we loop back at the first vertex on the last loop index (3). */ + uint next_vertex_index = start_loop_index + (corner_index + 1) % 4; + + output_lines[line_offset + 0] = vertex_index; + output_lines[line_offset + 1] = next_vertex_index; + } +} +#endif + +void main() +{ + uint index = get_global_invocation_index(); + if (index >= total_dispatch_size) { + return; + } + +#ifdef LINES_LOOSE + /* In the loose lines case, we execute for each line, with two vertices per line. */ + uint line_offset = edge_loose_offset + index * 2; + uint loop_index = num_subdiv_loops + index * 2; + output_lines[line_offset] = loop_index; + output_lines[line_offset + 1] = loop_index + 1; +#else + /* We execute for each quad, so the start index of the loop is quad_index * 4. */ + uint start_loop_index = index * 4; + /* We execute for each quad, so the start index of the line is quad_index * 8 (with 2 vertices + * per line). */ + uint start_line_index = index * 8; + + for (int i = 0; i < 4; i++) { + emit_line(start_line_index + i * 2, start_loop_index, i); + } +#endif +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl new file mode 100644 index 00000000000..3257ebdae17 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl @@ -0,0 +1,43 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +/* Generate triangles from subdivision quads indices. */ + +layout(std430, binding = 1) writeonly buffer outputTriangles +{ + uint output_tris[]; +}; + +#ifndef SINGLE_MATERIAL +layout(std430, binding = 2) readonly buffer inputPolygonMatOffset +{ + int polygon_mat_offset[]; +}; +#endif + +void main() +{ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint loop_index = quad_index * 4; + +#ifdef SINGLE_MATERIAL + uint triangle_loop_index = quad_index * 6; +#else + uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index, + coarse_poly_count); + int mat_offset = polygon_mat_offset[coarse_quad_index]; + + int triangle_loop_index = (int(quad_index) + mat_offset) * 6; +#endif + + output_tris[triangle_loop_index + 0] = loop_index + 0; + output_tris[triangle_loop_index + 1] = loop_index + 1; + output_tris[triangle_loop_index + 2] = loop_index + 2; + output_tris[triangle_loop_index + 3] = loop_index + 0; + output_tris[triangle_loop_index + 4] = loop_index + 2; + output_tris[triangle_loop_index + 5] = loop_index + 3; +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl new file mode 100644 index 00000000000..9dd86c35ee4 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl @@ -0,0 +1,176 @@ + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +/* Uniform block for #DRWSubivUboStorage. */ +layout(std140) uniform shader_data +{ + /* Offsets in the buffers data where the source and destination data start. */ + int src_offset; + int dst_offset; + + /* Parameters for the DRWPatchMap. */ + int min_patch_face; + int max_patch_face; + int max_depth; + int patches_are_triangular; + + /* Coarse topology information. */ + int coarse_poly_count; + uint edge_loose_offset; + + /* Subdiv topology information. */ + uint num_subdiv_loops; + + /* Subdivision settings. */ + bool optimal_display; + + /* Sculpt data. */ + bool has_sculpt_mask; + + /* Masks for the extra coarse face data. */ + uint coarse_face_select_mask; + uint coarse_face_smooth_mask; + uint coarse_face_active_mask; + uint coarse_face_loopstart_mask; + + /* Total number of elements to process. */ + uint total_dispatch_size; +}; + +uint get_global_invocation_index() +{ + uint invocations_per_row = gl_WorkGroupSize.x * gl_NumWorkGroups.x; + return gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * invocations_per_row; +} + +/* Structure for #CompressedPatchCoord. */ +struct BlenderPatchCoord { + int patch_index; + uint encoded_uv; +}; + +vec2 decode_uv(uint encoded_uv) +{ + float u = float((encoded_uv >> 16) & 0xFFFFu) / 65535.0; + float v = float(encoded_uv & 0xFFFFu) / 65535.0; + return vec2(u, v); +} + +/* This structure is a carbon copy of OpenSubDiv's PatchTable::PatchHandle. */ +struct PatchHandle { + int array_index; + int patch_index; + int vertex_index; +}; + +/* This structure is a carbon copy of OpenSubDiv's PatchCoord. */ +struct PatchCoord { + int array_index; + int patch_index; + int vertex_index; + float u; + float v; +}; + +/* This structure is a carbon copy of OpenSubDiv's PatchCoord.QuadNode. + * Each child is a bitfield. */ +struct QuadNode { + uvec4 child; +}; + +bool is_set(uint i) +{ + /* QuadNode.Child.isSet is the first bit of the bitfield. */ + return (i & 0x1u) != 0; +} + +bool is_leaf(uint i) +{ + /* QuadNode.Child.isLeaf is the second bit of the bitfield. */ + return (i & 0x2u) != 0; +} + +uint get_index(uint i) +{ + /* QuadNode.Child.index is made of the remaining bits. */ + return (i >> 2) & 0x3FFFFFFFu; +} + +/* Duplicate of #PosNorLoop from the mesh extract CPU code. + * We do not use a vec3 for the position as it will be padded to a vec4 which is incompatible with + * the format. */ +struct PosNorLoop { + float x, y, z; + /* TODO(kevindietrich) : figure how to compress properly as GLSL does not have char/short types, + * bit operations get tricky. */ + float nx, ny, nz; + float flag; +}; + +vec3 get_vertex_pos(PosNorLoop vertex_data) +{ + return vec3(vertex_data.x, vertex_data.y, vertex_data.z); +} + +vec3 get_vertex_nor(PosNorLoop vertex_data) +{ + return vec3(vertex_data.nx, vertex_data.ny, vertex_data.nz); +} + +void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos) +{ + vertex_data.x = pos.x; + vertex_data.y = pos.y; + vertex_data.z = pos.z; +} + +void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint flag) +{ + vertex_data.nx = nor.x; + vertex_data.ny = nor.y; + vertex_data.nz = nor.z; + vertex_data.flag = float(flag); +} + +/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the + * vertex normals when we cannot use the limit surface, in which case the flag and the normal are + * set by two separate compute pass. */ +void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor) +{ + set_vertex_nor(vertex_data, nor, 0); +} + +#define ORIGINDEX_NONE -1 + +#ifdef SUBDIV_POLYGON_OFFSET +layout(std430, binding = 0) readonly buffer inputSubdivPolygonOffset +{ + uint subdiv_polygon_offset[]; +}; + +/* Given the index of the subdivision quad, return the index of the corresponding coarse polygon. + * This uses subdiv_polygon_offset and since it is a growing list of offsets, we can use binary + * search to locate the right index. */ +uint coarse_polygon_index_from_subdiv_quad_index(uint subdiv_quad_index, uint coarse_poly_count) +{ + uint first = 0; + uint last = coarse_poly_count; + + while (first != last) { + uint middle = (first + last) / 2; + + if (subdiv_polygon_offset[middle] < subdiv_quad_index) { + first = middle + 1; + } + else { + last = middle; + } + } + + if (subdiv_polygon_offset[first] == subdiv_quad_index) { + return first; + } + + return first - 1; +} +#endif diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl new file mode 100644 index 00000000000..575090472b1 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl @@ -0,0 +1,56 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputVertexData +{ + PosNorLoop pos_nor[]; +}; + +layout(std430, binding = 1) readonly buffer faceAdjacencyOffsets +{ + uint face_adjacency_offsets[]; +}; + +layout(std430, binding = 2) readonly buffer faceAdjacencyLists +{ + uint face_adjacency_lists[]; +}; + +layout(std430, binding = 3) writeonly buffer vertexNormals +{ + vec3 normals[]; +}; + +void main() +{ + uint vertex_index = get_global_invocation_index(); + if (vertex_index >= total_dispatch_size) { + return; + } + + uint first_adjacent_face_offset = face_adjacency_offsets[vertex_index]; + uint number_of_adjacent_faces = face_adjacency_offsets[vertex_index + 1] - + first_adjacent_face_offset; + + vec3 accumulated_normal = vec3(0.0); + + /* For each adjacent face. */ + for (uint i = 0; i < number_of_adjacent_faces; i++) { + uint adjacent_face = face_adjacency_lists[first_adjacent_face_offset + i]; + uint start_loop_index = adjacent_face * 4; + + /* Compute face normal. */ + vec3 adjacent_verts[3]; + for (uint j = 0; j < 3; j++) { + adjacent_verts[j] = get_vertex_pos(pos_nor[start_loop_index + j]); + } + + vec3 face_normal = normalize( + cross(adjacent_verts[1] - adjacent_verts[0], adjacent_verts[2] - adjacent_verts[0])); + accumulated_normal += face_normal; + } + + float weight = 1.0 / float(number_of_adjacent_faces); + vec3 normal = normalize(accumulated_normal); + normals[vertex_index] = normal; +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl new file mode 100644 index 00000000000..84cd65d4161 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl @@ -0,0 +1,34 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputNormals +{ + vec3 vertex_normals[]; +}; + +layout(std430, binding = 1) readonly buffer inputSubdivVertLoopMap +{ + uint vert_loop_map[]; +}; + +layout(std430, binding = 2) buffer outputPosNor +{ + PosNorLoop pos_nor[]; +}; + +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 (int i = 0; i < 4; i++) { + uint subdiv_vert_index = vert_loop_map[start_loop_index + i]; + vec3 nor = vertex_normals[subdiv_vert_index]; + set_vertex_nor(pos_nor[start_loop_index + i], nor); + } +} 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 diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl new file mode 100644 index 00000000000..6c76cd41ca4 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl @@ -0,0 +1,97 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputVertexData +{ + PosNorLoop pos_nor[]; +}; + +layout(std430, binding = 1) readonly buffer inputEdgeIndex +{ + uint input_edge_index[]; +}; + +layout(std430, binding = 2) writeonly buffer outputEdgeFactors +{ +#ifdef GPU_AMD_DRIVER_BYTE_BUG + float output_edge_fac[]; +#else + uint output_edge_fac[]; +#endif +}; + +void write_vec4(uint index, vec4 edge_facs) +{ +#ifdef GPU_AMD_DRIVER_BYTE_BUG + for (uint i = 0; i < 4; i++) { + output_edge_fac[index + i] = edge_facs[i]; + } +#else + /* Use same scaling as in extract_edge_fac_iter_poly_mesh. */ + uint a = uint(clamp(edge_facs.x * 253.0 + 1.0, 0.0, 255.0)); + uint b = uint(clamp(edge_facs.y * 253.0 + 1.0, 0.0, 255.0)); + uint c = uint(clamp(edge_facs.z * 253.0 + 1.0, 0.0, 255.0)); + uint d = uint(clamp(edge_facs.w * 253.0 + 1.0, 0.0, 255.0)); + uint packed_edge_fac = a << 24 | b << 16 | c << 8 | d; + output_edge_fac[index] = packed_edge_fac; +#endif +} + +/* From extract_mesh_vbo_edge_fac.cc, keep in sync! */ +float loop_edge_factor_get(vec3 f_no, vec3 v_co, vec3 v_no, vec3 v_next_co) +{ + vec3 evec = v_next_co - v_co; + vec3 enor = normalize(cross(v_no, evec)); + float d = abs(dot(enor, f_no)); + /* Re-scale to the slider range. */ + d *= (1.0 / 0.065); + return clamp(d, 0.0, 1.0); +} + +float compute_line_factor(uint start_loop_index, uint corner_index, vec3 face_normal) +{ + uint vertex_index = start_loop_index + corner_index; + uint edge_index = input_edge_index[vertex_index]; + + if (edge_index == -1 && optimal_display) { + return 0.0; + } + + /* Mod 4 so we loop back at the first vertex on the last loop index (3), but only the corner + * index needs to be wrapped. */ + uint next_vertex_index = start_loop_index + (corner_index + 1) % 4; + vec3 vertex_pos = get_vertex_pos(pos_nor[vertex_index]); + vec3 vertex_nor = get_vertex_nor(pos_nor[vertex_index]); + vec3 next_vertex_pos = get_vertex_pos(pos_nor[next_vertex_index]); + return loop_edge_factor_get(face_normal, vertex_pos, vertex_nor, next_vertex_pos); +} + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + /* The start index of the loop is quad_index * 4. */ + uint start_loop_index = quad_index * 4; + + /* First compute the face normal, we need it to compute the bihedral edge angle. */ + vec3 v0 = get_vertex_pos(pos_nor[start_loop_index + 0]); + vec3 v1 = get_vertex_pos(pos_nor[start_loop_index + 1]); + vec3 v2 = get_vertex_pos(pos_nor[start_loop_index + 2]); + vec3 face_normal = normalize(cross(v1 - v0, v2 - v0)); + + vec4 edge_facs = vec4(0.0); + for (int i = 0; i < 4; i++) { + edge_facs[i] = compute_line_factor(start_loop_index, i, face_normal); + } + +#ifdef GPU_AMD_DRIVER_BYTE_BUG + write_vec4(start_loop_index, edge_facs); +#else + /* When packed into bytes, the index is the same as for the quad. */ + write_vec4(quad_index, edge_facs); +#endif +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl new file mode 100644 index 00000000000..ea73b9482d3 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl @@ -0,0 +1,80 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputVerts +{ + PosNorLoop pos_nor[]; +}; + +layout(std430, binding = 1) readonly buffer inputUVs +{ + vec2 uvs[]; +}; + +/* Mirror of #UVStretchAngle in the C++ code, but using floats until proper data compression + * is implemented for all subdivision data. */ +struct UVStretchAngle { + float angle; + float uv_angle0; + float uv_angle1; +}; + +layout(std430, binding = 2) writeonly buffer outputStretchAngles +{ + UVStretchAngle uv_stretches[]; +}; + +#define M_PI 3.1415926535897932 +#define M_1_PI 0.31830988618379067154 + +/* Adapted from BLI_math_vector.h */ +float angle_normalized_v3v3(vec3 v1, vec3 v2) +{ + /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */ + bool q = (dot(v1, v2) >= 0.0); + vec3 v = (q) ? (v1 - v2) : (v1 + v2); + float a = 2.0 * asin(length(v) / 2.0); + return (q) ? a : M_PI - a; +} + +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 i = 0; i < 4; i++) { + uint cur_loop_index = start_loop_index + i; + uint next_loop_index = start_loop_index + (i + 1) % 4; + uint prev_loop_index = start_loop_index + (i + 3) % 4; + + /* Compute 2d edge vectors from UVs. */ + vec2 cur_uv = uvs[src_offset + cur_loop_index]; + vec2 next_uv = uvs[src_offset + next_loop_index]; + vec2 prev_uv = uvs[src_offset + prev_loop_index]; + + vec2 norm_uv_edge0 = normalize(prev_uv - cur_uv); + vec2 norm_uv_edge1 = normalize(cur_uv - next_uv); + + /* Compute 3d edge vectors from positions. */ + vec3 cur_pos = get_vertex_pos(pos_nor[cur_loop_index]); + vec3 next_pos = get_vertex_pos(pos_nor[next_loop_index]); + vec3 prev_pos = get_vertex_pos(pos_nor[prev_loop_index]); + + vec3 norm_pos_edge0 = normalize(prev_pos - cur_pos); + vec3 norm_pos_edge1 = normalize(cur_pos - next_pos); + + /* Compute stretches, this logic is adapted from #edituv_get_edituv_stretch_angle. + * Keep in sync! */ + UVStretchAngle stretch; + stretch.uv_angle0 = atan(norm_uv_edge0.y, norm_uv_edge0.x) * M_1_PI; + stretch.uv_angle1 = atan(norm_uv_edge1.y, norm_uv_edge1.x) * M_1_PI; + stretch.angle = angle_normalized_v3v3(norm_pos_edge0, norm_pos_edge1) * M_1_PI; + + uv_stretches[cur_loop_index] = stretch; + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl new file mode 100644 index 00000000000..e897fb3f3c0 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl @@ -0,0 +1,31 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 1) readonly buffer inputCoarseData +{ + float coarse_stretch_area[]; +}; + +layout(std430, binding = 2) writeonly buffer outputSubdivData +{ + float subdiv_stretch_area[]; +}; + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + /* The start index of the loop is quad_index * 4. */ + uint start_loop_index = quad_index * 4; + + uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index, + coarse_poly_count); + + for (int i = 0; i < 4; i++) { + subdiv_stretch_area[start_loop_index + i] = coarse_stretch_area[coarse_quad_index]; + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl new file mode 100644 index 00000000000..41a8df3cf82 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl @@ -0,0 +1,52 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 1) readonly buffer inputVertexData +{ + PosNorLoop pos_nor[]; +}; + +layout(std430, binding = 2) readonly buffer extraCoarseFaceData +{ + uint extra_coarse_face_data[]; +}; + +layout(std430, binding = 3) writeonly buffer outputLoopNormals +{ + vec3 output_lnor[]; +}; + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + /* The start index of the loop is quad_index * 4. */ + uint start_loop_index = quad_index * 4; + + uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index, + coarse_poly_count); + + if ((extra_coarse_face_data[coarse_quad_index] & coarse_face_smooth_mask) != 0) { + /* Face is smooth, use vertex normals. */ + for (int i = 0; i < 4; i++) { + PosNorLoop pos_nor_loop = pos_nor[start_loop_index + i]; + output_lnor[start_loop_index + i] = get_vertex_nor(pos_nor_loop); + } + } + else { + /* Face is flat shaded, compute flat face normal from an inscribed triangle. */ + vec3 verts[3]; + for (int i = 0; i < 3; i++) { + verts[i] = get_vertex_pos(pos_nor[start_loop_index + i]); + } + + vec3 face_normal = normalize(cross(verts[1] - verts[0], verts[2] - verts[0])); + for (int i = 0; i < 4; i++) { + output_lnor[start_loop_index + i] = face_normal; + } + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl new file mode 100644 index 00000000000..7182ce57ad3 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl @@ -0,0 +1,47 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +struct SculptData { + uint face_set_color; + float mask; +}; + +layout(std430, binding = 0) readonly restrict buffer sculptMask +{ + float sculpt_mask[]; +}; + +layout(std430, binding = 1) readonly restrict buffer faceSetColor +{ + uint face_set_color[]; +}; + +layout(std430, binding = 2) writeonly restrict buffer sculptData +{ + SculptData sculpt_data[]; +}; + +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++) { + SculptData data; + data.face_set_color = face_set_color[loop_index]; + + if (has_sculpt_mask) { + data.mask = sculpt_mask[loop_index]; + } + else { + data.mask = 0.0; + } + + sculpt_data[loop_index] = data; + } +} diff --git a/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl b/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl new file mode 100644 index 00000000000..d55808c42d2 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_view_clipping_lib.glsl @@ -0,0 +1,33 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +#if defined(GPU_VERTEX_SHADER) || defined(GPU_GEOMETRY_SHADER) + +void view_clipping_distances(vec3 wpos) +{ +# ifdef USE_WORLD_CLIP_PLANES + vec4 pos = vec4(wpos, 1.0); + gl_ClipDistance[0] = dot(drw_view.clip_planes[0], pos); + gl_ClipDistance[1] = dot(drw_view.clip_planes[1], pos); + gl_ClipDistance[2] = dot(drw_view.clip_planes[2], pos); + gl_ClipDistance[3] = dot(drw_view.clip_planes[3], pos); + gl_ClipDistance[4] = dot(drw_view.clip_planes[4], pos); + gl_ClipDistance[5] = dot(drw_view.clip_planes[5], pos); +# endif +} + +/* Kept as define for compiler compatibility. */ +# ifdef USE_WORLD_CLIP_PLANES +# define view_clipping_distances_set(c) \ + gl_ClipDistance[0] = (c).gl_ClipDistance[0]; \ + gl_ClipDistance[1] = (c).gl_ClipDistance[1]; \ + gl_ClipDistance[2] = (c).gl_ClipDistance[2]; \ + gl_ClipDistance[3] = (c).gl_ClipDistance[3]; \ + gl_ClipDistance[4] = (c).gl_ClipDistance[4]; \ + gl_ClipDistance[5] = (c).gl_ClipDistance[5]; + +# else +# define view_clipping_distances_set(c) +# endif + +#endif diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index 1e64a43349b..573ad046ea9 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -1,5 +1,7 @@ -#define COMMON_VIEW_LIB -#define DRW_RESOURCE_CHUNK_LEN 512 +/* Temporary until we fully make the switch. */ +#ifndef DRW_SHADER_SHARED_H + +# define DRW_RESOURCE_CHUNK_LEN 512 /* keep in sync with DRWManager.view_data */ layout(std140) uniform viewBlock @@ -22,8 +24,13 @@ layout(std140) uniform viewBlock vec4 CameraTexCoFactors; vec2 ViewportSize; vec2 ViewportSizeInverse; + + vec3 frustum_corners[8]; + vec4 frustum_planes[6]; }; +#endif /* DRW_SHADER_SHARED_H */ + #define ViewNear (ViewVecs[0].w) #define ViewFar (ViewVecs[1].w) @@ -82,67 +89,96 @@ vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos) } } -uniform int resourceChunk; +/* Temporary until we fully make the switch. */ +#ifndef DRW_SHADER_SHARED_H +uniform int drw_resourceChunk; +#endif /* DRW_SHADER_SHARED_H */ #ifdef GPU_VERTEX_SHADER -# ifdef GPU_ARB_shader_draw_parameters -# define baseInstance gl_BaseInstanceARB -# else /* no ARB_shader_draw_parameters */ -uniform int baseInstance; -# endif -# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR) -/* When drawing instances of an object at the same position. */ -# define instanceId 0 -# elif defined(GPU_DEPRECATED_AMD_DRIVER) -/* A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format, - * the gl_InstanceID is incremented by the 2 bit component of the attribute. - * Ignore gl_InstanceID then. */ -# define instanceId 0 -# else -# define instanceId gl_InstanceID -# endif +/* Temporary until we fully make the switch. */ +# ifndef DRW_SHADER_SHARED_H -# ifdef UNIFORM_RESOURCE_ID -/* This is in the case we want to do a special instance drawcall but still want to have the - * right resourceId and all the correct ubo datas. */ -uniform int resourceId; -# define resource_id resourceId -# else -# define resource_id (baseInstance + instanceId) -# endif +/* clang-format off */ +# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR) || defined(DRW_LEGACY_MODEL_MATRIX) || defined(GPU_DEPRECATED_AMD_DRIVER) +/* clang-format on */ +/* When drawing instances of an object at the same position. */ +# define instanceId 0 +# else +# define instanceId gl_InstanceID +# endif + +# if defined(UNIFORM_RESOURCE_ID) +/* This is in the case we want to do a special instance drawcall for one object but still want to + * have the right resourceId and all the correct ubo datas. */ +uniform int drw_ResourceID; +# define resource_id drw_ResourceID +# else +# define resource_id (gpu_BaseInstance + instanceId) +# endif /* Use this to declare and pass the value if * the fragment shader uses the resource_id. */ -# ifdef USE_GEOMETRY_SHADER -# define RESOURCE_ID_VARYING flat out int resourceIDGeom; -# define PASS_RESOURCE_ID resourceIDGeom = resource_id; -# else -# define RESOURCE_ID_VARYING flat out int resourceIDFrag; -# define PASS_RESOURCE_ID resourceIDFrag = resource_id; +# ifdef USE_GEOMETRY_SHADER +# define RESOURCE_ID_VARYING flat out int resourceIDGeom; +# define PASS_RESOURCE_ID resourceIDGeom = resource_id; +# else +# define RESOURCE_ID_VARYING flat out int resourceIDFrag; +# define PASS_RESOURCE_ID resourceIDFrag = resource_id; +# endif + +# endif /* DRW_SHADER_SHARED_H */ + +#endif /* GPU_VERTEX_SHADER */ + +/* Temporary until we fully make the switch. */ +#ifdef DRW_SHADER_SHARED_H +/* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */ +# if defined(UNIFORM_RESOURCE_ID) +# define resource_id drw_ResourceID +# define PASS_RESOURCE_ID + +# elif defined(GPU_VERTEX_SHADER) +# define resource_id gpu_InstanceIndex +# define PASS_RESOURCE_ID drw_ResourceID_iface.resource_index = resource_id; + +# elif defined(GPU_GEOMETRY_SHADER) +# define resource_id drw_ResourceID_iface_in[0].index +# define PASS_RESOURCE_ID drw_ResourceID_iface_out.resource_index = resource_id; + +# elif defined(GPU_FRAGMENT_SHADER) +# define resource_id drw_ResourceID_iface.resource_index # endif -#endif +/* TODO(fclem): Remove. */ +# define RESOURCE_ID_VARYING + +#else /* If used in a fragment / geometry shader, we pass * resource_id as varying. */ -#ifdef GPU_GEOMETRY_SHADER -# define RESOURCE_ID_VARYING \ - flat out int resourceIDFrag; \ - flat in int resourceIDGeom[]; +# ifdef GPU_GEOMETRY_SHADER +# define RESOURCE_ID_VARYING \ + flat out int resourceIDFrag; \ + flat in int resourceIDGeom[]; -# define resource_id resourceIDGeom -# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0]; -#endif +# define resource_id resourceIDGeom +# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0]; +# endif -#ifdef GPU_FRAGMENT_SHADER +# ifdef GPU_FRAGMENT_SHADER flat in int resourceIDFrag; -# define resource_id resourceIDFrag +# define resource_id resourceIDFrag +# endif #endif /* Breaking this across multiple lines causes issues for some older GLSL compilers. */ /* clang-format off */ -#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR) +#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX) /* clang-format on */ + +/* Temporary until we fully make the switch. */ +# ifndef DRW_SHADER_SHARED_H + struct ObjectMatrices { mat4 drw_modelMatrix; mat4 drw_modelMatrixInverse; @@ -153,19 +189,28 @@ layout(std140) uniform modelBlock ObjectMatrices drw_matrices[DRW_RESOURCE_CHUNK_LEN]; }; -# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix) -# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse) +# define ModelMatrix (drw_matrices[resource_id].drw_modelMatrix) +# define ModelMatrixInverse (drw_matrices[resource_id].drw_modelMatrixInverse) +# endif /* DRW_SHADER_SHARED_H */ #else /* GPU_INTEL */ + +/* Temporary until we fully make the switch. */ +# ifndef DRW_SHADER_SHARED_H /* Intel GPU seems to suffer performance impact when the model matrix is in UBO storage. * So for now we just force using the legacy path. */ /* Note that this is also a workaround of a problem on osx (amd or nvidia) * and older amd driver on windows. */ uniform mat4 ModelMatrix; uniform mat4 ModelMatrixInverse; +# endif /* DRW_SHADER_SHARED_H */ + #endif -#define resource_handle (resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id) +/* Temporary until we fully make the switch. */ +#ifndef DRW_SHADER_SHARED_H +# define resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id) +#endif /** Transform shortcuts. */ /* Rule of thumb: Try to reuse world positions and normals because converting through viewspace @@ -181,7 +226,7 @@ uniform mat4 ModelMatrixInverse; * transpose(ViewMatrixInverse) * transpose(ModelMatrixInverse) * * Knowing that the view matrix is orthogonal, the transpose is also the inverse. - * Note: This is only valid because we are only using the mat3 of the ViewMatrixInverse. + * NOTE: This is only valid because we are only using the mat3 of the ViewMatrixInverse. * ViewMatrix * transpose(ModelMatrixInverse) */ #define NormalMatrix transpose(mat3(ModelMatrixInverse)) @@ -218,23 +263,25 @@ uniform mat4 ModelMatrixInverse; /* ---- Opengl Depth conversion ---- */ +/* Expects positive near/far values. Returns positive value. */ float linear_depth(bool is_persp, float z, float zf, float zn) { if (is_persp) { return (zn * zf) / (z * (zn - zf) + zf); } else { - return (z * 2.0 - 1.0) * zf; + return z * (zf - zn) + zn; } } +/* Expects positive near/far values. Returns positive value. */ float buffer_depth(bool is_persp, float z, float zf, float zn) { if (is_persp) { return (zf * (zn - z)) / (z * (zn - zf)); } else { - return (z / (zf * 2.0)) + 0.5; + return (z - zn) / (zf - zn); } } diff --git a/source/blender/draw/intern/shaders/draw_fullscreen_info.hh b/source/blender/draw/intern/shaders/draw_fullscreen_info.hh new file mode 100644 index 00000000000..803ad69ffb7 --- /dev/null +++ b/source/blender/draw/intern/shaders/draw_fullscreen_info.hh @@ -0,0 +1,8 @@ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_INTERFACE_INFO(fullscreen_iface, "").smooth(Type::VEC4, "uvcoordsvar"); + +GPU_SHADER_CREATE_INFO(draw_fullscreen) + .vertex_out(fullscreen_iface) + .vertex_source("common_fullscreen_vert.glsl"); diff --git a/source/blender/draw/intern/shaders/draw_hair_refine_info.hh b/source/blender/draw/intern/shaders/draw_hair_refine_info.hh new file mode 100644 index 00000000000..b41be7d8605 --- /dev/null +++ b/source/blender/draw/intern/shaders/draw_hair_refine_info.hh @@ -0,0 +1,42 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2022 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(draw_hair_refine_compute) + .local_group_size(1, 1) + .storage_buf(0, Qualifier::WRITE_ONLY, "vec4", "posTime[]") + .sampler(0, ImageType::FLOAT_BUFFER, "hairPointBuffer") + .sampler(1, ImageType::UINT_BUFFER, "hairStrandBuffer") + .sampler(2, ImageType::UINT_BUFFER, "hairStrandSegBuffer") + .push_constant(Type::VEC4, "hairDupliMatrix", 4) + .push_constant(Type::BOOL, "hairCloseTip") + .push_constant(Type::FLOAT, "hairRadShape") + .push_constant(Type::FLOAT, "hairRadTip") + .push_constant(Type::FLOAT, "hairRadRoot") + .push_constant(Type::INT, "hairThicknessRes") + .push_constant(Type::INT, "hairStrandsRes") + .push_constant(Type::INT, "hairStrandOffset") + .compute_source("common_hair_refine_comp.glsl") + .define("HAIR_PHASE_SUBDIV") + .do_static_compilation(true); diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh new file mode 100644 index 00000000000..17a32c7d5ed --- /dev/null +++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh @@ -0,0 +1,6 @@ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_CREATE_INFO(draw_object_infos) + .typedef_source("draw_shader_shared.h") + .uniform_buf(1, "ObjectInfos", "drw_infos[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH); diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh new file mode 100644 index 00000000000..0a25059ffed --- /dev/null +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -0,0 +1,105 @@ + +#include "gpu_shader_create_info.hh" + +/* -------------------------------------------------------------------- */ +/** \name Resource ID + * + * This is used to fetch per object data in drw_matrices and other object indexed + * buffers. There is multiple possibilities depending on how we are drawing the object. + * + * \{ */ + +/* Standard way. Use gpu_InstanceIndex to index the object data. */ +GPU_SHADER_CREATE_INFO(draw_resource_id).define("DYNAMIC_RESOURCE_ID"); + +/** + * Used if the resource index needs to be passed to the fragment shader. + * IMPORTANT: Vertex and Geometry shaders need to use PASS_RESOURCE_ID in main(). + */ +GPU_SHADER_INTERFACE_INFO(draw_resource_id_iface, "drw_ResourceID_iface") + .flat(Type::INT, "resource_index"); + +GPU_SHADER_CREATE_INFO(draw_resource_id_varying) + .vertex_out(draw_resource_id_iface) + .geometry_out(draw_resource_id_iface); /* Used if needed. */ + +/* Variation used when drawing multiple instances for one object. */ +GPU_SHADER_CREATE_INFO(draw_resource_id_uniform) + .define("UNIFORM_RESOURCE_ID") + .push_constant(Type::INT, "drw_ResourceID"); + +/** + * Declare a resource handle that identify a unique object. + * Requires draw_resource_id[_constant]. + */ +GPU_SHADER_CREATE_INFO(draw_resource_handle) + .define("resource_handle (drw_resourceChunk * DRW_RESOURCE_CHUNK_LEN + resource_id)") + .push_constant(Type::INT, "drw_resourceChunk"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Draw View + * \{ */ + +GPU_SHADER_CREATE_INFO(draw_view) + .uniform_buf(0, "ViewInfos", "drw_view", Frequency::PASS) + .typedef_source("draw_shader_shared.h"); + +GPU_SHADER_CREATE_INFO(draw_modelmat) + .uniform_buf(8, "ObjectMatrices", "drw_matrices[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH) + .define("ModelMatrix", "(drw_matrices[resource_id].drw_modelMatrix)") + .define("ModelMatrixInverse", "(drw_matrices[resource_id].drw_modelMatrixInverse)") + .additional_info("draw_view"); + +GPU_SHADER_CREATE_INFO(draw_modelmat_legacy) + .define("DRW_LEGACY_MODEL_MATRIX") + .push_constant(Type::MAT4, "ModelMatrix") + .push_constant(Type::MAT4, "ModelMatrixInverse") + .additional_info("draw_view"); + +GPU_SHADER_CREATE_INFO(draw_modelmat_instanced_attr) + .push_constant(Type::MAT4, "ModelMatrix") + .push_constant(Type::MAT4, "ModelMatrixInverse") + .additional_info("draw_view"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Draw View + * \{ */ + +GPU_SHADER_CREATE_INFO(drw_clipped).define("USE_WORLD_CLIP_PLANES"); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Geometry Type + * \{ */ + +GPU_SHADER_CREATE_INFO(draw_mesh).additional_info("draw_modelmat", "draw_resource_id"); + +GPU_SHADER_CREATE_INFO(draw_hair) + .sampler(15, ImageType::FLOAT_BUFFER, "hairPointBuffer") + .sampler(14, ImageType::UINT_BUFFER, "hairStrandBuffer") + .sampler(13, ImageType::UINT_BUFFER, "hairStrandSegBuffer") + /* TODO(fclem) Pack thoses into one UBO. */ + .push_constant(Type::INT, "hairStrandsRes") + .push_constant(Type::INT, "hairThicknessRes") + .push_constant(Type::FLOAT, "hairRadRoot") + .push_constant(Type::FLOAT, "hairRadTip") + .push_constant(Type::FLOAT, "hairRadShape") + .push_constant(Type::BOOL, "hairCloseTip") + .push_constant(Type::INT, "hairStrandOffset") + .push_constant(Type::VEC4, "hairDupliMatrix", 4) + .additional_info("draw_modelmat", "draw_resource_id"); + +GPU_SHADER_CREATE_INFO(draw_pointcloud) + .vertex_in(0, Type::VEC4, "pos") + .vertex_in(1, Type::VEC3, "pos_inst") + .vertex_in(2, Type::VEC3, "nor") + .additional_info("draw_modelmat_instanced_attr", "draw_resource_id_uniform"); + +GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform"); + +/** \} */ |