blob: cf3703f00e77366aeb6836469f55005187903a83 [file]
/*
* Copyright 2023 Rive
*/
#include "rive/renderer/vulkan/vulkan_context.hpp"
#include "draw_shader_vulkan.hpp"
#include "vulkan_shaders.hpp"
namespace rive::gpu
{
DrawShaderVulkan::DrawShaderVulkan(Type type,
VulkanContext* vk,
DrawType drawType,
ShaderFeatures shaderFeatures,
InterlockMode interlockMode,
ShaderMiscFlags shaderMiscFlags) :
m_vk(ref_rcp(vk))
{
VkShaderModuleCreateInfo createInfo = {
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
const bool fixedFunctionColorOutput =
enums::is_flag_set(shaderMiscFlags,
gpu::ShaderMiscFlags::fixedFunctionColorOutput);
if (type == Type::fragment &&
interlockMode == InterlockMode::depthStencil &&
drawType != DrawType::renderPassInitialize &&
drawType != DrawType::renderPassResolve)
{
// Fixed function color output and advanced blend are mutually exclusive
// and one of them should always be set in depthStencil mode.
assert(fixedFunctionColorOutput !=
bool(shaderFeatures & ShaderFeatures::ENABLE_ADVANCED_BLEND));
}
Span<const uint32_t> vertCode;
Span<const uint32_t> fragCode;
switch (interlockMode)
{
case gpu::InterlockMode::rasterOrdering:
{
switch (drawType)
{
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
vertCode = spirv::draw_path_vert;
fragCode = spirv::draw_path_frag;
break;
case DrawType::interiorTriangulation:
vertCode = spirv::draw_interior_triangles_vert;
fragCode = spirv::draw_interior_triangles_frag;
break;
case DrawType::featherAtlasBlit:
vertCode = spirv::draw_atlas_blit_vert;
fragCode = spirv::draw_atlas_blit_frag;
break;
case DrawType::imageMesh:
vertCode = spirv::draw_image_mesh_vert;
fragCode = spirv::draw_image_mesh_frag;
break;
case DrawType::renderPassResolve:
vertCode = spirv::draw_fullscreen_quad_vert;
fragCode = spirv::draw_input_attachment_frag;
break;
case DrawType::imageRect:
case DrawType::depthStrokes:
case DrawType::stencilMidpointFanBorrowedCoverage:
case DrawType::stencilDynamicMidpointFans:
case DrawType::stencilDynamicOuterCubics:
case DrawType::stencilMidpointFans:
case DrawType::stencilMidpointFanReset:
case DrawType::stencilMidpointFanWinding:
case DrawType::stencilMidpointFanCover:
case DrawType::stencilOuterCubicBorrowedCoverage:
case DrawType::stencilOuterCubicReset:
case DrawType::stencilOuterCubicWinding:
case DrawType::stencilOuterCubicCover:
case DrawType::stencilOuterCubics:
case DrawType::clipReset:
case DrawType::renderPassInitialize:
RIVE_UNREACHABLE();
}
break;
}
case gpu::InterlockMode::atomics:
{
switch (drawType)
{
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
vertCode = spirv::atomic_draw_path_vert;
fragCode = fixedFunctionColorOutput
? spirv::atomic_draw_path_fixedcolor_frag
: spirv::atomic_draw_path_frag;
break;
case DrawType::interiorTriangulation:
vertCode = spirv::atomic_draw_interior_triangles_vert;
fragCode =
fixedFunctionColorOutput
? spirv::
atomic_draw_interior_triangles_fixedcolor_frag
: spirv::atomic_draw_interior_triangles_frag;
break;
case DrawType::featherAtlasBlit:
vertCode = spirv::atomic_draw_atlas_blit_vert;
fragCode =
fixedFunctionColorOutput
? spirv::atomic_draw_atlas_blit_fixedcolor_frag
: spirv::atomic_draw_atlas_blit_frag;
break;
case DrawType::imageRect:
vertCode = spirv::atomic_draw_image_rect_vert;
fragCode =
fixedFunctionColorOutput
? spirv::atomic_draw_image_rect_fixedcolor_frag
: spirv::atomic_draw_image_rect_frag;
break;
case DrawType::imageMesh:
vertCode = spirv::atomic_draw_image_mesh_vert;
fragCode =
fixedFunctionColorOutput
? spirv::atomic_draw_image_mesh_fixedcolor_frag
: spirv::atomic_draw_image_mesh_frag;
break;
case DrawType::renderPassResolve:
if (enums::is_flag_set(
shaderMiscFlags,
gpu::ShaderMiscFlags::coalescedResolveAndTransfer))
{
vertCode = spirv::atomic_resolve_coalesced_vert;
fragCode = spirv::atomic_resolve_coalesced_frag;
}
else
{
vertCode = spirv::atomic_resolve_vert;
fragCode = fixedFunctionColorOutput
? spirv::atomic_resolve_fixedcolor_frag
: spirv::atomic_resolve_frag;
}
break;
case DrawType::depthStrokes:
case DrawType::stencilMidpointFanBorrowedCoverage:
case DrawType::stencilDynamicMidpointFans:
case DrawType::stencilDynamicOuterCubics:
case DrawType::stencilMidpointFans:
case DrawType::stencilMidpointFanReset:
case DrawType::stencilMidpointFanWinding:
case DrawType::stencilMidpointFanCover:
case DrawType::stencilOuterCubicBorrowedCoverage:
case DrawType::stencilOuterCubicReset:
case DrawType::stencilOuterCubicWinding:
case DrawType::stencilOuterCubicCover:
case DrawType::stencilOuterCubics:
case DrawType::clipReset:
case DrawType::renderPassInitialize:
RIVE_UNREACHABLE();
}
break;
}
case gpu::InterlockMode::clockwise:
{
#ifndef RIVE_ANDROID
switch (drawType)
{
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
vertCode = spirv::draw_clockwise_path_vert;
fragCode =
enums::is_flag_set(shaderMiscFlags,
gpu::ShaderMiscFlags::clipUpdateOnly)
? fixedFunctionColorOutput
? spirv::draw_clockwise_clip_fixedcolor_frag
: spirv::draw_clockwise_clip_frag
: fixedFunctionColorOutput
? spirv::draw_clockwise_path_fixedcolor_frag
: spirv::draw_clockwise_path_frag;
break;
case DrawType::interiorTriangulation:
vertCode = spirv::draw_clockwise_interior_triangles_vert;
fragCode =
enums::is_flag_set(shaderMiscFlags,
gpu::ShaderMiscFlags::clipUpdateOnly)
? fixedFunctionColorOutput
? spirv::
draw_clockwise_clip_interior_triangles_fixedcolor_frag
: spirv::
draw_clockwise_clip_interior_triangles_frag
: fixedFunctionColorOutput
? spirv::
draw_clockwise_interior_triangles_fixedcolor_frag
: spirv::draw_clockwise_interior_triangles_frag;
break;
case DrawType::featherAtlasBlit:
vertCode = spirv::draw_clockwise_atlas_blit_vert;
fragCode =
fixedFunctionColorOutput
? spirv::draw_clockwise_atlas_blit_fixedcolor_frag
: spirv::draw_clockwise_atlas_blit_frag;
break;
case DrawType::imageMesh:
vertCode = spirv::draw_clockwise_image_mesh_vert;
fragCode =
fixedFunctionColorOutput
? spirv::draw_clockwise_image_mesh_fixedcolor_frag
: spirv::draw_clockwise_image_mesh_frag;
break;
case DrawType::imageRect:
case DrawType::depthStrokes:
case DrawType::stencilMidpointFanBorrowedCoverage:
case DrawType::stencilDynamicMidpointFans:
case DrawType::stencilDynamicOuterCubics:
case DrawType::stencilMidpointFans:
case DrawType::stencilMidpointFanReset:
case DrawType::stencilMidpointFanWinding:
case DrawType::stencilMidpointFanCover:
case DrawType::stencilOuterCubicBorrowedCoverage:
case DrawType::stencilOuterCubicReset:
case DrawType::stencilOuterCubicWinding:
case DrawType::stencilOuterCubicCover:
case DrawType::stencilOuterCubics:
case DrawType::clipReset:
case DrawType::renderPassResolve:
case DrawType::renderPassInitialize:
RIVE_UNREACHABLE();
}
break;
#else
RIVE_UNREACHABLE();
#endif
}
case gpu::InterlockMode::clockwiseAtomic:
{
// Since advanced blend is done via input attachments in
// clockwiseAtomic mode, we can swap out the "_fixedcolor" shader
// variants on a per-draw basis instead of per render pass.
const bool drawUsesAdvancedBlend =
enums::is_flag_set(shaderFeatures,
gpu::ShaderFeatures::ENABLE_ADVANCED_BLEND);
switch (drawType)
{
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
vertCode = spirv::draw_clockwise_atomic_path_vert;
if (enums::is_flag_set(
shaderMiscFlags,
gpu::ShaderMiscFlags::borrowedCoveragePass))
{
assert(fixedFunctionColorOutput);
assert(!enums::any_flag_set(
shaderMiscFlags,
gpu::ShaderMiscFlags::clipUpdateOnly |
gpu::ShaderMiscFlags::nestedClipUpdateOnly));
assert(!drawUsesAdvancedBlend);
fragCode =
spirv::draw_clockwise_atomic_borrowed_coverage_frag;
}
else if (enums::any_flag_set(
shaderMiscFlags,
gpu::ShaderMiscFlags::clipUpdateOnly |
gpu::ShaderMiscFlags::
nestedClipUpdateOnly))
{
fragCode =
!drawUsesAdvancedBlend
? spirv::
draw_clockwise_atomic_clip_fixedcolor_frag
: spirv::draw_clockwise_atomic_clip_frag;
}
else
{
fragCode =
!drawUsesAdvancedBlend
? spirv::
draw_clockwise_atomic_path_fixedcolor_frag
: spirv::draw_clockwise_atomic_path_frag;
}
break;
case DrawType::interiorTriangulation:
vertCode =
spirv::draw_clockwise_atomic_interior_triangles_vert;
if (enums::is_flag_set(
shaderMiscFlags,
gpu::ShaderMiscFlags::borrowedCoveragePass))
{
assert(fixedFunctionColorOutput);
assert(!enums::any_flag_set(
shaderMiscFlags,
gpu::ShaderMiscFlags::clipUpdateOnly |
gpu::ShaderMiscFlags::nestedClipUpdateOnly));
assert(!drawUsesAdvancedBlend);
fragCode = spirv::
draw_clockwise_atomic_borrowed_coverage_interior_triangles_frag;
}
else if (enums::any_flag_set(
shaderMiscFlags,
gpu::ShaderMiscFlags::clipUpdateOnly |
gpu::ShaderMiscFlags::
nestedClipUpdateOnly))
{
fragCode =
!drawUsesAdvancedBlend
? spirv::
draw_clockwise_atomic_clip_interior_triangles_fixedcolor_frag
: spirv::
draw_clockwise_atomic_clip_interior_triangles_frag;
}
else
{
fragCode =
!drawUsesAdvancedBlend
? spirv::
draw_clockwise_atomic_interior_triangles_fixedcolor_frag
: spirv::
draw_clockwise_atomic_interior_triangles_frag;
}
break;
case DrawType::featherAtlasBlit:
vertCode = spirv::draw_clockwise_atomic_atlas_blit_vert;
fragCode =
!drawUsesAdvancedBlend
? spirv::
draw_clockwise_atomic_atlas_blit_fixedcolor_frag
: spirv::draw_clockwise_atomic_atlas_blit_frag;
break;
case DrawType::imageMesh:
vertCode = spirv::draw_clockwise_atomic_image_mesh_vert;
fragCode =
!drawUsesAdvancedBlend
? spirv::
draw_clockwise_atomic_image_mesh_fixedcolor_frag
: spirv::draw_clockwise_atomic_image_mesh_frag;
break;
case DrawType::clipReset:
vertCode = spirv::clear_clockwise_atomic_clip_vert;
fragCode =
!drawUsesAdvancedBlend
? spirv::clear_clockwise_atomic_clip_fixedcolor_frag
: spirv::clear_clockwise_atomic_clip_frag;
break;
case DrawType::renderPassInitialize:
vertCode = spirv::draw_fullscreen_quad_vert;
fragCode =
fixedFunctionColorOutput
? spirv::
init_clockwise_atomic_workaround_fixedcolor_frag
: spirv::init_clockwise_atomic_workaround_frag;
break;
case DrawType::imageRect:
case DrawType::depthStrokes:
case DrawType::stencilMidpointFanBorrowedCoverage:
case DrawType::stencilDynamicMidpointFans:
case DrawType::stencilDynamicOuterCubics:
case DrawType::stencilMidpointFans:
case DrawType::stencilMidpointFanReset:
case DrawType::stencilMidpointFanWinding:
case DrawType::stencilMidpointFanCover:
case DrawType::stencilOuterCubicBorrowedCoverage:
case DrawType::stencilOuterCubicReset:
case DrawType::stencilOuterCubicWinding:
case DrawType::stencilOuterCubicCover:
case DrawType::stencilOuterCubics:
case DrawType::renderPassResolve:
RIVE_UNREACHABLE();
}
break;
}
case gpu::InterlockMode::depthStencil:
{
switch (drawType)
{
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
RIVE_UNREACHABLE();
case DrawType::stencilOuterCubicBorrowedCoverage:
case DrawType::stencilOuterCubicReset:
case DrawType::stencilOuterCubicWinding:
case DrawType::stencilOuterCubicCover:
case DrawType::stencilOuterCubics:
case DrawType::depthStrokes:
case DrawType::stencilMidpointFanBorrowedCoverage:
case DrawType::stencilDynamicMidpointFans:
case DrawType::stencilDynamicOuterCubics:
case DrawType::stencilMidpointFans:
case DrawType::stencilMidpointFanReset:
case DrawType::stencilMidpointFanWinding:
case DrawType::stencilMidpointFanCover:
vertCode =
enums::is_flag_set(shaderFeatures,
ShaderFeatures::ENABLE_CLIP_RECT)
? spirv::draw_depthstencil_path_vert
: spirv::draw_depthstencil_path_noclipdistance_vert;
fragCode =
fixedFunctionColorOutput
? spirv::draw_depthstencil_path_fixedcolor_frag
: spirv::draw_depthstencil_path_frag;
break;
case DrawType::clipReset:
vertCode = spirv::draw_depthstencil_triangles_nocolor_vert;
fragCode = spirv::draw_depthstencil_triangles_nocolor_frag;
break;
case DrawType::interiorTriangulation:
// depthStencil interior triangles are smuggled in with
// outerCubic patches instead of using the
// interiorTriangulation draw type.
RIVE_UNREACHABLE();
break;
case DrawType::featherAtlasBlit:
vertCode =
enums::is_flag_set(shaderFeatures,
ShaderFeatures::ENABLE_CLIP_RECT)
? spirv::draw_depthstencil_atlas_blit_vert
: spirv::
draw_depthstencil_atlas_blit_noclipdistance_vert;
fragCode =
fixedFunctionColorOutput
? spirv::
draw_depthstencil_atlas_blit_fixedcolor_frag
: spirv::draw_depthstencil_atlas_blit_frag;
break;
case DrawType::imageMesh:
vertCode =
enums::is_flag_set(shaderFeatures,
ShaderFeatures::ENABLE_CLIP_RECT)
? spirv::draw_depthstencil_image_mesh_vert
: spirv::
draw_depthstencil_image_mesh_noclipdistance_vert;
fragCode =
fixedFunctionColorOutput
? spirv::
draw_depthstencil_image_mesh_fixedcolor_frag
: spirv::draw_depthstencil_image_mesh_frag;
break;
case DrawType::renderPassInitialize:
// depthStencil render passes get initialized by drawing the
// previous contents into the framebuffer.
// (LoadAction::preserveRenderTarget only.)
vertCode = spirv::draw_fullscreen_quad_vert;
fragCode = spirv::draw_msaa_color_seed_attachment_frag;
break;
case DrawType::renderPassResolve:
vertCode = spirv::draw_fullscreen_quad_vert;
fragCode = spirv::draw_msaa_resolve_frag;
break;
case DrawType::imageRect:
RIVE_UNREACHABLE();
}
break;
}
}
Span<const uint32_t> code;
switch (type)
{
case Type::vertex:
code = vertCode;
break;
case Type::fragment:
code = fragCode;
break;
}
assert(code.size_bytes() > 0);
createInfo.pCode = code.data();
createInfo.codeSize = code.size_bytes();
if (m_vk->CreateShaderModule(m_vk->device,
&createInfo,
nullptr,
&m_module) != VK_SUCCESS)
{
m_module = VK_NULL_HANDLE;
}
}
DrawShaderVulkan::~DrawShaderVulkan()
{
m_vk->DestroyShaderModule(m_vk->device, m_module, nullptr);
}
} // namespace rive::gpu