Skip to content

Commit

Permalink
Implement the feather atlas on Vulkan
Browse files Browse the repository at this point in the history
Also delete ShaderMiscFlags::atlasCoverage and instead handle the atlas with DrawType::atlasBlit.

Diffs=
98a0ac9b24 Implement the feather atlas on Vulkan (#9139)

Co-authored-by: Chris Dalton <[email protected]>
Co-authored-by: blakdragan7 <[email protected]>
  • Loading branch information
3 people committed Feb 28, 2025
1 parent 3c6f76a commit 9b0790a
Show file tree
Hide file tree
Showing 33 changed files with 1,050 additions and 573 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
492dfea655a43a3eca00fddc8c0534aa2c606a9d
98a0ac9b24c5c7ebbcdb131256c8b376e8e86a74
4 changes: 4 additions & 0 deletions include/rive/span.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ template <typename T> Span<T> make_span(T* ptr, size_t size)
return Span<T>(ptr, size);
}

template <typename T, size_t N> Span<T> make_span(T (&ptr)[N])
{
return Span<T>(ptr, N);
}
} // namespace rive

#endif
31 changes: 7 additions & 24 deletions renderer/include/rive/renderer/gpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ enum class DrawType : uint8_t
outerCurvePatches, // Just the outer curves of a path; the interior will be
// triangulated.
interiorTriangulation,
atlasBlit,
imageRect,
imageMesh,
atomicInitialize, // Clear/init PLS data when we can't do it with existing
Expand All @@ -623,6 +624,7 @@ constexpr static bool DrawTypeIsImageDraw(DrawType drawType)
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
case DrawType::atomicInitialize:
case DrawType::atomicResolve:
case DrawType::stencilClipReset:
Expand All @@ -642,6 +644,7 @@ constexpr static uint32_t PatchIndexCount(DrawType drawType)
case DrawType::outerCurvePatches:
return kOuterCurvePatchIndexCount;
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
case DrawType::imageRect:
case DrawType::imageMesh:
case DrawType::atomicInitialize:
Expand All @@ -663,6 +666,7 @@ constexpr static uint32_t PatchBorderIndexCount(DrawType drawType)
case DrawType::outerCurvePatches:
return kOuterCurvePatchBorderIndexCount;
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
case DrawType::imageRect:
case DrawType::imageMesh:
case DrawType::atomicInitialize:
Expand All @@ -689,6 +693,7 @@ constexpr static uint32_t PatchBaseIndex(DrawType drawType)
case DrawType::outerCurvePatches:
return kOuterCurvePatchBaseIndex;
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
case DrawType::imageRect:
case DrawType::imageMesh:
case DrawType::atomicInitialize:
Expand Down Expand Up @@ -821,40 +826,19 @@ enum class ShaderMiscFlags : uint32_t
// a single pass, instead of (1) resolving the offscreen texture, and then
// (2) copying the offscreen texture to back the renderTarget.
coalescedResolveAndTransfer = 1 << 5,

// Read coverage from the offscreen atlas instead of computing coverage in
// the shader.
atlasCoverage = 1 << 6,
};
RIVE_MAKE_ENUM_BITSET(ShaderMiscFlags)

constexpr static ShaderFeatures ShaderFeaturesMaskFor(
ShaderMiscFlags shaderMiscFlags)
{
if (shaderMiscFlags & ShaderMiscFlags::atlasCoverage)
{
return kAllShaderFeatures & ~(ShaderFeatures::ENABLE_FEATHER |
ShaderFeatures::ENABLE_EVEN_ODD |
ShaderFeatures::ENABLE_NESTED_CLIPPING);
}
return kAllShaderFeatures;
}

// The set of ShaderMiscFlags that affect the vertex shader. (The others only
// affect the fragment shader.)
constexpr static ShaderMiscFlags VERTEX_SHADER_MISC_FLAGS_MASK =
ShaderMiscFlags::atlasCoverage;

