From 8dee08996e42fdcc054f2cd362f33b63a4d5a6bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Foucault?= Date: Mon, 5 May 2025 09:59:00 +0200 Subject: [PATCH] GPU: Shader: Add wrapper to stage agnostic function This avoid having to guards functions that are only available in fragment shader stage. Calling the function inside another stage is still invalid and will yield a compile error on Metal. The vulkan and opengl glsl patch need to be modified per stage to allow the fragment specific function to be defined. This is not yet widely used, but a good example is the change in `film_display_depth_amend`. Rel #137261 Pull Request: https://projects.blender.org/blender/blender/pulls/138280 --- .../shaders/eevee_debug_gbuffer_frag.glsl | 2 +- .../shaders/eevee_debug_surfels_frag.glsl | 2 +- .../eevee_deferred_tile_classify_frag.glsl | 2 +- .../eevee_depth_of_field_scatter_frag.glsl | 2 +- .../eevee_display_lightprobe_sphere_frag.glsl | 2 +- .../eevee_display_lightprobe_volume_frag.glsl | 2 +- .../eevee/shaders/eevee_film_copy_frag.glsl | 2 +- .../engines/eevee/shaders/eevee_film_lib.glsl | 4 +- .../shaders/eevee_lookdev_display_frag.glsl | 2 +- .../eevee/shaders/eevee_nodetree_lib.glsl | 6 +- .../eevee/shaders/eevee_surf_depth_frag.glsl | 4 +- .../engines/eevee/shaders/eevee_surf_lib.glsl | 6 +- .../eevee/shaders/eevee_surf_shadow_frag.glsl | 2 +- .../eevee/shaders/eevee_transparency_lib.glsl | 2 +- .../shaders/gpencil_antialiasing_frag.glsl | 2 +- .../engines/gpencil/shaders/gpencil_frag.glsl | 6 +- .../shaders/image_engine_color_frag.glsl | 2 +- .../overlay_armature_shape_solid_frag.glsl | 2 +- .../overlay_depth_only_gpencil_frag.glsl | 2 +- .../shaders/overlay_edit_uv_edges_frag.glsl | 2 +- .../shaders/overlay_extra_wire_frag.glsl | 2 +- .../overlay/shaders/overlay_grid_frag.glsl | 6 +- .../overlay/shaders/overlay_image_frag.glsl | 2 +- .../shaders/overlay_outline_detect_frag.glsl | 2 +- .../overlay_outline_prepass_gpencil_frag.glsl | 2 +- .../shaders/overlay_paint_weight_frag.glsl | 2 +- .../shaders/overlay_particle_frag.glsl | 2 +- .../overlay_point_varying_color_frag.glsl | 2 +- .../shaders/overlay_wireframe_frag.glsl | 2 +- .../shaders/overlay_xray_fade_frag.glsl | 4 +- .../shaders/workbench_composite_frag.glsl | 2 +- .../shaders/workbench_effect_smaa_frag.glsl | 2 +- .../shaders/workbench_image_lib.glsl | 2 +- .../shaders/workbench_volume_frag.glsl | 6 +- source/blender/gpu/opengl/gl_shader.cc | 98 +++++++++++++++---- .../shaders/common/gpu_shader_smaa_lib.glsl | 6 +- .../blender/gpu/shaders/gpu_glsl_cpp_stubs.hh | 14 ++- .../gpu_shader_2D_line_dashed_frag.glsl | 2 +- .../gpu_shader_2D_widget_base_frag.glsl | 6 +- .../shaders/gpu_shader_3D_polyline_frag.glsl | 2 +- .../gpu/shaders/gpu_shader_codegen_lib.glsl | 8 +- .../gpu_shader_gpencil_stroke_frag.glsl | 2 +- ...ader_image_overlays_stereo_merge_frag.glsl | 2 +- ...pu_shader_point_uniform_color_aa_frag.glsl | 2 +- ...r_point_uniform_color_outline_aa_frag.glsl | 2 +- .../gpu_shader_point_varying_color_frag.glsl | 2 +- .../material/gpu_shader_material_bump.glsl | 4 +- .../gpu_shader_material_tex_image.glsl | 4 +- .../gpu_shader_material_wireframe.glsl | 4 +- .../gpu/shaders/metal/mtl_shader_defines.msl | 8 ++ .../shaders/opengl/glsl_shader_defines.glsl | 15 +++ source/blender/gpu/vulkan/vk_device.cc | 36 +++++-- source/blender/gpu/vulkan/vk_device.hh | 10 +- source/blender/gpu/vulkan/vk_shader.cc | 28 ++++-- 54 files changed, 238 insertions(+), 111 deletions(-) diff --git a/source/blender/draw/engines/eevee/shaders/eevee_debug_gbuffer_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_debug_gbuffer_frag.glsl index f37d904363b..ff15a12cd97 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_debug_gbuffer_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_debug_gbuffer_frag.glsl @@ -23,7 +23,7 @@ void main() GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel); if (gbuf.closure_count == 0) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/eevee/shaders/eevee_debug_surfels_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_debug_surfels_frag.glsl index a613e2ff448..cec489fcce6 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_debug_surfels_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_debug_surfels_frag.glsl @@ -42,7 +42,7 @@ void main() /* Display surfels as circles. */ if (distance(P, surfel.position) > debug_surfel_radius) { - discard; + gpu_discard_fragment(); return; } } diff --git a/source/blender/draw/engines/eevee/shaders/eevee_deferred_tile_classify_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_deferred_tile_classify_frag.glsl index 4be9cde130b..e8199c263a3 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_deferred_tile_classify_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_deferred_tile_classify_frag.glsl @@ -28,7 +28,7 @@ void main() * Discard fragments that do not have a number of closure whose bit-pattern * overlap the current stencil un-masked bit. */ if ((current_bit & (closure_count | has_transmission)) == 0) { - discard; + gpu_discard_fragment(); return; } #endif diff --git a/source/blender/draw/engines/eevee/shaders/eevee_depth_of_field_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_depth_of_field_scatter_frag.glsl index 948868f949d..2094f0a0bfe 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_depth_of_field_scatter_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_depth_of_field_scatter_frag.glsl @@ -44,7 +44,7 @@ void main() shapes = saturate(1.0f - linearstep(-0.8f, 0.8f, shapes)); /* Outside of bokeh shape. Try to avoid overloading ROPs. */ if (reduce_max(shapes) == 0.0f) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/eevee/shaders/eevee_display_lightprobe_sphere_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_display_lightprobe_sphere_frag.glsl index 60e6f4f2325..7b4fb1aeb71 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_display_lightprobe_sphere_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_display_lightprobe_sphere_frag.glsl @@ -15,7 +15,7 @@ void main() /* Discard outside the circle. */ if (dist_sqr > 1.0f) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/eevee/shaders/eevee_display_lightprobe_volume_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_display_lightprobe_volume_frag.glsl index 9d723b04a12..d1532a4e63b 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_display_lightprobe_volume_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_display_lightprobe_volume_frag.glsl @@ -16,7 +16,7 @@ void main() /* Discard outside the circle. */ if (dist_sqr > 1.0f) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/eevee/shaders/eevee_film_copy_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_film_copy_frag.glsl index 5c38f26441c..11db515fe7e 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_film_copy_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_film_copy_frag.glsl @@ -48,6 +48,6 @@ void main() float out_depth = imageLoadFast(depth_img, texel).r; out_depth = drw_depth_view_to_screen(-out_depth); - out_depth += 2.4e-7f * 4.0f + fwidth(out_depth); + out_depth += 2.4e-7f * 4.0f + gpu_fwidth(out_depth); gl_FragDepth = saturate(out_depth); } diff --git a/source/blender/draw/engines/eevee/shaders/eevee_film_lib.glsl b/source/blender/draw/engines/eevee/shaders/eevee_film_lib.glsl index 89c02aa4ae7..f814da6077f 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_film_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_film_lib.glsl @@ -630,9 +630,7 @@ float film_display_depth_amend(int2 texel, float depth) * twice. One for X and one for Y direction. */ /* TODO(fclem): This could be improved as it gives flickering result at depth discontinuity. * But this is the quickest stable result I could come with for now. */ -#ifdef GPU_FRAGMENT_SHADER - depth += fwidth(depth); -#endif + depth += gpu_fwidth(depth); /* Small offset to avoid depth test lessEqual failing because of all the conversions loss. */ depth += 2.4e-7f * 4.0f; return saturate(depth); diff --git a/source/blender/draw/engines/eevee/shaders/eevee_lookdev_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_lookdev_display_frag.glsl index a2ea5a49f44..a182cc8bdaf 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_lookdev_display_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_lookdev_display_frag.glsl @@ -13,7 +13,7 @@ void main() float distance_from_center = distance(uv_coord.xy, float2(0.5f)); if (distance_from_center > 0.5f) { - discard; + gpu_discard_fragment(); return; } float smooth_size = texel_size.x * 1.5f; diff --git a/source/blender/draw/engines/eevee/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee/shaders/eevee_nodetree_lib.glsl index c2ae119fdcb..c41b0c3389e 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_nodetree_lib.glsl @@ -621,7 +621,7 @@ float2 bsdf_lut(float cos_theta, float roughness, float ior, bool do_multiscatte /* Return new shading normal. */ float3 displacement_bump() { -# if defined(GPU_FRAGMENT_SHADER) && !defined(MAT_GEOM_CURVES) +# if !defined(MAT_GEOM_CURVES) /* This is the filter width for automatic displacement + bump mapping, which is fixed. * NOTE: keep the same as default bump node filter width. */ constexpr float bump_filter_width = 0.1f; @@ -629,8 +629,8 @@ float3 displacement_bump() float2 dHd; dF_branch(dot(nodetree_displacement(), g_data.N + dF_impl(g_data.N)), bump_filter_width, dHd); - float3 dPdx = dFdx(g_data.P); - float3 dPdy = dFdy(g_data.P); + float3 dPdx = gpu_dfdx(g_data.P); + float3 dPdy = gpu_dfdy(g_data.P); /* Get surface tangents from normal. */ float3 Rx = cross(dPdy, g_data.N); diff --git a/source/blender/draw/engines/eevee/shaders/eevee_surf_depth_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_surf_depth_frag.glsl index 0056f7ed7f7..4507377d613 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_surf_depth_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_surf_depth_frag.glsl @@ -50,7 +50,7 @@ void main() float transparency = average(g_transmittance); if (transparency > threshold) { - discard; + gpu_discard_fragment(); return; } #endif @@ -60,7 +60,7 @@ void main() * This would in turn create a discrepancy between the pre-pass depth and the G-buffer depth * which exhibits missing pixels data. */ if (clip_interp.clip_distance > 0.0f) { - discard; + gpu_discard_fragment(); return; } #endif diff --git a/source/blender/draw/engines/eevee/shaders/eevee_surf_lib.glsl b/source/blender/draw/engines/eevee/shaders/eevee_surf_lib.glsl index 067502da2bc..1c10e631003 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_surf_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_surf_lib.glsl @@ -18,8 +18,8 @@ SHADER_LIBRARY_CREATE_INFO(eevee_geom_mesh) #if defined(USE_BARYCENTRICS) && defined(GPU_FRAGMENT_SHADER) && defined(MAT_GEOM_MESH) float3 barycentric_distances_get() { - float wp_delta = length(dFdx(interp.P)) + length(dFdy(interp.P)); - float bc_delta = length(dFdx(gpu_BaryCoord)) + length(dFdy(gpu_BaryCoord)); + float wp_delta = length(gpu_dfdx(interp.P)) + length(gpu_dfdy(interp.P)); + float bc_delta = length(gpu_dfdx(gpu_BaryCoord)) + length(gpu_dfdy(gpu_BaryCoord)); float rate_of_change = wp_delta / bc_delta; return rate_of_change * (1.0f - gpu_BaryCoord); } @@ -107,7 +107,7 @@ void init_globals() #ifdef GPU_FRAGMENT_SHADER g_data.N = (FrontFacing) ? g_data.N : -g_data.N; g_data.Ni = (FrontFacing) ? g_data.Ni : -g_data.Ni; - g_data.Ng = safe_normalize(cross(dFdx(g_data.P), dFdy(g_data.P))); + g_data.Ng = safe_normalize(cross(gpu_dfdx(g_data.P), gpu_dfdy(g_data.P))); #endif #if defined(MAT_GEOM_MESH) diff --git a/source/blender/draw/engines/eevee/shaders/eevee_surf_shadow_frag.glsl b/source/blender/draw/engines/eevee/shaders/eevee_surf_shadow_frag.glsl index a49e6563cbd..b85f0c6adc8 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_surf_shadow_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_surf_shadow_frag.glsl @@ -43,7 +43,7 @@ void main() ndc_depth = 1.0f; #else # define discard_result \ - discard; \ + gpu_discard_fragment(); \ return; #endif diff --git a/source/blender/draw/engines/eevee/shaders/eevee_transparency_lib.glsl b/source/blender/draw/engines/eevee/shaders/eevee_transparency_lib.glsl index f949af6ef00..c52909962f0 100644 --- a/source/blender/draw/engines/eevee/shaders/eevee_transparency_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/eevee_transparency_lib.glsl @@ -20,7 +20,7 @@ float transparency_hash_3d(float3 a) float transparency_hashed_alpha_threshold(float hash_scale, float hash_offset, float3 P) { /* Find the discretized derivatives of our coordinates. */ - float max_deriv = max(length(dFdx(P)), length(dFdy(P))); + float max_deriv = max(length(gpu_dfdx(P)), length(gpu_dfdy(P))); float pix_scale = 1.0f / (hash_scale * max_deriv); /* Find two nearest log-discretized noise scales. */ float pix_scale_log = log2(pix_scale); diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl index cb9dcfe9c61..07323ad8778 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl @@ -16,7 +16,7 @@ void main() out_edges = max(out_edges, SMAALumaEdgeDetectionPS(uvs, offset, reveal_tx)); /* Discard if there is no edge. */ if (dot(out_edges, float2(1.0f, 1.0f)) == 0.0f) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl index 383bfbc49ef..2996d4bb255 100644 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl @@ -102,7 +102,7 @@ void main() revealColor = float4(0.0f, 0.0f, 0.0f, frag_color.a); if (frag_color.a < 0.001f) { - discard; + gpu_discard_fragment(); return; } } @@ -113,7 +113,7 @@ void main() /* Manual depth test */ float scene_depth = texture(gp_scene_depth_tx, uvs).r; if (gl_FragCoord.z > scene_depth) { - discard; + gpu_discard_fragment(); return; } @@ -121,7 +121,7 @@ void main() * depth written where the mask obliterate the layer. */ float mask = texture(gp_mask_tx, uvs).r; if (mask < 0.001f) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/image/shaders/image_engine_color_frag.glsl b/source/blender/draw/engines/image/shaders/image_engine_color_frag.glsl index 333f5fd8632..2e483718a93 100644 --- a/source/blender/draw/engines/image/shaders/image_engine_color_frag.glsl +++ b/source/blender/draw/engines/image/shaders/image_engine_color_frag.glsl @@ -18,7 +18,7 @@ void main() int2 uvs_clamped = int2(uv_screen); float depth = texelFetch(depth_tx, uvs_clamped, 0).r; if (depth == 1.0f) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl index dbb01a98d40..c765a9aa131 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl @@ -14,7 +14,7 @@ void main() * but needed for view clarity in X-ray mode and support * for inverted bone matrices. */ if ((inverted == 1) == gl_FrontFacing) { - discard; + gpu_discard_fragment(); return; } frag_color = float4(final_color.rgb, alpha); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_gpencil_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_gpencil_frag.glsl index 915d87433df..d5c5db3a86e 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_gpencil_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_gpencil_frag.glsl @@ -29,7 +29,7 @@ void main() #ifndef SELECT_ENABLE /* We cannot discard the fragment in selection mode. Otherwise we would break pipeline * correctness (no discard if early depth test enforced). */ - discard; + gpu_discard_fragment(); #endif return; } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl index c3f16862dc6..c2989de3947 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl @@ -15,7 +15,7 @@ void main() float4 inner_color = float4(float3(0.0f), 1.0f); float4 outer_color = float4(0.0f); - float2 dd = fwidth(stipple_pos); + float2 dd = gpu_fwidth(stipple_pos); float line_distance = distance(stipple_pos, stipple_start) / max(dd.x, dd.y); if (OVERLAY_UVLineStyle(line_style) == OVERLAY_UV_LINE_STYLE_OUTLINE) { diff --git a/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl index cf966b8ca8c..6e7cfdb3b33 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl @@ -33,7 +33,7 @@ void main() * This is because we force the early depth test to only output the front most fragment. * Discarding would expose us to race condition depending on rasterization order. */ if (fract(dist / dash_width) > dash_factor) { - discard; + gpu_discard_fragment(); } #endif diff --git a/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl index 2de4818dad9..2b60e3a39af 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl @@ -43,8 +43,8 @@ float3 get_axes(float3 co, float3 fwidthCos, float line_size) void main() { float3 P = local_pos * grid_buf.size.xyz; - float3 dFdxPos = dFdx(P); - float3 dFdyPos = dFdy(P); + float3 dFdxPos = gpu_dfdx(P); + float3 dFdyPos = gpu_dfdy(P); float3 fwidthPos = abs(dFdxPos) + abs(dFdyPos); P += drw_view_position() * plane_axes; @@ -210,7 +210,7 @@ void main() * (avoids popping visuals due to depth buffer precision) */ /* Harder settings tend to flicker more, * but have less "see through" appearance. */ - float bias = max(fwidth(gl_FragCoord.z), 2.4e-7f); + float bias = max(gpu_fwidth(gl_FragCoord.z), 2.4e-7f); fade *= linearstep(grid_depth, grid_depth + bias, scene_depth); } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl index 5e5e8568e14..aa5cdf2cc99 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl @@ -21,7 +21,7 @@ void main() /* Arbitrary discard anything below 5% opacity. * Note that this could be exposed to the User. */ if (tex_color.a < 0.05f) { - discard; + gpu_discard_fragment(); } else { frag_color.a = 1.0f; diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl index 7d993bb4c90..cc5df1c28ed 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl @@ -265,7 +265,7 @@ void main() /* NOTE(Metal): Discards are not explicit returns in Metal. We should also return to avoid * erroneous derivatives which can manifest during texture sampling in * non-uniform-control-flow. */ - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl index d4c9659c2e7..65f6a1590a8 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl @@ -25,7 +25,7 @@ void main() gp_interp_noperspective.thickness.x, gp_interp_noperspective.hardness) < 0.001f) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl index a2fa0fc40a0..4019de913fc 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl @@ -90,7 +90,7 @@ void main() /* Contour display */ if (draw_contours) { /* This must be executed uniformly for all fragments */ - float weight_gradient = length(float2(dFdx(weight), dFdy(weight))); + float weight_gradient = length(float2(gpu_dfdx(weight), gpu_dfdy(weight))); float4 grid = contour_grid(weight, weight_gradient); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl index 7cd0b7b28cd..f1d2bff595b 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl @@ -15,7 +15,7 @@ void main() float dist = length(uv); if (dist > 0.5f) { - discard; + gpu_discard_fragment(); return; } /* Nice sphere falloff. */ diff --git a/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl index 177290600f3..76bf55f7a40 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl @@ -16,7 +16,7 @@ void main() /* Round point with jagged edges. */ if (dist_squared > rad_squared) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl index fc52fa38189..360e57b14b5 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl @@ -16,7 +16,7 @@ void main() /* Needed only because of wireframe slider. * If we could get rid of it would be nice because of performance drain of discard. */ if (edge_start.r == -1.0f) { - discard; + gpu_discard_fragment(); return; } #endif diff --git a/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl index b370cfad203..b463fbc9c95 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl @@ -18,7 +18,7 @@ void main() return; } - discard; + gpu_discard_fragment(); return; } @@ -34,6 +34,6 @@ void main() return; } - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl index 01b88460e91..8a5482ee74b 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl @@ -23,7 +23,7 @@ void main() float depth = texture(depth_tx, uv).r; if (depth == 1.0f) { /* Skip the background. */ - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl index a494454a9d8..d276f14d3a8 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl @@ -16,7 +16,7 @@ void main() out_edges = SMAALumaEdgeDetectionPS(uvs, offset, color_tx); /* Discard if there is no edge. */ if (dot(out_edges, float2(1.0f, 1.0f)) == 0.0f) { - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl index ee56687d58b..f3cc8660736 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl @@ -59,7 +59,7 @@ float3 workbench_image_color(float2 uvs) # ifdef GPU_FRAGMENT_SHADER if (color.a < image_transparency_cutoff) { - discard; + gpu_discard_fragment(); } # endif diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index 8a9ce05bad9..981e9cf606d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -240,7 +240,7 @@ void main() constexpr uint in_front_stencil_bits = 1u << 1; if (do_depth_test && (stencil & in_front_stencil_bits) != 0) { /* Don't draw on top of "in front" objects. */ - discard; + gpu_discard_fragment(); return; } @@ -255,7 +255,7 @@ void main() * Adding a return call eliminates undefined behavior and a later out-of-bounds read causing * a crash on AMD platforms. * This behavior can also affect OpenGL on certain devices. */ - discard; + gpu_discard_fragment(); return; } @@ -305,7 +305,7 @@ void main() if (dot(ls_ray_dir, ls_vol_isect) < 0.0f) { /* Start is further away than the end. * That means no volume is intersected. */ - discard; + gpu_discard_fragment(); return; } diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 59d7690fb6a..d670c8f730c 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -1016,18 +1016,13 @@ bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info /** \name Shader stage creation * \{ */ -static StringRefNull glsl_patch_default_get() +static StringRefNull glsl_patch_vertex_get() { /** Used for shader patching. Init once. */ static std::string patch = []() { std::stringstream ss; /* Version need to go first. */ - if (epoxy_gl_version() >= 43) { - ss << "#version 430\n"; - } - else { - ss << "#version 330\n"; - } + ss << "#version 430\n"; /* Enable extensions for features that are not part of our base GLSL version * don't use an extension for something already available! */ @@ -1042,13 +1037,6 @@ static StringRefNull glsl_patch_default_get() if (GLContext::native_barycentric_support) { ss << "#extension GL_AMD_shader_explicit_vertex_parameter: enable\n"; } - if (GLContext::framebuffer_fetch_support) { - ss << "#extension GL_EXT_shader_framebuffer_fetch: enable\n"; - } - if (GPU_stencil_export_support()) { - ss << "#extension GL_ARB_shader_stencil_export: enable\n"; - ss << "#define GPU_ARB_shader_stencil_export\n"; - } /* Fallbacks. */ if (!GLContext::shader_draw_parameters_support) { @@ -1057,11 +1045,75 @@ static StringRefNull glsl_patch_default_get() /* Vulkan GLSL compatibility. */ ss << "#define gpu_InstanceIndex (gl_InstanceID + gpu_BaseInstance)\n"; - ss << "#define gpu_EmitVertex EmitVertex\n"; /* Array compatibility. */ ss << "#define gpu_Array(_type) _type[]\n"; + /* Needs to have this defined upfront for configuring shader defines. */ + ss << "#define GPU_VERTEX_SHADER\n"; + /* GLSL Backend Lib. */ + ss << datatoc_glsl_shader_defines_glsl; + + return ss.str(); + }(); + return patch; +} + +static StringRefNull glsl_patch_geometry_get() +{ + /** Used for shader patching. Init once. */ + static std::string patch = []() { + std::stringstream ss; + /* Version need to go first. */ + ss << "#version 430\n"; + + if (GLContext::layered_rendering_support) { + ss << "#extension GL_ARB_shader_viewport_layer_array: enable\n"; + } + if (GLContext::native_barycentric_support) { + ss << "#extension GL_AMD_shader_explicit_vertex_parameter: enable\n"; + } + + /* Array compatibility. */ + ss << "#define gpu_Array(_type) _type[]\n"; + + /* Needs to have this defined upfront for configuring shader defines. */ + ss << "#define GPU_GEOMETRY_SHADER\n"; + /* GLSL Backend Lib. */ + ss << datatoc_glsl_shader_defines_glsl; + + return ss.str(); + }(); + return patch; +} + +static StringRefNull glsl_patch_fragment_get() +{ + /** Used for shader patching. Init once. */ + static std::string patch = []() { + std::stringstream ss; + /* Version need to go first. */ + ss << "#version 430\n"; + + if (GLContext::layered_rendering_support) { + ss << "#extension GL_ARB_shader_viewport_layer_array: enable\n"; + } + if (GLContext::native_barycentric_support) { + ss << "#extension GL_AMD_shader_explicit_vertex_parameter: enable\n"; + } + if (GLContext::framebuffer_fetch_support) { + ss << "#extension GL_EXT_shader_framebuffer_fetch: enable\n"; + } + if (GPU_stencil_export_support()) { + ss << "#extension GL_ARB_shader_stencil_export: enable\n"; + ss << "#define GPU_ARB_shader_stencil_export\n"; + } + + /* Array compatibility. */ + ss << "#define gpu_Array(_type) _type[]\n"; + + /* Needs to have this defined upfront for configuring shader defines. */ + ss << "#define GPU_FRAGMENT_SHADER\n"; /* GLSL Backend Lib. */ ss << datatoc_glsl_shader_defines_glsl; @@ -1077,11 +1129,13 @@ static StringRefNull glsl_patch_compute_get() std::stringstream ss; /* Version need to go first. */ ss << "#version 430\n"; - ss << "#extension GL_ARB_compute_shader :enable\n"; /* Array compatibility. */ ss << "#define gpu_Array(_type) _type[]\n"; + /* Needs to have this defined upfront for configuring shader defines. */ + ss << "#define GPU_COMPUTE_SHADER\n"; + ss << datatoc_glsl_shader_defines_glsl; return ss.str(); @@ -1091,10 +1145,20 @@ static StringRefNull glsl_patch_compute_get() StringRefNull GLShader::glsl_patch_get(GLenum gl_stage) { + if (gl_stage == GL_VERTEX_SHADER) { + return glsl_patch_vertex_get(); + } + if (gl_stage == GL_GEOMETRY_SHADER) { + return glsl_patch_geometry_get(); + } + if (gl_stage == GL_FRAGMENT_SHADER) { + return glsl_patch_fragment_get(); + } if (gl_stage == GL_COMPUTE_SHADER) { return glsl_patch_compute_get(); } - return glsl_patch_default_get(); + BLI_assert_unreachable(); + return ""; } GLuint GLShader::create_shader_stage(GLenum gl_stage, diff --git a/source/blender/gpu/shaders/common/gpu_shader_smaa_lib.glsl b/source/blender/gpu/shaders/common/gpu_shader_smaa_lib.glsl index 7feb8b85b56..59ed51e5a0c 100644 --- a/source/blender/gpu/shaders/common/gpu_shader_smaa_lib.glsl +++ b/source/blender/gpu/shaders/common/gpu_shader_smaa_lib.glsl @@ -735,7 +735,7 @@ float2 SMAALumaEdgeDetectionPS(float2 texcoord, # ifndef SMAA_NO_DISCARD // Then discard if there is no edge: if (dot(edges, float2(1.0f, 1.0f)) == 0.0f) { - discard; + gpu_discard_fragment(); return float2(0.0f, 0.0f); } # endif @@ -810,7 +810,7 @@ float2 SMAAColorEdgeDetectionPS(float2 texcoord, # ifdef GPU_FRAGMENT_SHADER // Then discard if there is no edge: if (dot(edges, float2(1.0f, 1.0f)) == 0.0f) { - discard; + gpu_discard_fragment(); return float2(0.0f, 0.0f); } # endif @@ -858,7 +858,7 @@ float2 SMAADepthEdgeDetectionPS(float2 texcoord, float4 offset[3], SMAATexture2D # ifdef GPU_FRAGMENT_SHADER if (dot(edges, float2(1.0f, 1.0f)) == 0.0f) { - discard; + gpu_discard_fragment(); return float2(0.0f, 0.0f); } # endif diff --git a/source/blender/gpu/shaders/gpu_glsl_cpp_stubs.hh b/source/blender/gpu/shaders/gpu_glsl_cpp_stubs.hh index 1fdf7b77c8f..3e5b753f86b 100644 --- a/source/blender/gpu/shaders/gpu_glsl_cpp_stubs.hh +++ b/source/blender/gpu/shaders/gpu_glsl_cpp_stubs.hh @@ -835,12 +835,13 @@ uint floatBitsToUint(float) RET; float intBitsToFloat(int) RET; float uintBitsToFloat(uint) RET; -namespace gl_FragmentShader { /* Derivative functions. */ -template T dFdx(T) RET; -template T dFdy(T) RET; -template T fwidth(T) RET; -} // namespace gl_FragmentShader +template T gpu_dfdx(T) RET; +template T gpu_dfdy(T) RET; +template T gpu_fwidth(T) RET; + +/* Discards the output of the current fragment shader invocation and halts its execution. */ +void gpu_discard_fragment() {} /* Geometric functions. */ template VecBase faceforward(VecOp, VecOp, VecOp) RET; @@ -944,9 +945,6 @@ extern const uint gl_LocalInvocationIndex; /* Pass argument by copy (default). */ #define in -/* Discards the output of the current fragment shader invocation and halts its execution. */ -#define discard - /* Decorate a variable in global scope that is common to all threads in a thread-group. */ #define shared diff --git a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl index 9779f4e9c43..192985bf25f 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_line_dashed_frag.glsl @@ -30,7 +30,7 @@ void main() fragColor = color2; } else { - discard; + gpu_discard_fragment(); } } } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl index 614d671cff2..e4bb2afb178 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl @@ -16,7 +16,7 @@ float3 compute_masks(float2 uv) /* Correct aspect ratio for 2D views not using uniform scaling. * uv is already in pixel space so a uniform scale should give us a ratio of 1. */ - float ratio = (butCo != -2.0f) ? abs(dFdy(uv.y) / dFdx(uv.x)) : 1.0f; + float ratio = (butCo != -2.0f) ? abs(gpu_dfdy(uv.y) / gpu_dfdx(uv.x)) : 1.0f; float2 uv_sdf = uv; uv_sdf.x *= ratio; @@ -43,7 +43,7 @@ float3 compute_masks(float2 uv) /* Clamp line width to be at least 1px wide. This can happen if the projection matrix * has been scaled (i.e: Node editor)... */ - float line_width = (lineWidth > 0.0f) ? max(fwidth(uv.y), lineWidth) : 0.0f; + float line_width = (lineWidth > 0.0f) ? max(gpu_fwidth(uv.y), lineWidth) : 0.0f; constexpr float aa_radius = 0.5f; float3 masks; @@ -73,7 +73,7 @@ float4 do_checkerboard() void main() { if (min(1.0f, -butCo) > discardFac) { - discard; + gpu_discard_fragment(); } float3 masks = compute_masks(uvInterp); diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl index 96346bd4afa..4db8cc54059 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl @@ -12,7 +12,7 @@ void main() { #ifdef CLIP if (clip < 0.0f) { - discard; + gpu_discard_fragment(); } #endif fragColor = final_color; diff --git a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl index 7a1ef99d170..339964b0067 100644 --- a/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_codegen_lib.glsl @@ -339,8 +339,8 @@ void dF_branch(float fn, out float2 result) { /* NOTE: this function is currently unused, once it is used we need to check if * `g_derivative_filter_width` needs to be applied. */ - result.x = dFdx(fn); - result.y = dFdy(fn); + result.x = gpu_dfdx(fn); + result.y = gpu_dfdy(fn); } #else @@ -353,10 +353,10 @@ int g_derivative_flag = 0; float3 dF_impl(float3 v) { if (g_derivative_flag > 0) { - return dFdx(v) * g_derivative_filter_width; + return gpu_dfdx(v) * g_derivative_filter_width; } else if (g_derivative_flag < 0) { - return dFdy(v) * g_derivative_filter_width; + return gpu_dfdy(v) * g_derivative_filter_width; } return float3(0.0f); } 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 6d389bc9f26..863e3c347b4 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl @@ -15,7 +15,7 @@ void main() tColor.a = tColor.a * -1.0f; float dist = length(interp.mTexCoord - center); if (dist > 0.25f) { - discard; + gpu_discard_fragment(); } } /* Solid */ diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl index 0a5389ea8b2..e27efd89692 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_stereo_merge_frag.glsl @@ -37,7 +37,7 @@ void main() if (stereo_display_mode == S3D_DISPLAY_INTERLACE && (interlace(texel) == stereo_interlace_swap)) { - discard; + gpu_discard_fragment(); } imageColor = texelFetch(imageTexture, texel, 0); diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl index be23a227418..e9020b6bf96 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_aa_frag.glsl @@ -24,6 +24,6 @@ void main() fragColor.a = mix(color.a, 0.0f, smoothstep(radii[1], radii[0], dist)); if (fragColor.a == 0.0f) { - discard; + gpu_discard_fragment(); } } diff --git a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl index 7e307312562..4d75fef4fde 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl @@ -33,6 +33,6 @@ void main() } if (fragColor.a == 0.0f) { - discard; + gpu_discard_fragment(); } } diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl index 3c28ff083c0..a2fa9ef096c 100644 --- a/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl @@ -14,7 +14,7 @@ void main() /* Round point with jagged edges. */ if (dist_squared > rad_squared) { - discard; + gpu_discard_fragment(); } fragColor = finalColor; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl index 806224684db..3471b1006d2 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_bump.glsl @@ -28,8 +28,8 @@ void node_bump(float strength, dist *= FrontFacing ? invert : -invert; #ifdef GPU_FRAGMENT_SHADER - float3 dPdx = dFdx(g_data.P); - float3 dPdy = dFdy(g_data.P); + float3 dPdx = gpu_dfdx(g_data.P); + float3 dPdy = gpu_dfdy(g_data.P); /* Get surface tangents from normal. */ float3 Rx = cross(dPdy, N); diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl index 4c31cfe6247..5a1f1fa4675 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl @@ -57,8 +57,8 @@ void point_map_to_tube(float3 vin, out float3 vout) void node_tex_image_linear(float3 co, sampler2D ima, out float4 color, out float alpha) { #ifdef GPU_FRAGMENT_SHADER - float2 dx = dFdx(co.xy) * texture_lod_bias_get(); - float2 dy = dFdy(co.xy) * texture_lod_bias_get(); + float2 dx = gpu_dfdx(co.xy) * texture_lod_bias_get(); + float2 dy = gpu_dfdy(co.xy) * texture_lod_bias_get(); color = safe_color(textureGrad(ima, co.xy, dx, dy)); #else diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl index ef80c9ee09c..b1b2a4ab1b5 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_wireframe.glsl @@ -20,8 +20,8 @@ void node_wireframe_screenspace(float size, out float fac) #ifdef GPU_FRAGMENT_SHADER size *= (1.0f / 3.0f); - float3 dx = dFdx(barys); - float3 dy = dFdy(barys); + float3 dx = gpu_dfdx(barys); + float3 dy = gpu_dfdy(barys); float3 deltas = sqrt(dx * dx + dy * dy); float3 s = step(-deltas * size, -barys); diff --git a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl index 6e3496d6d40..a93f8b2e3a9 100644 --- a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl +++ b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl @@ -1165,3 +1165,11 @@ RESHAPE(float3x3, float3x4, m[0].xyz, m[1].xyz, m[2].xyz) #define _enum_end \ } \ ; + +/* Stage agnostic builtin function. + * MSL allow mixing shader stages inside the same source file. + * Leaving the calls untouched makes sure we catch invalid usage during CI testing. */ +#define gpu_discard_fragment() discard +#define gpu_dfdx(x) dFdx(x) +#define gpu_dfdy(x) dFdy(x) +#define gpu_fwidth(x) fwidth(x) diff --git a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl index 68d1bca4f12..4eec04d68ef 100644 --- a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl +++ b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl @@ -160,3 +160,18 @@ RESHAPE(float3x3, mat3x3, mat3x4) #define _enum_type(name) uint #define _enum_decl(name) constexpr uint #define _enum_end _enum_dummy; + +/* Stage agnostic builtin function. + * GLSL doesn't allow mixing shader stages inside the same source file. + * Make sure builtin functions are stubbed when used in an invalid stage. */ +#ifdef GPU_FRAGMENT_SHADER +# define gpu_discard_fragment() discard +# define gpu_dfdx(x) dFdx(x) +# define gpu_dfdy(x) dFdy(x) +# define gpu_fwidth(x) fwidth(x) +#else +# define gpu_discard_fragment() +# define gpu_dfdx(x) x +# define gpu_dfdy(x) x +# define gpu_fwidth(x) x +#endif diff --git a/source/blender/gpu/vulkan/vk_device.cc b/source/blender/gpu/vulkan/vk_device.cc index 154a2e28679..2e3f67666b8 100644 --- a/source/blender/gpu/vulkan/vk_device.cc +++ b/source/blender/gpu/vulkan/vk_device.cc @@ -73,7 +73,10 @@ void VKDevice::deinit() vk_queue_family_ = 0; vk_queue_ = VK_NULL_HANDLE; vk_physical_device_properties_ = {}; - glsl_patch_.clear(); + glsl_vert_patch_.clear(); + glsl_frag_patch_.clear(); + glsl_geom_patch_.clear(); + glsl_comp_patch_.clear(); lifetime = Lifetime::DESTROYED; } @@ -304,14 +307,35 @@ void VKDevice::init_glsl_patch() } /* GLSL Backend Lib. */ - ss << datatoc_glsl_shader_defines_glsl; - glsl_patch_ = ss.str(); + + glsl_vert_patch_ = ss.str() + "#define GPU_VERTEX_SHADER" + datatoc_glsl_shader_defines_glsl; + glsl_geom_patch_ = ss.str() + "#define GPU_GEOMETRY_SHADER" + datatoc_glsl_shader_defines_glsl; + glsl_frag_patch_ = ss.str() + "#define GPU_FRAGMENT_SHADER" + datatoc_glsl_shader_defines_glsl; + glsl_comp_patch_ = ss.str() + "#define GPU_COMPUTE_SHADER" + datatoc_glsl_shader_defines_glsl; } -const char *VKDevice::glsl_patch_get() const +const char *VKDevice::glsl_vertex_patch_get() const { - BLI_assert(!glsl_patch_.empty()); - return glsl_patch_.c_str(); + BLI_assert(!glsl_vert_patch_.empty()); + return glsl_vert_patch_.c_str(); +} + +const char *VKDevice::glsl_geometry_patch_get() const +{ + BLI_assert(!glsl_geom_patch_.empty()); + return glsl_geom_patch_.c_str(); +} + +const char *VKDevice::glsl_fragment_patch_get() const +{ + BLI_assert(!glsl_frag_patch_.empty()); + return glsl_frag_patch_.c_str(); +} + +const char *VKDevice::glsl_compute_patch_get() const +{ + BLI_assert(!glsl_comp_patch_.empty()); + return glsl_comp_patch_.c_str(); } /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/vulkan/vk_device.hh b/source/blender/gpu/vulkan/vk_device.hh index ce82170947f..f7331bfbb26 100644 --- a/source/blender/gpu/vulkan/vk_device.hh +++ b/source/blender/gpu/vulkan/vk_device.hh @@ -208,7 +208,10 @@ class VKDevice : public NonCopyable { VKWorkarounds workarounds_; VKExtensions extensions_; - std::string glsl_patch_; + std::string glsl_vert_patch_; + std::string glsl_geom_patch_; + std::string glsl_frag_patch_; + std::string glsl_comp_patch_; Vector thread_data_; public: @@ -361,7 +364,10 @@ class VKDevice : public NonCopyable { return extensions_; } - const char *glsl_patch_get() const; + const char *glsl_vertex_patch_get() const; + const char *glsl_geometry_patch_get() const; + const char *glsl_fragment_patch_get() const; + const char *glsl_compute_patch_get() const; void init_glsl_patch(); /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index e23e8f2fb7b..0b36e6be1b7 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -533,15 +533,29 @@ void VKShader::build_shader_module(MutableSpan sources, shaderc_shader_kind stage, VKShaderModule &r_shader_module) { - BLI_assert_msg(ELEM(stage, - shaderc_vertex_shader, - shaderc_geometry_shader, - shaderc_fragment_shader, - shaderc_compute_shader), - "Only forced ShaderC shader kinds are supported."); r_shader_module.is_ready = false; const VKDevice &device = VKBackend::get().device; - sources[SOURCES_INDEX_VERSION] = device.glsl_patch_get(); + const char *source_patch = nullptr; + + switch (stage) { + case shaderc_vertex_shader: + source_patch = device.glsl_vertex_patch_get(); + break; + case shaderc_geometry_shader: + source_patch = device.glsl_geometry_patch_get(); + break; + case shaderc_fragment_shader: + source_patch = device.glsl_fragment_patch_get(); + break; + case shaderc_compute_shader: + source_patch = device.glsl_compute_patch_get(); + break; + default: + BLI_assert_msg(0, "Only forced ShaderC shader kinds are supported."); + break; + } + + sources[SOURCES_INDEX_VERSION] = source_patch; r_shader_module.combined_sources = combine_sources(sources); if (!use_batch_compilation_) { VKShaderCompiler::compile_module(*this, stage, r_shader_module);