From 3035fd1c361e42420ae56e5eb9de76af04d1063f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 21 Oct 2024 16:25:24 +0200 Subject: [PATCH] GPencil: Port geometry shader to primitive expansion API This removes the need for the geometry shader and the workaround path for Metal. Note that creating 2 batches for each stroke might become a bottleneck in bigger scenes. But currently the bottleneck is always be the fill algorithm. It can be optimized further if needed. Rel #127493 Pull Request: https://projects.blender.org/blender/blender/pulls/129274 --- .../intern/grease_pencil_image_render.cc | 39 +- source/blender/gpu/CMakeLists.txt | 2 - source/blender/gpu/GPU_shader_shared.hh | 7 + .../gpu/intern/gpu_shader_create_info.cc | 3 - .../gpu_shader_gpencil_stroke_frag.glsl | 26 +- .../gpu_shader_gpencil_stroke_geom.glsl | 238 ------------ .../gpu_shader_gpencil_stroke_vert.glsl | 343 ++++++++++++++++- ...pu_shader_gpencil_stroke_vert_no_geom.glsl | 359 ------------------ .../infos/gpu_shader_gpencil_stroke_info.hh | 32 +- 9 files changed, 383 insertions(+), 666 deletions(-) delete mode 100644 source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl delete mode 100644 source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_image_render.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_image_render.cc index 59dec75d0cb..d744eef4f98 100644 --- a/source/blender/editors/grease_pencil/intern/grease_pencil_image_render.cc +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_image_render.cc @@ -302,11 +302,14 @@ static void draw_grease_pencil_stroke(const float4x4 &transform, } GPUVertFormat *format = immVertexFormat(); - const uint attr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - const uint attr_color = GPU_vertformat_attr_add( - format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + /* Format is matching shader manual load. Keep in sync with #GreasePencilStrokeData. + * Only the name of the first attribute is important. */ + const uint attr_pos = GPU_vertformat_attr_add( + format, "gp_vert_data", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); const uint attr_thickness = GPU_vertformat_attr_add( format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + const uint attr_color = GPU_vertformat_attr_add( + format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE); GPUUniformBuf *ubo = create_shader_ubo(rv3d, win_size, object, cap_start, cap_end, fill_stroke); @@ -315,7 +318,8 @@ static void draw_grease_pencil_stroke(const float4x4 &transform, /* If cyclic the curve needs one more vertex. */ const int cyclic_add = (cyclic && indices.size() > 2) ? 1 : 0; - immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, indices.size() + cyclic_add + 2); + blender::gpu::Batch *batch = immBeginBatchAtMost(GPU_PRIM_LINE_STRIP_ADJ, + indices.size() + cyclic_add + 2); auto draw_point = [&](const int point_i) { constexpr const float radius_to_pixel_factor = @@ -349,6 +353,33 @@ static void draw_grease_pencil_stroke(const float4x4 &transform, } immEnd(); + + /* Expanded drawcall. */ + GPUPrimType expand_prim_type = GPUPrimType::GPU_PRIM_TRIS; + /* Hardcoded in shader. */ + const uint expand_prim_len = 12; + /* Do not count adjacency info for start and end primitives. */ + const uint final_vert_len = ((batch->vertex_count_get() - 2) * expand_prim_len) * 3; + + if (final_vert_len > 0) { + GPU_batch_bind_as_resources(batch, batch->shader); + + /* TODO(fclem): get rid of this dummy VBO. */ + GPUVertFormat format = {0}; + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + blender::gpu::VertBuf *vbo = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(*vbo, 1); + + gpu::Batch *gpu_batch = GPU_batch_create_ex( + expand_prim_type, vbo, nullptr, GPU_BATCH_OWNS_VBO); + + GPU_batch_set_shader(gpu_batch, batch->shader); + GPU_batch_draw_advanced(gpu_batch, 0, final_vert_len, 0, 1); + + GPU_batch_discard(gpu_batch); + } + GPU_batch_discard(batch); + immUnbindProgram(); GPU_uniformbuf_free(ubo); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 382a871acdd..82bd839d3b4 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -646,9 +646,7 @@ set(GLSL_SRC shaders/material/gpu_shader_material_world_normals.glsl shaders/gpu_shader_gpencil_stroke_vert.glsl - shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl shaders/gpu_shader_gpencil_stroke_frag.glsl - shaders/gpu_shader_gpencil_stroke_geom.glsl shaders/gpu_shader_display_fallback_vert.glsl shaders/gpu_shader_display_fallback_frag.glsl diff --git a/source/blender/gpu/GPU_shader_shared.hh b/source/blender/gpu/GPU_shader_shared.hh index c46b8b58d7b..ff136fb29af 100644 --- a/source/blender/gpu/GPU_shader_shared.hh +++ b/source/blender/gpu/GPU_shader_shared.hh @@ -158,6 +158,13 @@ struct SeqContextDrawData { }; BLI_STATIC_ASSERT_ALIGN(SeqContextDrawData, 16) +struct GreasePencilStrokeData { + packed_float3 position; + float stroke_thickness; + float4 stroke_color; +}; +BLI_STATIC_ASSERT_ALIGN(GreasePencilStrokeData, 16) + enum TestStatus : uint32_t { TEST_STATUS_NONE = 0u, TEST_STATUS_PASSED = 1u, diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc index f99e94eee5f..f1d85ae5592 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.cc +++ b/source/blender/gpu/intern/gpu_shader_create_info.cc @@ -537,9 +537,6 @@ void gpu_shader_create_info_init() /* Edit UV Edges. */ overlay_edit_uv_edges = overlay_edit_uv_edges_no_geom; - /* GPencil stroke. */ - gpu_shader_gpencil_stroke = gpu_shader_gpencil_stroke_no_geom; - /* NOTE: As atomic data types can alter shader gen if native atomics are unsupported, we need * to use differing create info's to handle the tile optimized check. This does prevent * the shadow techniques from being dynamically switchable. */ diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl index f0c12ca25a7..687df1362a5 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl @@ -2,36 +2,14 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -#if defined(USE_GEOMETRY_SHADER) || defined(USE_GEOMETRY_IFACE_COLOR) -vec4 fragment_in_color() -{ - return geometry_out.mColor; -} - -vec2 fragment_in_tex_coord() -{ - return geometry_out.mTexCoord; -} -#else -vec4 fragment_in_color() -{ - return geometry_in.finalColor; -} - -vec2 fragment_in_tex_coord() -{ - return vec2(0.5); -} -#endif - void main() { const vec2 center = vec2(0, 0.5); - vec4 tColor = fragment_in_color(); + vec4 tColor = interp.mColor; /* if alpha < 0, then encap */ if (tColor.a < 0) { tColor.a = tColor.a * -1.0; - float dist = length(fragment_in_tex_coord() - center); + float dist = length(interp.mTexCoord - center); if (dist > 0.25) { discard; } diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl deleted file mode 100644 index 520b4b2b3a3..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl +++ /dev/null @@ -1,238 +0,0 @@ -/* SPDX-FileCopyrightText: 2018-2022 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#define GP_XRAY_FRONT 0 -#define GP_XRAY_3DSPACE 1 -#define GP_XRAY_BACK 2 - -#define GPENCIL_FLATCAP 1 - -/* project 3d point to 2d on screen space */ -vec2 toScreenSpace(vec4 vertex) -{ - return vec2(vertex.xy / vertex.w) * gpencil_stroke_data.viewport; -} - -/* Get Z-depth value. */ -float getZdepth(vec4 point) -{ - if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) { - return 0.0; - } - if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) { - return (point.z / point.w); - } - if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) { - return 1.0; - } - - /* in front by default */ - return 0.0; -} - -/* check equality but with a small tolerance */ -bool is_equal(vec4 p1, vec4 p2) -{ - float limit = 0.0001; - float x = abs(p1.x - p2.x); - float y = abs(p1.y - p2.y); - float z = abs(p1.z - p2.z); - - if ((x < limit) && (y < limit) && (z < limit)) { - return true; - } - - return false; -} - -void main(void) -{ - float MiterLimit = 0.75; - - /* receive 4 points */ - vec4 P0 = gl_in[0].gl_Position; - vec4 P1 = gl_in[1].gl_Position; - vec4 P2 = gl_in[2].gl_Position; - vec4 P3 = gl_in[3].gl_Position; - - /* get the four vertices passed to the shader */ - vec2 sp0 = toScreenSpace(P0); /* start of previous segment */ - vec2 sp1 = toScreenSpace(P1); /* end of previous segment, start of current segment */ - vec2 sp2 = toScreenSpace(P2); /* end of current segment, start of next segment */ - vec2 sp3 = toScreenSpace(P3); /* end of next segment */ - - /* culling outside viewport */ - vec2 area = gpencil_stroke_data.viewport * 4.0; - if (sp1.x < -area.x || sp1.x > area.x) { - return; - } - if (sp1.y < -area.y || sp1.y > area.y) { - return; - } - if (sp2.x < -area.x || sp2.x > area.x) { - return; - } - if (sp2.y < -area.y || sp2.y > area.y) { - return; - } - - /* determine the direction of each of the 3 segments (previous, current, next) */ - vec2 v0 = normalize(sp1 - sp0); - vec2 v1 = normalize(sp2 - sp1); - vec2 v2 = normalize(sp3 - sp2); - - /* determine the normal of each of the 3 segments (previous, current, next) */ - vec2 n0 = vec2(-v0.y, v0.x); - vec2 n1 = vec2(-v1.y, v1.x); - vec2 n2 = vec2(-v2.y, v2.x); - - /* determine miter lines by averaging the normals of the 2 segments */ - vec2 miter_a = normalize(n0 + n1); /* miter at start of current segment */ - vec2 miter_b = normalize(n1 + n2); /* miter at end of current segment */ - - /* determine the length of the miter by projecting it onto normal and then inverse it */ - float an1 = dot(miter_a, n1); - float bn1 = dot(miter_b, n2); - if (an1 == 0) { - an1 = 1; - } - if (bn1 == 0) { - bn1 = 1; - } - float length_a = geometry_in[1].finalThickness / an1; - float length_b = geometry_in[2].finalThickness / bn1; - if (length_a <= 0.0) { - length_a = 0.01; - } - if (length_b <= 0.0) { - length_b = 0.01; - } - - /* prevent excessively long miters at sharp corners */ - if (dot(v0, v1) < -MiterLimit) { - miter_a = n1; - length_a = geometry_in[1].finalThickness; - - /* close the gap */ - if (dot(v0, n1) > 0) { - geometry_out.mTexCoord = vec2(0, 0); - geometry_out.mColor = geometry_in[1].finalColor; - gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport, - getZdepth(P1), - 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 0); - geometry_out.mColor = geometry_in[1].finalColor; - gl_Position = vec4((sp1 + geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport, - getZdepth(P1), - 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 0.5); - geometry_out.mColor = geometry_in[1].finalColor; - gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - gpu_EmitVertex(); - - EndPrimitive(); - } - else { - geometry_out.mTexCoord = vec2(0, 1); - geometry_out.mColor = geometry_in[1].finalColor; - gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n1) / gpencil_stroke_data.viewport, - getZdepth(P1), - 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 1); - geometry_out.mColor = geometry_in[1].finalColor; - gl_Position = vec4((sp1 - geometry_in[1].finalThickness * n0) / gpencil_stroke_data.viewport, - getZdepth(P1), - 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 0.5); - geometry_out.mColor = geometry_in[1].finalColor; - gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - gpu_EmitVertex(); - - EndPrimitive(); - } - } - - if (dot(v1, v2) < -MiterLimit) { - miter_b = n1; - length_b = geometry_in[2].finalThickness; - } - - /* Generate the start end-cap (alpha < 0 used as end-cap flag). */ - float extend = gpencil_stroke_data.fill_stroke ? 2 : 1; - if ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) { - geometry_out.mTexCoord = vec2(1, 0.5); - geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0); - vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend; - gl_Position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 0); - geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0); - gl_Position = vec4( - (sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 1); - geometry_out.mColor = vec4(geometry_in[1].finalColor.rgb, geometry_in[1].finalColor.a * -1.0); - gl_Position = vec4( - (sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - gpu_EmitVertex(); - } - - /* generate the triangle strip */ - geometry_out.mTexCoord = vec2(0, 0); - geometry_out.mColor = geometry_in[1].finalColor; - gl_Position = vec4( - (sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 1); - geometry_out.mColor = geometry_in[1].finalColor; - gl_Position = vec4( - (sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 0); - geometry_out.mColor = geometry_in[2].finalColor; - gl_Position = vec4( - (sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 1); - geometry_out.mColor = geometry_in[2].finalColor; - gl_Position = vec4( - (sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - gpu_EmitVertex(); - - /* Generate the end end-cap (alpha < 0 used as end-cap flag). */ - if ((gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) { - geometry_out.mTexCoord = vec2(0, 1); - geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0); - gl_Position = vec4( - (sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(0, 0); - geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0); - gl_Position = vec4( - (sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - gpu_EmitVertex(); - - geometry_out.mTexCoord = vec2(1, 0.5); - geometry_out.mColor = vec4(geometry_in[2].finalColor.rgb, geometry_in[2].finalColor.a * -1.0); - vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend; - gl_Position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - gpu_EmitVertex(); - } - - EndPrimitive(); -} diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl index ead2f57ec99..b81f5d72068 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl @@ -2,19 +2,346 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ -float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor); +#include "gpu_shader_attribute_load_lib.glsl" +#include "gpu_shader_math_base_lib.glsl" +#include "gpu_shader_utildefines_lib.glsl" -void main(void) +#define GP_XRAY_FRONT 0 +#define GP_XRAY_3DSPACE 1 +#define GP_XRAY_BACK 2 + +#define GPENCIL_FLATCAP 1 + +/* project 3d point to 2d on screen space */ +vec2 toScreenSpace(vec4 vert) { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0); - geometry_in.finalColor = color; + return vec2(vert.xy / vert.w) * gpencil_stroke_data.viewport; +} + +/* Get Z-depth value. */ +float getZdepth(vec4 point) +{ + if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) { + return 0.0; + } + if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) { + return (point.z / point.w); + } + if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) { + return 1.0; + } + + /* in front by default */ + return 0.0; +} + +/* check equality but with a small tolerance */ +bool is_equal(vec4 p1, vec4 p2) +{ + float limit = 0.0001; + float x = abs(p1.x - p2.x); + float y = abs(p1.y - p2.y); + float z = abs(p1.z - p2.z); + + if ((x < limit) && (y < limit) && (z < limit)) { + return true; + } + + return false; +} + +GreasePencilStrokeData input_assembly(uint in_vertex_id) +{ + /* Assume no index buffer. */ + return gp_vert_data[in_vertex_id]; +} + +struct VertOut { + vec4 gpu_position; + vec4 final_color; + float final_thickness; +}; + +VertOut vertex_main(GreasePencilStrokeData vert_in) +{ + float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor); + + VertOut vert_out; + vert_out.gpu_position = ModelViewProjectionMatrix * vec4(vert_in.position, 1.0); + vert_out.final_color = vert_in.stroke_color; if (gpencil_stroke_data.keep_size) { - geometry_in.finalThickness = thickness; + vert_out.final_thickness = vert_in.stroke_thickness; } else { - float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) : - (thickness / defaultpixsize); - geometry_in.finalThickness = max(size * gpencil_stroke_data.objscale, 1.0); + float size = (ProjectionMatrix[3][3] == 0.0) ? + (vert_in.stroke_thickness / (vert_out.gpu_position.z * defaultpixsize)) : + (vert_in.stroke_thickness / defaultpixsize); + vert_out.final_thickness = max(size * gpencil_stroke_data.objscale, 1.0); + } + return vert_out; +} + +struct GeomOut { + vec4 gpu_position; + vec2 tex_coord; + vec4 final_color; +}; + +void export_vertex(GeomOut geom_out) +{ + gl_Position = geom_out.gpu_position; + interp.mTexCoord = geom_out.tex_coord; + interp.mColor = geom_out.final_color; +} + +void strip_EmitVertex(const uint strip_index, + uint out_vertex_id, + uint out_primitive_id, + GeomOut geom_out) +{ + bool is_odd_primitive = (out_primitive_id & 1u) != 0u; + /* Maps triangle list primitives to triangle strip indices. */ + uint out_strip_index = (is_odd_primitive ? (2u - out_vertex_id) : out_vertex_id) + + out_primitive_id; + + if (out_strip_index == strip_index) { + export_vertex(geom_out); } } + +void geometry_main(VertOut geom_in[4], + uint out_vertex_id, + uint out_primitive_id, + uint out_invocation_id) +{ + const float MiterLimit = 0.75; + + vec4 P0 = geom_in[0].gpu_position; + vec4 P1 = geom_in[1].gpu_position; + vec4 P2 = geom_in[2].gpu_position; + vec4 P3 = geom_in[3].gpu_position; + + /* Get the four vertices passed to the shader. */ + vec2 sp0 = toScreenSpace(P0); /* start of previous segment */ + vec2 sp1 = toScreenSpace(P1); /* end of previous segment, start of current segment */ + vec2 sp2 = toScreenSpace(P2); /* end of current segment, start of next segment */ + vec2 sp3 = toScreenSpace(P3); /* end of next segment */ + + /* Culling outside viewport. */ + vec2 area = gpencil_stroke_data.viewport * 4.0; + if (sp1.x < -area.x || sp1.x > area.x) { + return; + } + if (sp1.y < -area.y || sp1.y > area.y) { + return; + } + if (sp2.x < -area.x || sp2.x > area.x) { + return; + } + if (sp2.y < -area.y || sp2.y > area.y) { + return; + } + + /* determine the direction of each of the 3 segments (previous, current, next) */ + vec2 v0 = normalize(sp1 - sp0); + vec2 v1 = normalize(sp2 - sp1); + vec2 v2 = normalize(sp3 - sp2); + + /* determine the normal of each of the 3 segments (previous, current, next) */ + vec2 n0 = vec2(-v0.y, v0.x); + vec2 n1 = vec2(-v1.y, v1.x); + vec2 n2 = vec2(-v2.y, v2.x); + + /* determine miter lines by averaging the normals of the 2 segments */ + vec2 miter_a = normalize(n0 + n1); /* miter at start of current segment */ + vec2 miter_b = normalize(n1 + n2); /* miter at end of current segment */ + + /* determine the length of the miter by projecting it onto normal and then inverse it */ + float an1 = dot(miter_a, n1); + float bn1 = dot(miter_b, n2); + if (an1 == 0) { + an1 = 1; + } + if (bn1 == 0) { + bn1 = 1; + } + float length_a = geom_in[1].final_thickness / an1; + float length_b = geom_in[2].final_thickness / bn1; + if (length_a <= 0.0) { + length_a = 0.01; + } + if (length_b <= 0.0) { + length_b = 0.01; + } + + GeomOut geom_out; + + /* prevent excessively long miters at sharp corners */ + if (dot(v0, v1) < -MiterLimit) { + miter_a = n1; + length_a = geom_in[1].final_thickness; + + /* close the gap */ + if (dot(v0, n1) > 0) { + geom_out.tex_coord = vec2(0, 0); + geom_out.final_color = geom_in[1].final_color; + geom_out.gpu_position = vec4((sp1 + geom_in[1].final_thickness * n0) / + gpencil_stroke_data.viewport, + getZdepth(P1), + 1.0); + strip_EmitVertex(0, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 0); + geom_out.final_color = geom_in[1].final_color; + geom_out.gpu_position = vec4((sp1 + geom_in[1].final_thickness * n1) / + gpencil_stroke_data.viewport, + getZdepth(P1), + 1.0); + strip_EmitVertex(1, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 0.5); + geom_out.final_color = geom_in[1].final_color; + geom_out.gpu_position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); + strip_EmitVertex(2, out_vertex_id, out_primitive_id, geom_out); + } + else { + geom_out.tex_coord = vec2(0, 1); + geom_out.final_color = geom_in[1].final_color; + geom_out.gpu_position = vec4((sp1 - geom_in[1].final_thickness * n1) / + gpencil_stroke_data.viewport, + getZdepth(P1), + 1.0); + strip_EmitVertex(0, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 1); + geom_out.final_color = geom_in[1].final_color; + geom_out.gpu_position = vec4((sp1 - geom_in[1].final_thickness * n0) / + gpencil_stroke_data.viewport, + getZdepth(P1), + 1.0); + strip_EmitVertex(1, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 0.5); + geom_out.final_color = geom_in[1].final_color; + geom_out.gpu_position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); + strip_EmitVertex(2, out_vertex_id, out_primitive_id, geom_out); + } + + /* Restart the strip. */ + geom_out.gpu_position = vec4(NAN_FLT); + strip_EmitVertex(3, out_vertex_id, out_primitive_id, geom_out); + } + + if (dot(v1, v2) < -MiterLimit) { + miter_b = n1; + length_b = geom_in[2].final_thickness; + } + + /* Generate the start end-cap (alpha < 0 used as end-cap flag). */ + float extend = gpencil_stroke_data.fill_stroke ? 2 : 1; + if ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) { + geom_out.tex_coord = vec2(1, 0.5); + geom_out.final_color = vec4(geom_in[1].final_color.rgb, geom_in[1].final_color.a * -1.0); + vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend; + geom_out.gpu_position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); + strip_EmitVertex(4, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 0); + geom_out.final_color = vec4(geom_in[1].final_color.rgb, geom_in[1].final_color.a * -1.0); + geom_out.gpu_position = vec4( + (sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); + strip_EmitVertex(5, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 1); + geom_out.final_color = vec4(geom_in[1].final_color.rgb, geom_in[1].final_color.a * -1.0); + geom_out.gpu_position = vec4( + (sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); + strip_EmitVertex(6, out_vertex_id, out_primitive_id, geom_out); + } + + /* generate the triangle strip */ + geom_out.tex_coord = vec2(0, 0); + geom_out.final_color = geom_in[1].final_color; + geom_out.gpu_position = vec4( + (sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); + strip_EmitVertex(7, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 1); + geom_out.final_color = geom_in[1].final_color; + geom_out.gpu_position = vec4( + (sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); + strip_EmitVertex(8, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 0); + geom_out.final_color = geom_in[2].final_color; + geom_out.gpu_position = vec4( + (sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); + strip_EmitVertex(9, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 1); + geom_out.final_color = geom_in[2].final_color; + geom_out.gpu_position = vec4( + (sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); + strip_EmitVertex(10, out_vertex_id, out_primitive_id, geom_out); + + /* Generate the end end-cap (alpha < 0 used as end-cap flag). */ + if ((gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) { + geom_out.tex_coord = vec2(0, 1); + geom_out.final_color = vec4(geom_in[2].final_color.rgb, geom_in[2].final_color.a * -1.0); + geom_out.gpu_position = vec4( + (sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); + strip_EmitVertex(11, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(0, 0); + geom_out.final_color = vec4(geom_in[2].final_color.rgb, geom_in[2].final_color.a * -1.0); + geom_out.gpu_position = vec4( + (sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); + strip_EmitVertex(12, out_vertex_id, out_primitive_id, geom_out); + + geom_out.tex_coord = vec2(1, 0.5); + geom_out.final_color = vec4(geom_in[2].final_color.rgb, geom_in[2].final_color.a * -1.0); + vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend; + geom_out.gpu_position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); + strip_EmitVertex(13, out_vertex_id, out_primitive_id, geom_out); + } +} + +void main() +{ + /* Line Strip Adjacency primitive. */ + const uint input_primitive_vertex_count = 1u; /* We read 4 but advance 1. Assume no restart. */ + /* Triangle list primitive (emulating triangle strip). */ + const uint ouput_primitive_vertex_count = 3u; + const uint ouput_primitive_count = 12u; + const uint ouput_invocation_count = 1u; + const uint output_vertex_count_per_invocation = ouput_primitive_count * + ouput_primitive_vertex_count; + const uint output_vertex_count_per_input_primitive = output_vertex_count_per_invocation * + ouput_invocation_count; + + uint in_primitive_id = uint(gl_VertexID) / output_vertex_count_per_input_primitive; + uint in_primitive_first_vertex = in_primitive_id * input_primitive_vertex_count; + + uint out_vertex_id = uint(gl_VertexID) % ouput_primitive_vertex_count; + uint out_primitive_id = (uint(gl_VertexID) / ouput_primitive_vertex_count) % + ouput_primitive_count; + uint out_invocation_id = (uint(gl_VertexID) / output_vertex_count_per_invocation) % + ouput_invocation_count; + + GreasePencilStrokeData vert_in[4]; + vert_in[0] = input_assembly(in_primitive_first_vertex + 0u); + vert_in[1] = input_assembly(in_primitive_first_vertex + 1u); + vert_in[2] = input_assembly(in_primitive_first_vertex + 2u); + vert_in[3] = input_assembly(in_primitive_first_vertex + 3u); + + VertOut vert_out[4]; + vert_out[0] = vertex_main(vert_in[0]); + vert_out[1] = vertex_main(vert_in[1]); + vert_out[2] = vertex_main(vert_in[2]); + vert_out[3] = vertex_main(vert_in[3]); + + /* Discard by default. */ + gl_Position = vec4(NAN_FLT); + geometry_main(vert_out, out_vertex_id, out_primitive_id, out_invocation_id); +} diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl deleted file mode 100644 index 4913a0f0802..00000000000 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl +++ /dev/null @@ -1,359 +0,0 @@ -/* SPDX-FileCopyrightText: 2023 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma USE_SSBO_VERTEX_FETCH(TriangleList, 27) - -#define GP_XRAY_FRONT 0 -#define GP_XRAY_3DSPACE 1 -#define GP_XRAY_BACK 2 - -#define GPENCIL_FLATCAP 1 - -#define DISCARD_VERTEX \ - gl_Position = vec4(0.0); \ - return; - -/* project 3d point to 2d on screen space */ -vec2 toScreenSpace(vec4 in_vertex) -{ - return vec2(in_vertex.xy / in_vertex.w) * gpencil_stroke_data.viewport; -} - -/* Get Z-depth value. */ -float getZdepth(vec4 point) -{ - if (gpencil_stroke_data.xraymode == GP_XRAY_FRONT) { - return 0.0; - } - if (gpencil_stroke_data.xraymode == GP_XRAY_3DSPACE) { - return (point.z / point.w); - } - if (gpencil_stroke_data.xraymode == GP_XRAY_BACK) { - return 1.0; - } - - /* in front by default */ - return 0.0; -} - -/* check equality but with a small tolerance */ -bool is_equal(vec4 p1, vec4 p2) -{ - float limit = 0.0001; - float x = abs(p1.x - p2.x); - float y = abs(p1.y - p2.y); - float z = abs(p1.z - p2.z); - - if ((x < limit) && (y < limit) && (z < limit)) { - return true; - } - - return false; -} - -/* Vertex emission. */ - -#define EMIT_VERTEX(vertex_selector, _v0, _v1, _v2) \ - { \ - switch (vertex_selector) { \ - case 0: { \ - _v0 \ - } break; \ - case 1: { \ - _v1 \ - } break; \ - case 2: { \ - _v2 \ - } break; \ - } \ - } \ - return; - -#define EMIT_VERTEX_COND(vertex_selector, condition, _v0, _v1, _v2) \ - { \ - if (condition) { \ - switch (vertex_selector) { \ - case 0: { \ - _v0 \ - } break; \ - case 1: { \ - _v1 \ - } break; \ - case 2: { \ - _v2 \ - } break; \ - } \ - } \ - else { \ - DISCARD_VERTEX; \ - } \ - } \ - return; - -/** All output vertex combinations. */ -/* Excessively long mitre gap. */ -#define V0_a \ - geometry_out.mTexCoord = vec2(0, 0); \ - geometry_out.mColor = finalColor[1]; \ - gl_Position = vec4( \ - (sp1 + finalThickness[1] * n0) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -#define V1_a \ - geometry_out.mTexCoord = vec2(0, 0); \ - geometry_out.mColor = finalColor[1]; \ - gl_Position = vec4( \ - (sp1 + finalThickness[1] * n1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -#define V2_a \ - geometry_out.mTexCoord = vec2(0, 0.5); \ - geometry_out.mColor = finalColor[1]; \ - gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -#define V0_b \ - geometry_out.mTexCoord = vec2(0, 1); \ - geometry_out.mColor = finalColor[1]; \ - gl_Position = vec4( \ - (sp1 - finalThickness[1] * n1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); -#define V1_b \ - geometry_out.mTexCoord = vec2(0, 1); \ - geometry_out.mColor = finalColor[1]; \ - gl_Position = vec4( \ - (sp1 - finalThickness[1] * n0) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -#define V2_b \ - geometry_out.mTexCoord = vec2(0, 0.5); \ - geometry_out.mColor = finalColor[1]; \ - gl_Position = vec4(sp1 / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -/* -- start end cap. -- */ -#define V3 \ - geometry_out.mTexCoord = vec2(1, 0.5); \ - geometry_out.mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); \ - vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend; \ - gl_Position = vec4((sp1 + svn1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -/* V4. */ -#define V4 \ - geometry_out.mTexCoord = vec2(0, 0); \ - geometry_out.mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); \ - gl_Position = vec4( \ - (sp1 - (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -/* V5. */ -#define V5 \ - geometry_out.mTexCoord = vec2(0, 1); \ - geometry_out.mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0); \ - gl_Position = vec4( \ - (sp1 + (length_a * 2.0) * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -/* -- Main triangle strip --*/ -#define V6 \ - geometry_out.mTexCoord = vec2(0, 0); \ - geometry_out.mColor = finalColor[1]; \ - gl_Position = vec4( \ - (sp1 + length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -/* V7. */ -#define V7 \ - geometry_out.mTexCoord = vec2(0, 1); \ - geometry_out.mColor = finalColor[1]; \ - gl_Position = vec4( \ - (sp1 - length_a * miter_a) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0); - -/* V8. */ -#define V8 \ - geometry_out.mTexCoord = vec2(0, 0); \ - geometry_out.mColor = finalColor[2]; \ - gl_Position = vec4( \ - (sp2 + length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - -/* V9. */ -#define V9 \ - geometry_out.mTexCoord = vec2(0, 1); \ - geometry_out.mColor = finalColor[2]; \ - gl_Position = vec4( \ - (sp2 - length_b * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - -/* End end-cap. */ -/* V10. */ -#define V10 \ - geometry_out.mTexCoord = vec2(0, 1); \ - geometry_out.mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); \ - gl_Position = vec4( \ - (sp2 + (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - -/* V11. */ -#define V11 \ - geometry_out.mTexCoord = vec2(0, 0); \ - geometry_out.mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); \ - gl_Position = vec4( \ - (sp2 - (length_b * 2.0) * miter_b) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - -/* V12. */ -#define V12 \ - geometry_out.mTexCoord = vec2(1, 0.5); \ - geometry_out.mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0); \ - vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend; \ - gl_Position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0); - -vec4 uchar4_to_normalized_vec4(uchar4 udata) -{ - return vec4(udata) / vec4(255.0f); -} - -void main(void) -{ - /* Determine output geometry IDs. */ - uint input_prim_id = gl_VertexID / 27; - uint output_vertex_id = gl_VertexID % 27; - uint output_prim_triangle_id = output_vertex_id / 3; - uint vertex_in_triangle = output_vertex_id % 3; - - /** Run Vertex shader for all input vertices (Lines adjacency). */ - vec4 finalPos[4]; - vec4 finalColor[4]; - float finalThickness[4]; - - float defaultpixsize = gpencil_stroke_data.pixsize * (1000.0 / gpencil_stroke_data.pixfactor); - - for (int i = 0; i < 4; i++) { - finalPos[i] = ModelViewProjectionMatrix * - vec4(vertex_fetch_attribute(input_prim_id + i, pos, vec3).xyz, 1.0); - /* Attribute is expected to be in the float4 format. */ - finalColor[i] = vertex_fetch_attribute(input_prim_id + i, color, float4); - float in_thickness = vertex_fetch_attribute(input_prim_id + i, thickness, float); - - if (gpencil_stroke_data.keep_size) { - finalThickness[i] = in_thickness; - } - else { - float size = (ProjectionMatrix[3][3] == 0.0) ? - (in_thickness / (finalPos[i].z * defaultpixsize)) : - (in_thickness / defaultpixsize); - finalThickness[i] = max(size * gpencil_stroke_data.objscale, 1.0); - } - } - - /** Perform Geometry shader alternative. */ - float MiterLimit = 0.75; - - /* receive 4 points */ - vec4 P0 = finalPos[0]; - vec4 P1 = finalPos[1]; - vec4 P2 = finalPos[2]; - vec4 P3 = finalPos[3]; - - /* get the four vertices passed to the shader */ - vec2 sp0 = toScreenSpace(P0); /* start of previous segment */ - vec2 sp1 = toScreenSpace(P1); /* end of previous segment, start of current segment */ - vec2 sp2 = toScreenSpace(P2); /* end of current segment, start of next segment */ - vec2 sp3 = toScreenSpace(P3); /* end of next segment */ - - /* culling outside viewport */ - vec2 area = gpencil_stroke_data.viewport * 4.0; - if (sp1.x < -area.x || sp1.x > area.x) { - DISCARD_VERTEX; - } - if (sp1.y < -area.y || sp1.y > area.y) { - DISCARD_VERTEX; - } - if (sp2.x < -area.x || sp2.x > area.x) { - DISCARD_VERTEX; - } - if (sp2.y < -area.y || sp2.y > area.y) { - DISCARD_VERTEX; - } - - /* determine the direction of each of the 3 segments (previous, - * current, next) */ - vec2 v0 = normalize(sp1 - sp0); - vec2 v1 = normalize(sp2 - sp1); - vec2 v2 = normalize(sp3 - sp2); - - /* determine the normal of each of the 3 segments (previous, - * current, next) */ - vec2 n0 = vec2(-v0.y, v0.x); - vec2 n1 = vec2(-v1.y, v1.x); - vec2 n2 = vec2(-v2.y, v2.x); - - /* determine miter lines by averaging the normals of the 2 - * segments */ - vec2 miter_a = normalize(n0 + n1); /* miter at start of current segment */ - vec2 miter_b = normalize(n1 + n2); /* miter at end of current segment */ - - /* determine the length of the miter by projecting it onto normal - * and then inverse it */ - float an1 = dot(miter_a, n1); - float bn1 = dot(miter_b, n2); - if (an1 == 0) { - an1 = 1; - } - if (bn1 == 0) { - bn1 = 1; - } - float length_a = finalThickness[1] / an1; - float length_b = finalThickness[2] / bn1; - if (length_a <= 0.0) { - length_a = 0.01; - } - if (length_b <= 0.0) { - length_b = 0.01; - } - - /** Geometry output. */ - - /* prevent excessively long miters at sharp corners */ - if (dot(v0, v1) < -MiterLimit) { - miter_a = n1; - length_a = finalThickness[1]; - } - - /* First triangle (T0). */ - if (output_prim_triangle_id == 0) { - if (dot(v0, v1) < -MiterLimit) { - if (dot(v0, n1) > 0) { - EMIT_VERTEX(vertex_in_triangle, V0_a, V1_a, V2_a) - } - else { - EMIT_VERTEX(vertex_in_triangle, V0_b, V1_b, V2_b) - } - } - else { - DISCARD_VERTEX - } - } - - if (dot(v1, v2) < -MiterLimit) { - miter_b = n1; - length_b = finalThickness[2]; - } - - float extend = gpencil_stroke_data.fill_stroke ? 2 : 1; - bool start_endcap = ((gpencil_stroke_data.caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)); - bool end_endcap = (gpencil_stroke_data.caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3); - - switch (output_prim_triangle_id) { - /* -- Start: end cap. -*/ - case 1: - EMIT_VERTEX_COND(vertex_in_triangle, start_endcap, V3, V4, V5) - case 2: - EMIT_VERTEX_COND(vertex_in_triangle, start_endcap, V4, V5, V6) - case 3: - EMIT_VERTEX_COND(vertex_in_triangle, start_endcap, V5, V6, V7) - /* -- Standard triangle strip. -- */ - case 4: - EMIT_VERTEX(vertex_in_triangle, V6, V7, V8) - case 5: - EMIT_VERTEX(vertex_in_triangle, V7, V8, V9) - /* -- End: end cap. -- */ - case 6: - EMIT_VERTEX_COND(vertex_in_triangle, end_endcap, V8, V9, V10) - case 7: - EMIT_VERTEX_COND(vertex_in_triangle, end_endcap, V9, V10, V11) - case 8: - EMIT_VERTEX_COND(vertex_in_triangle, end_endcap, V10, V11, V12) - default: - DISCARD_VERTEX - } -} diff --git a/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh index 3adbb5b81a8..0f82e58f712 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_gpencil_stroke_info.hh @@ -8,44 +8,20 @@ #include "gpu_shader_create_info.hh" -GPU_SHADER_NAMED_INTERFACE_INFO(gpencil_stroke_vert_iface, geometry_in) -SMOOTH(VEC4, finalColor) -SMOOTH(FLOAT, finalThickness) -GPU_SHADER_NAMED_INTERFACE_END(geometry_in) -GPU_SHADER_NAMED_INTERFACE_INFO(gpencil_stroke_geom_iface, geometry_out) +GPU_SHADER_NAMED_INTERFACE_INFO(gpencil_stroke_vert_iface, interp) SMOOTH(VEC4, mColor) SMOOTH(VEC2, mTexCoord) GPU_SHADER_NAMED_INTERFACE_END(geometry_out) -GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke_base) -VERTEX_IN(0, VEC4, color) -VERTEX_IN(1, VEC3, pos) -VERTEX_IN(2, FLOAT, thickness) +GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke) +TYPEDEF_SOURCE("GPU_shader_shared.hh") +STORAGE_BUF_FREQ(0, READ, GreasePencilStrokeData, gp_vert_data[], GEOMETRY) VERTEX_OUT(gpencil_stroke_vert_iface) FRAGMENT_OUT(0, VEC4, fragColor) - UNIFORM_BUF(0, GPencilStrokeData, gpencil_stroke_data) - PUSH_CONSTANT(MAT4, ModelViewProjectionMatrix) PUSH_CONSTANT(MAT4, ProjectionMatrix) FRAGMENT_SOURCE("gpu_shader_gpencil_stroke_frag.glsl") -TYPEDEF_SOURCE("GPU_shader_shared.hh") -GPU_SHADER_CREATE_END() - -GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke) -ADDITIONAL_INFO(gpu_shader_gpencil_stroke_base) -GEOMETRY_LAYOUT(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::TRIANGLE_STRIP, 13) -GEOMETRY_OUT(gpencil_stroke_geom_iface) VERTEX_SOURCE("gpu_shader_gpencil_stroke_vert.glsl") -GEOMETRY_SOURCE("gpu_shader_gpencil_stroke_geom.glsl") -DO_STATIC_COMPILATION() -GPU_SHADER_CREATE_END() - -GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke_no_geom) -METAL_BACKEND_ONLY() -DEFINE("USE_GEOMETRY_IFACE_COLOR") -ADDITIONAL_INFO(gpu_shader_gpencil_stroke_base) -VERTEX_OUT(gpencil_stroke_geom_iface) -VERTEX_SOURCE("gpu_shader_gpencil_stroke_vert_no_geom.glsl") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END()