constexpr static ShaderFeatures ShaderFeaturesMaskFor(
DrawType drawType,
ShaderMiscFlags shaderMiscFlags,
InterlockMode interlockMode)
{
ShaderFeatures mask = ShaderFeatures::NONE;
switch (drawType)
{
case DrawType::imageRect:
case DrawType::imageMesh:
case DrawType::atlasBlit:
if (interlockMode != gpu::InterlockMode::atomics)
{
mask = ShaderFeatures::ENABLE_CLIPPING |
Expand Down Expand Up @@ -882,8 +866,7 @@ constexpr static ShaderFeatures ShaderFeaturesMaskFor(
mask = ShaderFeatures::NONE;
break;
}
return mask & ShaderFeaturesMaskFor(shaderMiscFlags) &
ShaderFeaturesMaskFor(interlockMode);
return mask & ShaderFeaturesMaskFor(interlockMode);
}

// Returns a unique value that can be used to key a shader.
Expand Down
2 changes: 1 addition & 1 deletion renderer/include/rive/renderer/render_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ class RenderContext : public RiveRenderFactory
// Pushes a screen-space rectangle to the draw list, whose pixel
// coverage is determined by the atlas region associated with the given
// pathID.
void pushAtlasCoverageDraw(PathDraw*, uint32_t pathID);
void pushAtlasBlit(PathDraw*, uint32_t pathID);

// Pushes an "imageRect" to the draw list.
// This should only be used when we in atomic mode. Otherwise, images
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class RenderContextVulkanImpl : public RenderContextImpl

void resizeGradientTexture(uint32_t width, uint32_t height) override;
void resizeTessellationTexture(uint32_t width, uint32_t height) override;
void resizeAtlasTexture(uint32_t width, uint32_t height) override {}
void resizeAtlasTexture(uint32_t width, uint32_t height) override;
void resizeCoverageBuffer(size_t sizeInBytes) override;

// Wraps a VkDescriptorPool created specifically for a PLS flush, and tracks
Expand Down Expand Up @@ -275,6 +275,13 @@ class RenderContextVulkanImpl : public RenderContextImpl
rcp<vkutil::TextureView> m_tessVertexTextureView;
rcp<vkutil::Framebuffer> m_tessTextureFramebuffer;

// Renders feathers to the atlas.
class AtlasPipeline;
std::unique_ptr<AtlasPipeline> m_atlasPipeline;
rcp<vkutil::Texture> m_atlasTexture;
rcp<vkutil::TextureView> m_atlasTextureView;
rcp<vkutil::Framebuffer> m_atlasFramebuffer;

// Coverage buffer used by shaders in clockwiseAtomic mode.
rcp<vkutil::Buffer> m_coverageBuffer;

Expand Down
1 change: 0 additions & 1 deletion renderer/premake5_pls_renderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ do
'include',
'glad',
'src',
'shader_hotload',
'../include',
pls_generated_headers,
})
Expand Down
10 changes: 10 additions & 0 deletions renderer/shader_hotload/shader_hotload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,15 @@ rive::Span<const uint32_t> loadNewShaderFileData()
riveSpirvPath / "color_ramp.frag.spirv",
riveSpirvPath / "tessellate.vert.spirv",
riveSpirvPath / "tessellate.frag.spirv",
riveSpirvPath / "render_atlas.vert.spirv",
riveSpirvPath / "render_atlas_fill.frag.spirv",
riveSpirvPath / "render_atlas_stroke.frag.spirv",
riveSpirvPath / "draw_path.vert.spirv",
riveSpirvPath / "draw_path.frag.spirv",
riveSpirvPath / "draw_interior_triangles.vert.spirv",
riveSpirvPath / "draw_interior_triangles.frag.spirv",
riveSpirvPath / "draw_atlas_blit.vert.spirv",
riveSpirvPath / "draw_atlas_blit.frag.spirv",
riveSpirvPath / "draw_image_mesh.vert.spirv",
riveSpirvPath / "draw_image_mesh.frag.spirv",
riveSpirvPath / "atomic_draw_path.vert.spirv",
Expand All @@ -77,6 +82,9 @@ rive::Span<const uint32_t> loadNewShaderFileData()
riveSpirvPath / "atomic_draw_interior_triangles.vert.spirv",
riveSpirvPath / "atomic_draw_interior_triangles.frag.spirv",
riveSpirvPath / "atomic_draw_interior_triangles.fixedcolor_frag.spirv",
riveSpirvPath / "atomic_draw_atlas_blit.vert.spirv",
riveSpirvPath / "atomic_draw_atlas_blit.frag.spirv",
riveSpirvPath / "atomic_draw_atlas_blit.fixedcolor_frag.spirv",
riveSpirvPath / "atomic_draw_image_rect.vert.spirv",
riveSpirvPath / "atomic_draw_image_rect.frag.spirv",
riveSpirvPath / "atomic_draw_image_rect.fixedcolor_frag.spirv",
Expand All @@ -90,6 +98,8 @@ rive::Span<const uint32_t> loadNewShaderFileData()
riveSpirvPath / "draw_clockwise_path.frag.spirv",
riveSpirvPath / "draw_clockwise_interior_triangles.vert.spirv",
riveSpirvPath / "draw_clockwise_interior_triangles.frag.spirv",
riveSpirvPath / "draw_clockwise_atlas_blit.vert.spirv",
riveSpirvPath / "draw_clockwise_atlas_blit.frag.spirv",
riveSpirvPath / "draw_clockwise_image_mesh.vert.spirv",
riveSpirvPath / "draw_clockwise_image_mesh.frag.spirv",
};
Expand Down
29 changes: 16 additions & 13 deletions renderer/src/d3d/render_context_d3d_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
#include "generated/shaders/color_ramp.glsl.hpp"
#include "generated/shaders/constants.glsl.hpp"
#include "generated/shaders/common.glsl.hpp"
#include "generated/shaders/draw_atlas.glsl.hpp"
#include "generated/shaders/draw_image_mesh.glsl.hpp"
#include "generated/shaders/draw_path_common.glsl.hpp"
#include "generated/shaders/draw_path.glsl.hpp"
#include "generated/shaders/hlsl.glsl.hpp"
#include "generated/shaders/bezier_utils.glsl.hpp"
#include "generated/shaders/render_atlas.glsl.hpp"
#include "generated/shaders/tessellate.glsl.hpp"

