diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 7a39e6ffda3..b2101662969 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -105,9 +105,10 @@ if(WITH_VULKAN_BACKEND) set(VULKAN_ROOT_DIR ${LIBDIR}/vulkan/macOS) set(VULKAN_INCLUDE_DIR ${VULKAN_ROOT_DIR}/include) set(VULKAN_LIBRARY ${VULKAN_ROOT_DIR}/lib/libvulkan.1.dylib) + set(SHADERC_LIBRARY ${VULKAN_ROOT_DIR}/lib/libshaderc_combined.a) set(VULKAN_INCLUDE_DIRS ${VULKAN_INCLUDE_DIR} ${MOLTENVK_INCLUDE_DIRS}) - set(VULKAN_LIBRARIES ${VULKAN_LIBRARY} ${MOLTENVK_LIBRARIES}) + set(VULKAN_LIBRARIES ${VULKAN_LIBRARY} ${SHADERC_LIBRARY} ${MOLTENVK_LIBRARIES}) else() message(WARNING "Vulkan SDK was not found, disabling WITH_VULKAN_BACKEND") set(WITH_VULKAN_BACKEND OFF) diff --git a/source/blender/compositor/realtime_compositor/shaders/compositor_screen_lens_distortion.glsl b/source/blender/compositor/realtime_compositor/shaders/compositor_screen_lens_distortion.glsl index dc572ea5aaf..58c1d97e81d 100644 --- a/source/blender/compositor/realtime_compositor/shaders/compositor_screen_lens_distortion.glsl +++ b/source/blender/compositor/realtime_compositor/shaders/compositor_screen_lens_distortion.glsl @@ -20,9 +20,9 @@ vec3 compute_chromatic_distortion_scale(float distance_squared) /* Compute the image coordinates after distortion by the given distortion scale computed by the * compute_distortion_scale function. Note that the function expects centered normalized UV * coordinates but outputs non-centered image coordinates. */ -vec2 compute_distorted_uv(vec2 uv, float scale) +vec2 compute_distorted_uv(vec2 uv, float uv_scale) { - return (uv * scale + 0.5) * texture_size(input_tx) - 0.5; + return (uv * uv_scale + 0.5) * texture_size(input_tx) - 0.5; } /* Compute the number of integration steps that should be used to approximate the distorted pixel diff --git a/source/blender/compositor/realtime_compositor/shaders/library/gpu_shader_compositor_texture_utilities.glsl b/source/blender/compositor/realtime_compositor/shaders/library/gpu_shader_compositor_texture_utilities.glsl index 128fc6aeaf5..cd99e16add6 100644 --- a/source/blender/compositor/realtime_compositor/shaders/library/gpu_shader_compositor_texture_utilities.glsl +++ b/source/blender/compositor/realtime_compositor/shaders/library/gpu_shader_compositor_texture_utilities.glsl @@ -1,35 +1,35 @@ /* A shorthand for 1D textureSize with a zero LOD. */ -int texture_size(sampler1D sampler) +int texture_size(sampler1D sampler_1d) { - return textureSize(sampler, 0); + return textureSize(sampler_1d, 0); } /* A shorthand for 1D texelFetch with zero LOD and bounded access clamped to border. */ -vec4 texture_load(sampler1D sampler, int x) +vec4 texture_load(sampler1D sampler_1d, int x) { - const int texture_bound = texture_size(sampler) - 1; - return texelFetch(sampler, clamp(x, 0, texture_bound), 0); + const int texture_bound = texture_size(sampler_1d) - 1; + return texelFetch(sampler_1d, clamp(x, 0, texture_bound), 0); } /* A shorthand for 2D textureSize with a zero LOD. */ -ivec2 texture_size(sampler2D sampler) +ivec2 texture_size(sampler2D sampler_2d) { - return textureSize(sampler, 0); + return textureSize(sampler_2d, 0); } /* A shorthand for 2D texelFetch with zero LOD and bounded access clamped to border. */ -vec4 texture_load(sampler2D sampler, ivec2 texel) +vec4 texture_load(sampler2D sampler_2d, ivec2 texel) { - const ivec2 texture_bounds = texture_size(sampler) - ivec2(1); - return texelFetch(sampler, clamp(texel, ivec2(0), texture_bounds), 0); + const ivec2 texture_bounds = texture_size(sampler_2d) - ivec2(1); + return texelFetch(sampler_2d, clamp(texel, ivec2(0), texture_bounds), 0); } /* A shorthand for 2D texelFetch with zero LOD and a fallback value for out-of-bound access. */ -vec4 texture_load(sampler2D sampler, ivec2 texel, vec4 fallback) +vec4 texture_load(sampler2D sampler_2d, ivec2 texel, vec4 fallback) { - const ivec2 texture_bounds = texture_size(sampler) - ivec2(1); + const ivec2 texture_bounds = texture_size(sampler_2d) - ivec2(1); if (any(lessThan(texel, ivec2(0))) || any(greaterThan(texel, texture_bounds))) { return fallback; } - return texelFetch(sampler, texel, 0); + return texelFetch(sampler_2d, texel, 0); } diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index fca8737f661..55d3921e39b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -9,7 +9,9 @@ * dragging larger headers into the createInfo pipeline which would cause problems. */ -#pragma once +#ifndef GPU_SHADER +# pragma once +#endif /* Hierarchical Z down-sampling. */ #define HIZ_MIP_COUNT 8 diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl index 88737ade386..33aefb7f76d 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_depth_of_field_tiles_flatten_comp.glsl @@ -26,7 +26,7 @@ shared uint bg_min_coc; shared uint bg_max_coc; shared uint bg_min_intersectable_coc; -const uint dof_tile_large_coc_uint = floatBitsToUint(dof_tile_large_coc); +uint dof_tile_large_coc_uint = floatBitsToUint(dof_tile_large_coc); void main() { diff --git a/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl index 50c24de0838..331dcdf6519 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl @@ -13,8 +13,12 @@ vec2 proj(vec4 pos) return (0.5 * (pos.xy / pos.w) + 0.5) * sizeViewport.xy; } -#define SET_INTENSITY(A, B, C, min, max) \ - (((1.0 - (float(C - B) / float(C - A))) * (max - min)) + min) +float calc_intensity(int segment_start, int segment_current, int segment_end, float min, float max) +{ + return ((1.0 - (float(segment_end - segment_current) / float(segment_end - segment_start))) * + (max - min)) + + min; +} void main() { @@ -39,10 +43,10 @@ void main() else { /* black - before frameCurrent */ if (selected) { - intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.25, 0.75); + intensity = calc_intensity(frameStart, frame, frameCurrent, 0.25, 0.75); } else { - intensity = SET_INTENSITY(frameStart, frame, frameCurrent, 0.68, 0.92); + intensity = calc_intensity(frameStart, frame, frameCurrent, 0.68, 0.92); } interp.color.rgb = mix(colorWire.rgb, blend_base, intensity); } @@ -55,10 +59,10 @@ void main() else { /* blue - after frameCurrent */ if (selected) { - intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.25, 0.75); + intensity = calc_intensity(frameCurrent, frame, frameEnd, 0.25, 0.75); } else { - intensity = SET_INTENSITY(frameCurrent, frame, frameEnd, 0.68, 0.92); + intensity = calc_intensity(frameCurrent, frame, frameEnd, 0.68, 0.92); } interp.color.rgb = mix(colorBonePose.rgb, blend_base, intensity); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl index a220434ec45..fa4d5ef4d96 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_vert.glsl @@ -5,5 +5,6 @@ void main() { vData.pos = pos; vData.frontPosition = point_object_to_ndc(pos); - vData.backPosition = point_object_to_ndc(pos + lightDirection * lightDistance); + vec3 back_pos = pos + lightDirection * lightDistance; + vData.backPosition = point_object_to_ndc(back_pos); } diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl index 0c040c9acfe..1b8a8202166 100644 --- a/source/blender/draw/intern/shaders/common_smaa_lib.glsl +++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl @@ -569,7 +569,7 @@ SamplerState PointSampler # define SMAAGather(tex, coord) tex.Gather(LinearSampler, coord, 0) # endif #endif -#if defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4) || defined(GPU_METAL) +#if defined(SMAA_GLSL_3) || defined(SMAA_GLSL_4) || defined(GPU_METAL) || defined(GPU_VULKAN) # define SMAATexture2D(tex) sampler2D tex # define SMAATexturePass2D(tex) tex # define SMAASampleLevelZero(tex, coord) textureLod(tex, coord, 0.0) @@ -583,8 +583,28 @@ SamplerState PointSampler # define lerp(a, b, t) mix(a, b, t) # define saturate(a) clamp(a, 0.0, 1.0) # if defined(SMAA_GLSL_4) -# define mad(a, b, c) fma(a, b, c) # define SMAAGather(tex, coord) textureGather(tex, coord) +# endif +# if defined(SMAA_GLSL_4) +# define mad(a, b, c) fma(a, b, c) +# elif defined(GPU_VULKAN) +/* NOTE(Vulkan) mad macro doesn't work, define each override as work-around. */ +vec4 mad(vec4 a, vec4 b, vec4 c) +{ + return fma(a, b, c); +} +vec3 mad(vec3 a, vec3 b, vec3 c) +{ + return fma(a, b, c); +} +vec2 mad(vec2 a, vec2 b, vec2 c) +{ + return fma(a, b, c); +} +float mad(float a, float b, float c) +{ + return fma(a, b, c); +} # else # define mad(a, b, c) (a * b + c) # endif diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index d6985f86ddc..53ef194b4f5 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -234,12 +234,28 @@ uniform mat4 ModelMatrixInverse; (ProjectionMatrix * (ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0))) #define point_object_to_view(p) ((ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)).xyz) #define point_object_to_world(p) ((ModelMatrix * vec4(p, 1.0)).xyz) -#define point_view_to_ndc(p) (ProjectionMatrix * vec4(p, 1.0)) #define point_view_to_object(p) ((ModelMatrixInverse * (ViewMatrixInverse * vec4(p, 1.0))).xyz) -#define point_view_to_world(p) ((ViewMatrixInverse * vec4(p, 1.0)).xyz) -#define point_world_to_ndc(p) (ProjectionMatrix * (ViewMatrix * vec4(p, 1.0))) #define point_world_to_object(p) ((ModelMatrixInverse * vec4(p, 1.0)).xyz) -#define point_world_to_view(p) ((ViewMatrix * vec4(p, 1.0)).xyz) + +vec4 point_view_to_ndc(vec3 p) +{ + return ProjectionMatrix * vec4(p, 1.0); +} + +vec3 point_view_to_world(vec3 p) +{ + return (ViewMatrixInverse * vec4(p, 1.0)).xyz; +} + +vec4 point_world_to_ndc(vec3 p) +{ + return ProjectionMatrix * (ViewMatrix * vec4(p, 1.0)); +} + +vec3 point_world_to_view(vec3 p) +{ + return (ViewMatrix * vec4(p, 1.0)).xyz; +} /* Due to some shader compiler bug, we somewhat need to access gl_VertexID * to make vertex shaders work. even if it's actually dead code. */ diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 86a38c02efc..9f9d216064a 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -43,6 +43,7 @@ set(INC set(INC_SYS ${Epoxy_INCLUDE_DIRS} + ${VULKAN_INCLUDE_DIRS} ) set(SRC @@ -197,6 +198,7 @@ set(VULKAN_SRC vulkan/vk_pixel_buffer.cc vulkan/vk_query.cc vulkan/vk_shader.cc + vulkan/vk_shader_log.cc vulkan/vk_storage_buffer.cc vulkan/vk_texture.cc vulkan/vk_uniform_buffer.cc @@ -212,6 +214,7 @@ set(VULKAN_SRC vulkan/vk_pixel_buffer.hh vulkan/vk_query.hh vulkan/vk_shader.hh + vulkan/vk_shader_log.hh vulkan/vk_storage_buffer.hh vulkan/vk_texture.hh vulkan/vk_uniform_buffer.hh @@ -275,6 +278,7 @@ endif() set(LIB ${Epoxy_LIBRARIES} + ${VULKAN_LIBRARIES} ) if(WITH_VULKAN_BACKEND) diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 7f2a81c8141..0653ae11a0a 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -98,6 +98,9 @@ static void standard_defines(Vector &sources) case GPU_BACKEND_METAL: sources.append("#define GPU_METAL\n"); break; + case GPU_BACKEND_VULKAN: + sources.append("#define GPU_VULKAN\n"); + break; default: BLI_assert(false && "Invalid GPU Backend Type"); break; diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc index 96e3eacd6f5..61cf95c6d17 100644 --- a/source/blender/gpu/intern/gpu_shader_builder.cc +++ b/source/blender/gpu/intern/gpu_shader_builder.cc @@ -54,6 +54,12 @@ void ShaderBuilder::init() break; #endif +#ifdef WITH_VULKAN_BACKEND + case GPU_BACKEND_VULKAN: + glSettings.context_type = GHOST_kDrawingContextTypeVulkan; + break; +#endif + default: BLI_assert_unreachable(); break; @@ -100,6 +106,9 @@ int main(int argc, const char *argv[]) backends_to_validate.append({"OpenGL", GPU_BACKEND_OPENGL}); #ifdef WITH_METAL_BACKEND backends_to_validate.append({"Metal", GPU_BACKEND_METAL}); +#endif +#ifdef WITH_VULKAN_BACKEND + backends_to_validate.append({"Vulkan", GPU_BACKEND_VULKAN}); #endif for (NamedBackend &backend : backends_to_validate) { GPU_backend_type_selection_set(backend.backend); @@ -114,6 +123,9 @@ int main(int argc, const char *argv[]) printf("Shader compilation failed for %s backend\n", backend.name.c_str()); exit_code = 1; } + else { + printf("%s backend shader compilation succeeded.\n", backend.name.c_str()); + } builder.exit(); } diff --git a/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl b/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl index 3edf0e31799..35f1c7a2427 100644 --- a/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_cfg_world_clip_lib.glsl @@ -1,40 +1,25 @@ #ifdef USE_WORLD_CLIP_PLANES # if defined(GPU_VERTEX_SHADER) || defined(GPU_GEOMETRY_SHADER) -# ifndef USE_GPU_SHADER_CREATE_INFO -uniform vec4 WorldClipPlanes[6]; -# endif - -# define _world_clip_planes_calc_clip_distance(wpos, _clipplanes) \ - { \ - vec4 _pos = vec4(wpos, 1.0); \ - gl_ClipDistance[0] = dot(_clipplanes[0], _pos); \ - gl_ClipDistance[1] = dot(_clipplanes[1], _pos); \ - gl_ClipDistance[2] = dot(_clipplanes[2], _pos); \ - gl_ClipDistance[3] = dot(_clipplanes[3], _pos); \ - gl_ClipDistance[4] = dot(_clipplanes[4], _pos); \ - gl_ClipDistance[5] = dot(_clipplanes[5], _pos); \ - } - /* When all shaders are builtin shaders are migrated this could be applied directly. */ # ifdef USE_GPU_SHADER_CREATE_INFO # define WorldClipPlanes clipPlanes.world +# else +uniform vec4 WorldClipPlanes[6]; # endif -/* HACK Dirty hack to be able to override the definition in common_view_lib.glsl. - * Not doing this would require changing the include order in every shaders. */ -# define world_clip_planes_calc_clip_distance(wpos) \ - _world_clip_planes_calc_clip_distance(wpos, WorldClipPlanes) + +void world_clip_planes_calc_clip_distance(vec3 wpos) +{ + vec4 pos = vec4(wpos, 1.0); + + gl_ClipDistance[0] = dot(WorldClipPlanes[0], pos); + gl_ClipDistance[1] = dot(WorldClipPlanes[1], pos); + gl_ClipDistance[2] = dot(WorldClipPlanes[2], pos); + gl_ClipDistance[3] = dot(WorldClipPlanes[3], pos); + gl_ClipDistance[4] = dot(WorldClipPlanes[4], pos); + gl_ClipDistance[5] = dot(WorldClipPlanes[5], pos); +} # endif -# define world_clip_planes_set_clip_distance(c) \ - { \ - gl_ClipDistance[0] = (c)[0]; \ - gl_ClipDistance[1] = (c)[1]; \ - gl_ClipDistance[2] = (c)[2]; \ - gl_ClipDistance[3] = (c)[3]; \ - gl_ClipDistance[4] = (c)[4]; \ - gl_ClipDistance[5] = (c)[5]; \ - } - #endif diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index b0212012fdf..b402ef2f503 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -5,6 +5,7 @@ * \ingroup gpu */ +#include "gpu_capabilities_private.hh" #include "gpu_platform_private.hh" #include "vk_batch.hh" @@ -144,4 +145,18 @@ void VKBackend::render_step() { } +shaderc::Compiler &VKBackend::get_shaderc_compiler() +{ + return shaderc_compiler_; +} + +void VKBackend::capabilities_init(VKContext &context) +{ + /* Reset all capabilities from previous context. */ + GCaps = {}; + GCaps.compute_shader_support = true; + GCaps.shader_storage_buffer_objects_support = true; + GCaps.shader_image_load_store_support = true; +} + } // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_backend.hh b/source/blender/gpu/vulkan/vk_backend.hh index c78788298a5..4c6312ed682 100644 --- a/source/blender/gpu/vulkan/vk_backend.hh +++ b/source/blender/gpu/vulkan/vk_backend.hh @@ -9,9 +9,21 @@ #include "gpu_backend.hh" +#ifdef __APPLE__ +# include +#else +# include +#endif +#include "shaderc/shaderc.hpp" + namespace blender::gpu { +class VKContext; + class VKBackend : public GPUBackend { + private: + shaderc::Compiler shaderc_compiler_; + public: VKBackend() { @@ -50,6 +62,10 @@ class VKBackend : public GPUBackend { void render_end() override; void render_step() override; + shaderc::Compiler &get_shaderc_compiler(); + + static void capabilities_init(VKContext &context); + private: static void init_platform(); static void platform_exit(); diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index 0bf2d29e124..6013b5eb95c 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -7,6 +7,8 @@ #include "vk_context.hh" +#include "vk_backend.hh" + #include "GHOST_C-api.h" namespace blender::gpu { @@ -32,6 +34,8 @@ VKContext::VKContext(void *ghost_window, void *ghost_context) info.device = device_; info.instance = instance_; vmaCreateAllocator(&info, &mem_allocator_); + + VKBackend::capabilities_init(*this); } VKContext::~VKContext() diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index 7c83548536d..56d39169538 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -47,6 +47,16 @@ class VKContext : public Context { void debug_group_begin(const char *, int) override; void debug_group_end() override; + static VKContext *get(void) + { + return static_cast(Context::get()); + } + + VkDevice device_get() const + { + return device_; + } + VmaAllocator mem_allocator_get() const { return mem_allocator_; diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index d628f3eb851..40408759679 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -7,26 +7,679 @@ #include "vk_shader.hh" +#include "vk_backend.hh" +#include "vk_shader_log.hh" + +#include "BLI_string_utils.h" +#include "BLI_vector.hh" + +using namespace blender::gpu::shader; + +extern "C" char datatoc_glsl_shader_defines_glsl[]; + namespace blender::gpu { -void VKShader::vertex_shader_from_glsl(MutableSpan /*sources*/) + +/* -------------------------------------------------------------------- */ +/** \name Create Info + * \{ */ + +static const char *to_string(const Interpolation &interp) { + switch (interp) { + case Interpolation::SMOOTH: + return "smooth"; + case Interpolation::FLAT: + return "flat"; + case Interpolation::NO_PERSPECTIVE: + return "noperspective"; + default: + return "unknown"; + } } -void VKShader::geometry_shader_from_glsl(MutableSpan /*sources*/) +static const char *to_string(const Type &type) { + switch (type) { + case Type::FLOAT: + return "float"; + case Type::VEC2: + return "vec2"; + case Type::VEC3: + return "vec3"; + case Type::VEC4: + return "vec4"; + case Type::MAT3: + return "mat3"; + case Type::MAT4: + return "mat4"; + case Type::UINT: + return "uint"; + case Type::UVEC2: + return "uvec2"; + case Type::UVEC3: + return "uvec3"; + case Type::UVEC4: + return "uvec4"; + case Type::INT: + return "int"; + case Type::IVEC2: + return "ivec2"; + case Type::IVEC3: + return "ivec3"; + case Type::IVEC4: + return "ivec4"; + case Type::BOOL: + return "bool"; + default: + return "unknown"; + } } -void VKShader::fragment_shader_from_glsl(MutableSpan /*sources*/) +static const char *to_string(const eGPUTextureFormat &type) { + switch (type) { + case GPU_RGBA8UI: + return "rgba8ui"; + case GPU_RGBA8I: + return "rgba8i"; + case GPU_RGBA8: + return "rgba8"; + case GPU_RGBA32UI: + return "rgba32ui"; + case GPU_RGBA32I: + return "rgba32i"; + case GPU_RGBA32F: + return "rgba32f"; + case GPU_RGBA16UI: + return "rgba16ui"; + case GPU_RGBA16I: + return "rgba16i"; + case GPU_RGBA16F: + return "rgba16f"; + case GPU_RGBA16: + return "rgba16"; + case GPU_RG8UI: + return "rg8ui"; + case GPU_RG8I: + return "rg8i"; + case GPU_RG8: + return "rg8"; + case GPU_RG32UI: + return "rg32ui"; + case GPU_RG32I: + return "rg32i"; + case GPU_RG32F: + return "rg32f"; + case GPU_RG16UI: + return "rg16ui"; + case GPU_RG16I: + return "rg16i"; + case GPU_RG16F: + return "rg16f"; + case GPU_RG16: + return "rg16"; + case GPU_R8UI: + return "r8ui"; + case GPU_R8I: + return "r8i"; + case GPU_R8: + return "r8"; + case GPU_R32UI: + return "r32ui"; + case GPU_R32I: + return "r32i"; + case GPU_R32F: + return "r32f"; + case GPU_R16UI: + return "r16ui"; + case GPU_R16I: + return "r16i"; + case GPU_R16F: + return "r16f"; + case GPU_R16: + return "r16"; + case GPU_R11F_G11F_B10F: + return "r11f_g11f_b10f"; + case GPU_RGB10_A2: + return "rgb10_a2"; + default: + return "unknown"; + } } -void VKShader::compute_shader_from_glsl(MutableSpan /*sources*/) +static const char *to_string(const PrimitiveIn &layout) { + switch (layout) { + case PrimitiveIn::POINTS: + return "points"; + case PrimitiveIn::LINES: + return "lines"; + case PrimitiveIn::LINES_ADJACENCY: + return "lines_adjacency"; + case PrimitiveIn::TRIANGLES: + return "triangles"; + case PrimitiveIn::TRIANGLES_ADJACENCY: + return "triangles_adjacency"; + default: + return "unknown"; + } +} + +static const char *to_string(const PrimitiveOut &layout) +{ + switch (layout) { + case PrimitiveOut::POINTS: + return "points"; + case PrimitiveOut::LINE_STRIP: + return "line_strip"; + case PrimitiveOut::TRIANGLE_STRIP: + return "triangle_strip"; + default: + return "unknown"; + } +} + +static const char *to_string(const DepthWrite &value) +{ + switch (value) { + case DepthWrite::ANY: + return "depth_any"; + case DepthWrite::GREATER: + return "depth_greater"; + case DepthWrite::LESS: + return "depth_less"; + default: + return "depth_unchanged"; + } +} + +static void print_image_type(std::ostream &os, + const ImageType &type, + const ShaderCreateInfo::Resource::BindType bind_type) +{ + switch (type) { + case ImageType::INT_BUFFER: + case ImageType::INT_1D: + case ImageType::INT_1D_ARRAY: + case ImageType::INT_2D: + case ImageType::INT_2D_ARRAY: + case ImageType::INT_3D: + case ImageType::INT_CUBE: + case ImageType::INT_CUBE_ARRAY: + os << "i"; + break; + case ImageType::UINT_BUFFER: + case ImageType::UINT_1D: + case ImageType::UINT_1D_ARRAY: + case ImageType::UINT_2D: + case ImageType::UINT_2D_ARRAY: + case ImageType::UINT_3D: + case ImageType::UINT_CUBE: + case ImageType::UINT_CUBE_ARRAY: + os << "u"; + break; + default: + break; + } + + if (bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { + os << "image"; + } + else { + os << "sampler"; + } + + switch (type) { + case ImageType::FLOAT_BUFFER: + case ImageType::INT_BUFFER: + case ImageType::UINT_BUFFER: + os << "Buffer"; + break; + case ImageType::FLOAT_1D: + case ImageType::FLOAT_1D_ARRAY: + case ImageType::INT_1D: + case ImageType::INT_1D_ARRAY: + case ImageType::UINT_1D: + case ImageType::UINT_1D_ARRAY: + os << "1D"; + break; + case ImageType::FLOAT_2D: + case ImageType::FLOAT_2D_ARRAY: + case ImageType::INT_2D: + case ImageType::INT_2D_ARRAY: + case ImageType::UINT_2D: + case ImageType::UINT_2D_ARRAY: + case ImageType::SHADOW_2D: + case ImageType::SHADOW_2D_ARRAY: + case ImageType::DEPTH_2D: + case ImageType::DEPTH_2D_ARRAY: + os << "2D"; + break; + case ImageType::FLOAT_3D: + case ImageType::INT_3D: + case ImageType::UINT_3D: + os << "3D"; + break; + case ImageType::FLOAT_CUBE: + case ImageType::FLOAT_CUBE_ARRAY: + case ImageType::INT_CUBE: + case ImageType::INT_CUBE_ARRAY: + case ImageType::UINT_CUBE: + case ImageType::UINT_CUBE_ARRAY: + case ImageType::SHADOW_CUBE: + case ImageType::SHADOW_CUBE_ARRAY: + case ImageType::DEPTH_CUBE: + case ImageType::DEPTH_CUBE_ARRAY: + os << "Cube"; + break; + default: + break; + } + + switch (type) { + case ImageType::FLOAT_1D_ARRAY: + case ImageType::FLOAT_2D_ARRAY: + case ImageType::FLOAT_CUBE_ARRAY: + case ImageType::INT_1D_ARRAY: + case ImageType::INT_2D_ARRAY: + case ImageType::INT_CUBE_ARRAY: + case ImageType::UINT_1D_ARRAY: + case ImageType::UINT_2D_ARRAY: + case ImageType::UINT_CUBE_ARRAY: + case ImageType::SHADOW_2D_ARRAY: + case ImageType::SHADOW_CUBE_ARRAY: + case ImageType::DEPTH_2D_ARRAY: + case ImageType::DEPTH_CUBE_ARRAY: + os << "Array"; + break; + default: + break; + } + + switch (type) { + case ImageType::SHADOW_2D: + case ImageType::SHADOW_2D_ARRAY: + case ImageType::SHADOW_CUBE: + case ImageType::SHADOW_CUBE_ARRAY: + os << "Shadow"; + break; + default: + break; + } + os << " "; +} + +static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifiers) +{ + if (bool(qualifiers & Qualifier::NO_RESTRICT) == false) { + os << "restrict "; + } + if (bool(qualifiers & Qualifier::READ) == false) { + os << "writeonly "; + } + if (bool(qualifiers & Qualifier::WRITE) == false) { + os << "readonly "; + } + return os; +} + +static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res) +{ + os << "layout(binding = " << res.slot; + if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { + os << ", " << to_string(res.image.format); + } + else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { + os << ", std140"; + } + else if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { + os << ", std430"; + } + os << ") "; + + int64_t array_offset; + StringRef name_no_array; + + switch (res.bind_type) { + case ShaderCreateInfo::Resource::BindType::SAMPLER: + os << "uniform "; + print_image_type(os, res.sampler.type, res.bind_type); + os << res.sampler.name << ";\n"; + break; + case ShaderCreateInfo::Resource::BindType::IMAGE: + os << "uniform "; + print_qualifier(os, res.image.qualifiers); + print_image_type(os, res.image.type, res.bind_type); + os << res.image.name << ";\n"; + break; + case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: + array_offset = res.uniformbuf.name.find_first_of("["); + name_no_array = (array_offset == -1) ? res.uniformbuf.name : + StringRef(res.uniformbuf.name.c_str(), array_offset); + os << "uniform " << name_no_array << " { " << res.uniformbuf.type_name << " _" + << res.uniformbuf.name << "; };\n"; + break; + case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: + array_offset = res.storagebuf.name.find_first_of("["); + name_no_array = (array_offset == -1) ? res.storagebuf.name : + StringRef(res.storagebuf.name.c_str(), array_offset); + print_qualifier(os, res.storagebuf.qualifiers); + os << "buffer "; + os << name_no_array << " { " << res.storagebuf.type_name << " _" << res.storagebuf.name + << "; };\n"; + break; + } +} + +static void print_resource_alias(std::ostream &os, const ShaderCreateInfo::Resource &res) +{ + int64_t array_offset; + StringRef name_no_array; + + switch (res.bind_type) { + case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: + array_offset = res.uniformbuf.name.find_first_of("["); + name_no_array = (array_offset == -1) ? res.uniformbuf.name : + StringRef(res.uniformbuf.name.c_str(), array_offset); + os << "#define " << name_no_array << " (_" << name_no_array << ")\n"; + break; + case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: + array_offset = res.storagebuf.name.find_first_of("["); + name_no_array = (array_offset == -1) ? res.storagebuf.name : + StringRef(res.storagebuf.name.c_str(), array_offset); + os << "#define " << name_no_array << " (_" << name_no_array << ")\n"; + break; + default: + break; + } +} + +inline int get_location_count(const Type &type) +{ + if (type == shader::Type::MAT4) { + return 4; + } + else if (type == shader::Type::MAT3) { + return 3; + } + return 1; +} + +static void print_interface(std::ostream &os, + const std::string &prefix, + const StageInterfaceInfo &iface, + int &location, + const StringRefNull &suffix = "") +{ + if (iface.instance_name.is_empty()) { + for (const StageInterfaceInfo::InOut &inout : iface.inouts) { + os << "layout(location=" << location << ") " << prefix << " " << to_string(inout.interp) + << " " << to_string(inout.type) << " " << inout.name << ";\n"; + location += get_location_count(inout.type); + } + } + else { + std::string struct_name = prefix + iface.name; + std::string iface_attribute; + if (iface.instance_name.is_empty()) { + iface_attribute = "iface_"; + } + else { + iface_attribute = iface.instance_name; + } + std::string flat = ""; + if (prefix == "in") { + flat = "flat "; + } + const bool add_defines = iface.instance_name.is_empty(); + + os << "struct " << struct_name << " {\n"; + for (const StageInterfaceInfo::InOut &inout : iface.inouts) { + os << " " << to_string(inout.type) << " " << inout.name << ";\n"; + } + os << "};\n"; + os << "layout(location=" << location << ") " << prefix << " " << flat << struct_name << " " + << iface_attribute << suffix << ";\n"; + + if (add_defines) { + for (const StageInterfaceInfo::InOut &inout : iface.inouts) { + os << "#define " << inout.name << " (" << iface_attribute << "." << inout.name << ")\n"; + } + } + + for (const StageInterfaceInfo::InOut &inout : iface.inouts) { + location += get_location_count(inout.type); + } + } +} + +/** \} */ +static std::string main_function_wrapper(std::string &pre_main, std::string &post_main) +{ + std::stringstream ss; + /* Prototype for the original main. */ + ss << "\n"; + ss << "void main_function_();\n"; + /* Wrapper to the main function in order to inject code processing on globals. */ + ss << "void main() {\n"; + ss << pre_main; + ss << " main_function_();\n"; + ss << post_main; + ss << "}\n"; + /* Rename the original main. */ + ss << "#define main main_function_\n"; + ss << "\n"; + return ss.str(); +} + +static const std::string to_stage_name(shaderc_shader_kind stage) +{ + switch (stage) { + case shaderc_vertex_shader: + return std::string("vertex"); + case shaderc_geometry_shader: + return std::string("geometry"); + case shaderc_fragment_shader: + return std::string("fragment"); + case shaderc_compute_shader: + return std::string("compute"); + + default: + BLI_assert_msg(false, "Do not know how to convert shaderc_shader_kind to stage name."); + break; + } + return std::string("unknown stage"); +} + +static char *glsl_patch_get() +{ + static char patch[2048] = "\0"; + if (patch[0] != '\0') { + return patch; + } + + size_t slen = 0; + /* Version need to go first. */ + STR_CONCAT(patch, slen, "#version 450\n"); + STR_CONCAT(patch, slen, "#define gl_VertexID gl_VertexIndex\n"); + STR_CONCAT(patch, slen, "#define gpu_BaseInstance (0)\n"); + STR_CONCAT(patch, slen, "#define gpu_InstanceIndex (gl_InstanceIndex)\n"); + STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n"); + + STR_CONCAT(patch, slen, "#define gl_InstanceID gpu_InstanceIndex\n"); + + STR_CONCAT(patch, slen, "#define DFDX_SIGN 1.0\n"); + STR_CONCAT(patch, slen, "#define DFDY_SIGN 1.0\n"); + + /* GLSL Backend Lib. */ + STR_CONCAT(patch, slen, datatoc_glsl_shader_defines_glsl); + + BLI_assert(slen < sizeof(patch)); + return patch; +} + +static std::string combine_sources(Span sources) +{ + char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size()); + return std::string(sources_combined); +} + +Vector VKShader::compile_glsl_to_spirv(Span sources, + shaderc_shader_kind stage) +{ + std::string combined_sources = combine_sources(sources); + VKBackend &backend = static_cast(*VKBackend::get()); + shaderc::Compiler &compiler = backend.get_shaderc_compiler(); + shaderc::CompileOptions options; + options.SetOptimizationLevel(shaderc_optimization_level_performance); + + shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv( + combined_sources, stage, name, options); + if (module.GetNumErrors() != 0 || module.GetNumWarnings() != 0) { + std::string log = module.GetErrorMessage(); + Vector logcstr(log.c_str(), log.c_str() + log.size() + 1); + + VKLogParser parser; + print_log(sources, + logcstr.data(), + to_stage_name(stage).c_str(), + module.GetCompilationStatus() != shaderc_compilation_status_success, + &parser); + } + + if (module.GetCompilationStatus() != shaderc_compilation_status_success) { + compilation_failed_ = true; + return Vector(); + } + + return Vector(module.cbegin(), module.cend()); +} + +void VKShader::build_shader_module(Span spirv_module, VkShaderModule *r_shader_module) +{ + VkShaderModuleCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + create_info.codeSize = spirv_module.size() * sizeof(uint32_t); + create_info.pCode = spirv_module.data(); + + VKContext &context = *static_cast(VKContext::get()); + + VkResult result = vkCreateShaderModule( + context.device_get(), &create_info, nullptr, r_shader_module); + if (result != VK_SUCCESS) { + compilation_failed_ = true; + *r_shader_module = VK_NULL_HANDLE; + } +} + +VKShader::VKShader(const char *name) : Shader(name) +{ + context_ = VKContext::get(); +} + +VKShader::~VKShader() +{ + VkDevice device = context_->device_get(); + if (vertex_module_ != VK_NULL_HANDLE) { + vkDestroyShaderModule(device, vertex_module_, nullptr); + vertex_module_ = VK_NULL_HANDLE; + } + if (geometry_module_ != VK_NULL_HANDLE) { + vkDestroyShaderModule(device, geometry_module_, nullptr); + geometry_module_ = VK_NULL_HANDLE; + } + if (fragment_module_ != VK_NULL_HANDLE) { + vkDestroyShaderModule(device, fragment_module_, nullptr); + fragment_module_ = VK_NULL_HANDLE; + } + if (compute_module_ != VK_NULL_HANDLE) { + vkDestroyShaderModule(device, compute_module_, nullptr); + compute_module_ = VK_NULL_HANDLE; + } +} + +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."); + sources[0] = glsl_patch_get(); + Vector spirv_module = compile_glsl_to_spirv(sources, stage); + build_shader_module(spirv_module, &compute_module_); +} + +void VKShader::vertex_shader_from_glsl(MutableSpan sources) +{ + build_shader_module(sources, shaderc_vertex_shader, &vertex_module_); +} + +void VKShader::geometry_shader_from_glsl(MutableSpan sources) +{ + build_shader_module(sources, shaderc_geometry_shader, &geometry_module_); +} + +void VKShader::fragment_shader_from_glsl(MutableSpan sources) +{ + build_shader_module(sources, shaderc_fragment_shader, &fragment_module_); +} + +void VKShader::compute_shader_from_glsl(MutableSpan sources) +{ + build_shader_module(sources, shaderc_compute_shader, &compute_module_); } bool VKShader::finalize(const shader::ShaderCreateInfo * /*info*/) { - return false; + if (compilation_failed_) { + return false; + } + + if (vertex_module_ != VK_NULL_HANDLE) { + BLI_assert(fragment_module_ != VK_NULL_HANDLE); + BLI_assert(compute_module_ == VK_NULL_HANDLE); + + VkPipelineShaderStageCreateInfo vertex_stage_info = {}; + vertex_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertex_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertex_stage_info.module = vertex_module_; + vertex_stage_info.pName = "main"; + pipeline_infos_.append(vertex_stage_info); + + if (geometry_module_ != VK_NULL_HANDLE) { + VkPipelineShaderStageCreateInfo geo_stage_info = {}; + geo_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + geo_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT; + geo_stage_info.module = geometry_module_; + geo_stage_info.pName = "main"; + pipeline_infos_.append(geo_stage_info); + } + VkPipelineShaderStageCreateInfo fragment_stage_info = {}; + fragment_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragment_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragment_stage_info.module = fragment_module_; + fragment_stage_info.pName = "main"; + pipeline_infos_.append(fragment_stage_info); + } + else { + BLI_assert(vertex_module_ == VK_NULL_HANDLE); + BLI_assert(geometry_module_ == VK_NULL_HANDLE); + BLI_assert(fragment_module_ == VK_NULL_HANDLE); + BLI_assert(compute_module_ != VK_NULL_HANDLE); + + VkPipelineShaderStageCreateInfo compute_stage_info = {}; + compute_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + compute_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT; + compute_stage_info.module = geometry_module_; + compute_stage_info.pName = "main"; + pipeline_infos_.append(compute_stage_info); + } + + return true; } void VKShader::transform_feedback_names_set(Span /*name_list*/, @@ -64,34 +717,222 @@ void VKShader::uniform_int(int /*location*/, { } -std::string VKShader::resources_declare(const shader::ShaderCreateInfo & /*info*/) const +std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) const { - return std::string(); + std::stringstream ss; + + ss << "\n/* Pass Resources. */\n"; + for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { + print_resource(ss, res); + } + for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { + print_resource_alias(ss, res); + } + + ss << "\n/* Batch Resources. */\n"; + for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { + print_resource(ss, res); + } + for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { + print_resource_alias(ss, res); + } + + if (!info.push_constants_.is_empty()) { + ss << "\n/* Push Constants. */\n"; + ss << "layout(push_constant) uniform constants\n"; + ss << "{\n"; + for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) { + ss << " " << to_string(uniform.type) << " pc_" << uniform.name; + if (uniform.array_size > 0) { + ss << "[" << uniform.array_size << "]"; + } + ss << ";\n"; + } + ss << "} PushConstants;\n"; + for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) { + ss << "#define " << uniform.name << " (PushConstants.pc_" << uniform.name << ")\n"; + } + } + + ss << "\n"; + return ss.str(); } -std::string VKShader::vertex_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +std::string VKShader::vertex_interface_declare(const shader::ShaderCreateInfo &info) const { - return std::string(); + std::stringstream ss; + std::string post_main; + + ss << "\n/* Inputs. */\n"; + for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) { + ss << "layout(location = " << attr.index << ") "; + ss << "in " << to_string(attr.type) << " " << attr.name << ";\n"; + } + /* NOTE(D4490): Fix a bug where shader without any vertex attributes do not behave correctly. + */ + if (GPU_type_matches_ex(GPU_DEVICE_APPLE, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL) && + info.vertex_inputs_.is_empty()) { + ss << "in float gpu_dummy_workaround;\n"; + } + ss << "\n/* Interfaces. */\n"; + int location = 0; + for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { + print_interface(ss, "out", *iface, location); + } + if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { + /* Need this for stable barycentric. */ + ss << "flat out vec4 gpu_pos_flat;\n"; + ss << "out vec4 gpu_pos;\n"; + + post_main += " gpu_pos = gpu_pos_flat = gl_Position;\n"; + } + ss << "\n"; + + if (post_main.empty() == false) { + std::string pre_main; + ss << main_function_wrapper(pre_main, post_main); + } + return ss.str(); } -std::string VKShader::fragment_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +std::string VKShader::fragment_interface_declare(const shader::ShaderCreateInfo &info) const { - return std::string(); + std::stringstream ss; + std::string pre_main; + + ss << "\n/* Interfaces. */\n"; + const Vector &in_interfaces = info.geometry_source_.is_empty() ? + info.vertex_out_interfaces_ : + info.geometry_out_interfaces_; + int location = 0; + for (const StageInterfaceInfo *iface : in_interfaces) { + print_interface(ss, "in", *iface, location); + } + if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { + std::cout << "native" << std::endl; + /* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry + * shader workaround if this extension/feature is detected. */ + ss << "\n/* Stable Barycentric Coordinates. */\n"; + ss << "flat in vec4 gpu_pos_flat;\n"; + ss << "__explicitInterpAMD in vec4 gpu_pos;\n"; + /* Globals. */ + ss << "vec3 gpu_BaryCoord;\n"; + ss << "vec3 gpu_BaryCoordNoPersp;\n"; + ss << "\n"; + ss << "vec2 stable_bary_(vec2 in_bary) {\n"; + ss << " vec3 bary = vec3(in_bary, 1.0 - in_bary.x - in_bary.y);\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { return bary.zxy; }\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { return bary.yzx; }\n"; + ss << " return bary.xyz;\n"; + ss << "}\n"; + ss << "\n"; + ss << "vec4 gpu_position_at_vertex(int v) {\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { v = (v + 2) % 3; }\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { v = (v + 1) % 3; }\n"; + ss << " return interpolateAtVertexAMD(gpu_pos, v);\n"; + ss << "}\n"; + + pre_main += " gpu_BaryCoord = stable_bary_(gl_BaryCoordSmoothAMD);\n"; + pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n"; + } + if (info.early_fragment_test_) { + ss << "layout(early_fragment_tests) in;\n"; + } + ss << "layout(" << to_string(info.depth_write_) << ") out float gl_FragDepth;\n"; + ss << "\n/* Outputs. */\n"; + for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) { + ss << "layout(location = " << output.index; + switch (output.blend) { + case DualBlend::SRC_0: + ss << ", index = 0"; + break; + case DualBlend::SRC_1: + ss << ", index = 1"; + break; + default: + break; + } + ss << ") "; + ss << "out " << to_string(output.type) << " " << output.name << ";\n"; + } + ss << "\n"; + + if (pre_main.empty() == false) { + std::string post_main; + ss << main_function_wrapper(pre_main, post_main); + } + return ss.str(); } -std::string VKShader::geometry_interface_declare(const shader::ShaderCreateInfo & /*info*/) const +std::string VKShader::geometry_interface_declare(const shader::ShaderCreateInfo &info) const { - return std::string(); + int max_verts = info.geometry_layout_.max_vertices; + int invocations = info.geometry_layout_.invocations; + + std::stringstream ss; + ss << "\n/* Geometry Layout. */\n"; + ss << "layout(" << to_string(info.geometry_layout_.primitive_in); + if (invocations != -1) { + ss << ", invocations = " << invocations; + } + ss << ") in;\n"; + + ss << "layout(" << to_string(info.geometry_layout_.primitive_out) + << ", max_vertices = " << max_verts << ") out;\n"; + ss << "\n"; + return ss.str(); } -std::string VKShader::geometry_layout_declare(const shader::ShaderCreateInfo & /*info*/) const +static StageInterfaceInfo *find_interface_by_name(const Vector &ifaces, + const StringRefNull &name) { - return std::string(); + for (auto *iface : ifaces) { + if (iface->instance_name == name) { + return iface; + } + } + return nullptr; } -std::string VKShader::compute_layout_declare(const shader::ShaderCreateInfo & /*info*/) const +std::string VKShader::geometry_layout_declare(const shader::ShaderCreateInfo &info) const { - return std::string(); + std::stringstream ss; + + ss << "\n/* Interfaces. */\n"; + int location = 0; + for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { + bool has_matching_output_iface = find_interface_by_name(info.geometry_out_interfaces_, + iface->instance_name) != nullptr; + const char *suffix = (has_matching_output_iface) ? "_in[]" : "[]"; + print_interface(ss, "in", *iface, location, suffix); + } + ss << "\n"; + + for (const StageInterfaceInfo *iface : info.geometry_out_interfaces_) { + bool has_matching_input_iface = find_interface_by_name(info.vertex_out_interfaces_, + iface->instance_name) != nullptr; + const char *suffix = (has_matching_input_iface) ? "_out" : ""; + print_interface(ss, "out", *iface, location, suffix); + } + ss << "\n"; + + return ss.str(); +} + +std::string VKShader::compute_layout_declare(const shader::ShaderCreateInfo &info) const +{ + std::stringstream ss; + ss << "\n/* Compute Layout. */\n"; + ss << "layout(local_size_x = " << info.compute_layout_.local_size_x; + if (info.compute_layout_.local_size_y != -1) { + ss << ", local_size_y = " << info.compute_layout_.local_size_y; + } + if (info.compute_layout_.local_size_z != -1) { + ss << ", local_size_z = " << info.compute_layout_.local_size_z; + } + ss << ") in;\n"; + ss << "\n"; + return ss.str(); } int VKShader::program_handle_get() const diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index 9ab0aca67eb..aa8f0b84ae7 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -9,13 +9,26 @@ #include "gpu_shader_private.hh" +#include "vk_backend.hh" +#include "vk_context.hh" + +#include "BLI_string_ref.hh" + namespace blender::gpu { class VKShader : public Shader { + private: + VKContext *context_ = nullptr; + VkShaderModule vertex_module_ = VK_NULL_HANDLE; + VkShaderModule geometry_module_ = VK_NULL_HANDLE; + VkShaderModule fragment_module_ = VK_NULL_HANDLE; + VkShaderModule compute_module_ = VK_NULL_HANDLE; + bool compilation_failed_ = false; + Vector pipeline_infos_; + public: - VKShader(const char *name) : Shader(name) - { - } + VKShader(const char *name); + virtual ~VKShader(); void vertex_shader_from_glsl(MutableSpan sources) override; void geometry_shader_from_glsl(MutableSpan sources) override; @@ -43,6 +56,13 @@ class VKShader : public Shader { /* DEPRECATED: Kept only because of BGL API. */ int program_handle_get() const override; + + private: + Vector compile_glsl_to_spirv(Span sources, shaderc_shader_kind kind); + void build_shader_module(Span spirv_module, VkShaderModule *r_shader_module); + void build_shader_module(MutableSpan sources, + shaderc_shader_kind stage, + VkShaderModule *r_shader_module); }; } // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_shader_log.cc b/source/blender/gpu/vulkan/vk_shader_log.cc new file mode 100644 index 00000000000..4a7d1771c53 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader_log.cc @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_shader_log.hh" + +#include "GPU_platform.h" + +namespace blender::gpu { + +char *VKLogParser::parse_line(char *log_line, GPULogItem &log_item) +{ + log_line = skip_name(log_line); + log_line = skip_separators(log_line, ":"); + + /* Parse error line & char numbers. */ + if (at_number(log_line)) { + char *error_line_number_end; + log_item.cursor.row = parse_number(log_line, &error_line_number_end); + log_line = error_line_number_end; + } + log_line = skip_separators(log_line, ": "); + + /* Skip to message. Avoid redundant info. */ + log_line = skip_severity_keyword(log_line, log_item); + log_line = skip_separators(log_line, ": "); + + return log_line; +} + +char *VKLogParser::skip_name(char *log_line) +{ + return skip_until(log_line, ':'); +} + +char *VKLogParser::skip_severity_keyword(char *log_line, GPULogItem &log_item) +{ + return skip_severity(log_line, log_item, "error", "warning"); +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader_log.hh b/source/blender/gpu/vulkan/vk_shader_log.hh new file mode 100644 index 00000000000..fb12b7a5039 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader_log.hh @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +#include "gpu_shader_private.hh" + +namespace blender::gpu { + +class VKLogParser : public GPULogParser { + public: + char *parse_line(char *log_line, GPULogItem &log_item) override; + + protected: + char *skip_name(char *log_line); + char *skip_severity_keyword(char *log_line, GPULogItem &log_item); +}; +} // namespace blender::gpu \ No newline at end of file