GPU: Compile vulkan shaders to Spir-V binaries.

Compile each static shader using shaderc to Spir-V binaries.

The main goal is to make sure that the GLSL created using ShaderCreateInfo and able to compile to Spir-V.
For the second stage a correct pipeline needs to be created and some shader would need more
adjustments (push constants size).

With this patch future changes to GLSL sources can already be checked against vulkan, without the
backend finished.

Mechanism has been tested using MacOS and MoltenVK. For other OS, we should finetune CMake
files to find the right location to shaderc.

```
************************************************************
*** Build Mon 12 Dec 2022 11:08:07 CET
************************************************************
Shader Test compilation result: 463 / 463 passed (skipped 118 for compatibility reasons)
OpenGL backend shader compilation succeeded.
Shader Test compilation result: 529 / 529 passed (skipped 52 for compatibility reasons)
Vulkan backend shader compilation succeeded.
```

Reviewed By: fclem

Maniphest Tasks: T102760

Differential Revision: https://developer.blender.org/D16610
This commit is contained in:
Jeroen Bakker 2022-12-12 12:22:38 +01:00 committed by Jeroen Bakker
parent 719513dd9f
commit 9c0d822737
Notes: blender-bot 2023-05-29 09:17:12 +02:00
Referenced by issue #102760, GPU: Implement VKShader.
21 changed files with 1094 additions and 80 deletions

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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()
{

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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. */

View File

@ -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)

View File

@ -98,6 +98,9 @@ static void standard_defines(Vector<const char *> &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;

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -9,9 +9,21 @@
#include "gpu_backend.hh"
#ifdef __APPLE__
# include <MoltenVK/vk_mvk_moltenvk.h>
#else
# include <vulkan/vulkan.h>
#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();

View File

@ -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()

View File

@ -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<VKContext *>(Context::get());
}
VkDevice device_get() const
{
return device_;
}
VmaAllocator mem_allocator_get() const
{
return mem_allocator_;

View File

@ -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<const char *> /*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<const char *> /*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<const char *> /*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<const char *> /*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<const char *> sources)
{
char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size());
return std::string(sources_combined);
}
Vector<uint32_t> VKShader::compile_glsl_to_spirv(Span<const char *> sources,
shaderc_shader_kind stage)
{
std::string combined_sources = combine_sources(sources);
VKBackend &backend = static_cast<VKBackend &>(*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<char> 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<uint32_t>();
}
return Vector<uint32_t>(module.cbegin(), module.cend());
}
void VKShader::build_shader_module(Span<uint32_t> 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 *>(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<const char *> 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<uint32_t> spirv_module = compile_glsl_to_spirv(sources, stage);
build_shader_module(spirv_module, &compute_module_);
}
void VKShader::vertex_shader_from_glsl(MutableSpan<const char *> sources)
{
build_shader_module(sources, shaderc_vertex_shader, &vertex_module_);
}
void VKShader::geometry_shader_from_glsl(MutableSpan<const char *> sources)
{
build_shader_module(sources, shaderc_geometry_shader, &geometry_module_);
}
void VKShader::fragment_shader_from_glsl(MutableSpan<const char *> sources)
{
build_shader_module(sources, shaderc_fragment_shader, &fragment_module_);
}
void VKShader::compute_shader_from_glsl(MutableSpan<const char *> 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<const char *> /*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<StageInterfaceInfo *> &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<StageInterfaceInfo *> &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

View File

@ -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<VkPipelineShaderStageCreateInfo> pipeline_infos_;
public:
VKShader(const char *name) : Shader(name)
{
}
VKShader(const char *name);
virtual ~VKShader();
void vertex_shader_from_glsl(MutableSpan<const char *> sources) override;
void geometry_shader_from_glsl(MutableSpan<const char *> 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<uint32_t> compile_glsl_to_spirv(Span<const char *> sources, shaderc_shader_kind kind);
void build_shader_module(Span<uint32_t> spirv_module, VkShaderModule *r_shader_module);
void build_shader_module(MutableSpan<const char *> sources,
shaderc_shader_kind stage,
VkShaderModule *r_shader_module);
};
} // namespace blender::gpu

View File

@ -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

View File

@ -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