// D3D11 doesn't let us bind the framebuffer UAV to slot 0 when there is a color
Expand Down Expand Up @@ -1156,7 +1156,7 @@ void RenderContextD3DImpl::resizeAtlasTexture(uint32_t width, uint32_t height)
s << glsl::constants << '\n';
s << glsl::common << '\n';
s << glsl::draw_path_common << '\n';
s << glsl::draw_atlas << '\n';
s << glsl::render_atlas << '\n';
ComPtr<ID3DBlob> blob = compileSourceToBlob(GLSL_VERTEX,
s.str().c_str(),
GLSL_atlasVertexMain,
Expand Down Expand Up @@ -1212,11 +1212,11 @@ void RenderContextD3DImpl::setPipelineLayoutAndShaders(
gpu::InterlockMode interlockMode,
gpu::ShaderMiscFlags shaderMiscFlags)
{
uint32_t vertexShaderKey = gpu::ShaderUniqueKey(
drawType,
shaderFeatures & kVertexShaderFeaturesMask,
interlockMode,
shaderMiscFlags & gpu::VERTEX_SHADER_MISC_FLAGS_MASK);
uint32_t vertexShaderKey =
gpu::ShaderUniqueKey(drawType,
shaderFeatures & kVertexShaderFeaturesMask,
interlockMode,
gpu::ShaderMiscFlags::none);
auto vertexEntry = m_drawVertexShaders.find(vertexShaderKey);

uint32_t pixelShaderKey = ShaderUniqueKey(drawType,
Expand All @@ -1240,8 +1240,7 @@ void RenderContextD3DImpl::setPipelineLayoutAndShaders(
if (m_d3dCapabilities.supportsRasterizerOrderedViews)
{
if (interlockMode == gpu::InterlockMode::rasterOrdering &&
(drawType != DrawType::interiorTriangulation ||
(shaderMiscFlags & gpu::ShaderMiscFlags::atlasCoverage)))
drawType != DrawType::interiorTriangulation)
{
s << "#define " << GLSL_ENABLE_RASTERIZER_ORDERED_VIEWS << '\n';
}
Expand All @@ -1268,17 +1267,16 @@ void RenderContextD3DImpl::setPipelineLayoutAndShaders(
{
s << "#define " << GLSL_CLOCKWISE_FILL << " 1\n";
}
if (shaderMiscFlags & gpu::ShaderMiscFlags::atlasCoverage)
{
s << "#define " << GLSL_ATLAS_COVERAGE << " 1\n";
}
switch (drawType)
{
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
s << "#define " << GLSL_DRAW_PATH << '\n';
break;
case DrawType::atlasBlit:
s << "#define " << GLSL_ATLAS_BLIT << " 1\n";
[[fallthrough]];
case DrawType::interiorTriangulation:
s << "#define " << GLSL_DRAW_INTERIOR_TRIANGLES << '\n';
break;
Expand Down Expand Up @@ -1320,6 +1318,7 @@ void RenderContextD3DImpl::setPipelineLayoutAndShaders(
<< '\n';
break;
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
s << gpu::glsl::draw_path_common << '\n';
s << (interlockMode == gpu::InterlockMode::rasterOrdering
? gpu::glsl::draw_path
Expand Down Expand Up @@ -1385,6 +1384,7 @@ void RenderContextD3DImpl::setPipelineLayoutAndShaders(
vertexAttribCount = 2;
break;
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
layoutDesc[0] = {GLSL_a_triangleVertex,
0,
DXGI_FORMAT_R32G32B32_FLOAT,
Expand Down Expand Up @@ -2021,6 +2021,7 @@ void RenderContextD3DImpl::flush(const FlushDescriptor& desc)
break;
}
case DrawType::interiorTriangulation:
case DrawType::atlasBlit:
{
m_gpuContext->IASetPrimitiveTopology(
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
Expand All @@ -2030,6 +2031,7 @@ void RenderContextD3DImpl::flush(const FlushDescriptor& desc)
break;
}
case DrawType::imageRect:
{
m_gpuContext->IASetPrimitiveTopology(
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_gpuContext->IASetIndexBuffer(m_imageRectIndexBuffer.Get(),
Expand All @@ -2048,6 +2050,7 @@ void RenderContextD3DImpl::flush(const FlushDescriptor& desc)
0,
0);
break;
}
case DrawType::imageMesh:
{
LITE_RTTI_CAST_OR_BREAK(vertexBuffer,
Expand Down
8 changes: 4 additions & 4 deletions renderer/src/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1472,12 +1472,12 @@ void PathDraw::pushToRenderContext(RenderContext::LogicalFlush* flush,

if (m_coverageType == CoverageType::atlas)
{
// Atlas draws only have one subpass -- the rectangular draw to the
// screen. The step that renders coverage to the offscreen atlas is
// handled separately, outside the subpass system.
// Atlas draws only have one subpass -- the rectangular blit from the
// atlas to the screen. The step that renders coverage to the offscreen
// atlas is handled separately, outside the subpass system.
assert(!clockwiseAtomicFill);
assert(subpassIndex == 0);
flush->pushAtlasCoverageDraw(this, m_pathID);
flush->pushAtlasBlit(this, m_pathID);
return;
}

Expand Down
Loading

0 comments on commit 9b0790a

Please sign in to comment.