Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/intern/shaders')
-rw-r--r--source/blender/draw/intern/shaders/common_debug_lib.glsl131
-rw-r--r--source/blender/draw/intern/shaders/common_fullscreen_vert.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_fxaa_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_globals_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl9
-rw-r--r--source/blender/draw/intern/shaders/common_hair_refine_comp.glsl5
-rw-r--r--source/blender/draw/intern/shaders/common_intersection_lib.glsl209
-rw-r--r--source/blender/draw/intern/shaders/common_math_geom_lib.glsl115
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl43
-rw-r--r--source/blender/draw/intern/shaders/common_pointcloud_lib.glsl17
-rw-r--r--source/blender/draw/intern/shaders/common_smaa_lib.glsl6
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl230
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl57
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl43
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_lib.glsl176
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl56
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl34
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl416
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl97
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl80
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl31
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl52
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl47
-rw-r--r--source/blender/draw/intern/shaders/common_view_clipping_lib.glsl33
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl147
-rw-r--r--source/blender/draw/intern/shaders/draw_fullscreen_info.hh8
-rw-r--r--source/blender/draw/intern/shaders/draw_hair_refine_info.hh42
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh6
-rw-r--r--source/blender/draw/intern/shaders/draw_view_info.hh105
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");
+
+/** \} */