Skip to content

Commit

Permalink
Draw large feathers at lower resolution
Browse files Browse the repository at this point in the history
Diffs=
633c8ef979 Draw large feathers at lower resolution (#9013)

Co-authored-by: Chris Dalton <[email protected]>
  • Loading branch information
csmartdalton and csmartdalton committed Feb 11, 2025
1 parent dc3000b commit e694a1b
Show file tree
Hide file tree
Showing 31 changed files with 1,041 additions and 327 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
339867b4de68e3c301409dad079747b954d4fa11
633c8ef979c22715dd1a64694c2e406d923cde7a
6 changes: 6 additions & 0 deletions include/rive/math/aabb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ template <typename T> struct TAABB
bottom == o.bottom;
}
bool operator!=(const TAABB& o) const { return !(*this == o); }

bool contains(const TAABB& rhs) const
{
return left <= rhs.left && top <= rhs.top && right >= rhs.right &&
bottom >= rhs.bottom;
}
};

using IAABB = TAABB<int32_t>;
Expand Down
15 changes: 14 additions & 1 deletion renderer/include/rive/renderer/d3d/render_context_d3d_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,14 @@ class RenderContextD3DImpl : public RenderContextHelperImpl

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 flush(const FlushDescriptor&) override;

void setPipelineLayoutAndShaders(DrawType,
gpu::ShaderFeatures,
gpu::InterlockMode,
gpu::ShaderMiscFlags pixelShaderMiscFlags);
gpu::ShaderMiscFlags shaderMiscFlags);

const D3DCapabilities m_d3dCapabilities;

Expand All @@ -159,6 +160,11 @@ class RenderContextD3DImpl : public RenderContextHelperImpl
ComPtr<ID3D11ShaderResourceView> m_tessTextureSRV;
ComPtr<ID3D11RenderTargetView> m_tessTextureRTV;

ComPtr<ID3D11Texture2D> m_atlasTexture;
ComPtr<ID3D11ShaderResourceView> m_atlasTextureSRV;
ComPtr<ID3D11RenderTargetView> m_atlasTextureRTV;

ComPtr<ID3D11RasterizerState> m_atlasRasterState;
ComPtr<ID3D11RasterizerState> m_backCulledRasterState[2];
ComPtr<ID3D11RasterizerState> m_doubleSidedRasterState[2];

Expand All @@ -171,6 +177,11 @@ class RenderContextD3DImpl : public RenderContextHelperImpl
ComPtr<ID3D11PixelShader> m_tessellatePixelShader;
ComPtr<ID3D11Buffer> m_tessSpanIndexBuffer;

ComPtr<ID3D11InputLayout> m_atlasLayout;
ComPtr<ID3D11VertexShader> m_atlasVertexShader;
ComPtr<ID3D11PixelShader> m_atlasFillPixelShader;
ComPtr<ID3D11PixelShader> m_atlasStrokePixelShader;

struct DrawVertexShader
{
ComPtr<ID3D11InputLayout> layout;
Expand Down Expand Up @@ -206,5 +217,7 @@ class RenderContextD3DImpl : public RenderContextHelperImpl
ComPtr<ID3D11SamplerState> m_mipmapSampler;

ComPtr<ID3D11BlendState> m_srcOverBlendState;
ComPtr<ID3D11BlendState> m_plusBlendState;
ComPtr<ID3D11BlendState> m_maxBlendState;
};
} // namespace rive::gpu
10 changes: 6 additions & 4 deletions renderer/include/rive/renderer/draw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,10 @@ class PathDraw : public Draw
}

// Only used when rendering coverage via the atlas.
int16_t screenToAtlasOffsetX() const { return m_screenToAtlasOffsetX; }
int16_t screenToAtlasOffsetY() const { return m_screenToAtlasOffsetY; }
const gpu::AtlasTransform& atlasTransform() const
{
return m_atlasTransform;
}
const TAABB<uint16_t>& atlasScissor() const { return m_atlasScissor; }
bool atlasScissorEnabled() const { return m_atlasScissorEnabled; }

Expand Down Expand Up @@ -264,6 +266,7 @@ class PathDraw : public Draw

protected:
static CoverageType SelectCoverageType(const RiveRenderPaint*,
float matrixMaxScale,
gpu::InterlockMode);

// Prepares to draw the path by tessellating a fan around its midpoint.
Expand Down Expand Up @@ -333,8 +336,7 @@ class PathDraw : public Draw
uint32_t m_contourFlags = 0;

// Only used when rendering coverage via the atlas.
int16_t m_screenToAtlasOffsetX;
int16_t m_screenToAtlasOffsetY;
gpu::AtlasTransform m_atlasTransform;
TAABB<uint16_t> m_atlasScissor; // Scissor rect when rendering to the atlas.
bool m_atlasScissorEnabled;

Expand Down
107 changes: 64 additions & 43 deletions renderer/include/rive/renderer/gpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -777,45 +777,6 @@ constexpr static ShaderFeatures ShaderFeaturesMaskFor(
RIVE_UNREACHABLE();
}

constexpr static ShaderFeatures ShaderFeaturesMaskFor(
DrawType drawType,
InterlockMode interlockMode)
{
ShaderFeatures mask = ShaderFeatures::NONE;
switch (drawType)
{
case DrawType::imageRect:
case DrawType::imageMesh:
if (interlockMode != gpu::InterlockMode::atomics)
{
mask = ShaderFeatures::ENABLE_CLIPPING |
ShaderFeatures::ENABLE_CLIP_RECT |
ShaderFeatures::ENABLE_ADVANCED_BLEND |
ShaderFeatures::ENABLE_HSL_BLEND_MODES;
break;
}
// Since atomic mode has to resolve previous draws, images need to
// consider the same shader features for path draws.
[[fallthrough]];
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
case DrawType::interiorTriangulation:
case DrawType::atomicResolve:
mask = kAllShaderFeatures;
break;
case DrawType::atomicInitialize:
assert(interlockMode == gpu::InterlockMode::atomics);
mask = ShaderFeatures::ENABLE_CLIPPING |
ShaderFeatures::ENABLE_ADVANCED_BLEND;
break;
case DrawType::stencilClipReset:
mask = ShaderFeatures::NONE;
break;
}
return mask & ShaderFeaturesMaskFor(interlockMode);
}

// Miscellaneous switches that *do* affect the behavior of the fragment shader.
// The renderContext may add some of these, and a backend may also add them to a
// shader key if it wants to implement the behavior.
Expand Down Expand Up @@ -861,11 +822,64 @@ enum class ShaderMiscFlags : uint32_t
};
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:
if (interlockMode != gpu::InterlockMode::atomics)
{
mask = ShaderFeatures::ENABLE_CLIPPING |
ShaderFeatures::ENABLE_CLIP_RECT |
ShaderFeatures::ENABLE_ADVANCED_BLEND |
ShaderFeatures::ENABLE_HSL_BLEND_MODES;
break;
}
// Since atomic mode has to resolve previous draws, images need to
// consider the same shader features for path draws.
[[fallthrough]];
case DrawType::midpointFanPatches:
case DrawType::midpointFanCenterAAPatches:
case DrawType::outerCurvePatches:
case DrawType::interiorTriangulation:
case DrawType::atomicResolve:
mask = kAllShaderFeatures;
break;
case DrawType::atomicInitialize:
assert(interlockMode == gpu::InterlockMode::atomics);
mask = ShaderFeatures::ENABLE_CLIPPING |
ShaderFeatures::ENABLE_ADVANCED_BLEND;
break;
case DrawType::stencilClipReset:
mask = ShaderFeatures::NONE;
break;
}
return mask & ShaderFeaturesMaskFor(shaderMiscFlags) &
ShaderFeaturesMaskFor(interlockMode);
}

// Returns a unique value that can be used to key a shader.
uint32_t ShaderUniqueKey(DrawType,
ShaderFeatures,
Expand Down Expand Up @@ -1183,6 +1197,15 @@ constexpr static uint32_t StorageBufferElementSizeInBytes(
RIVE_UNREACHABLE();
}

// Defines a transform from screen space into a region of the atlas.
// The atlas may have a different scale factor than the screen.
struct AtlasTransform
{
float scaleFactor;
float translateX;
float translateY;
};

// Defines a sub-allocation for a path's coverage data within the
// renderContext's coverage buffer. (clockwiseAtomic mode only.)
struct CoverageBufferRange
Expand Down Expand Up @@ -1210,8 +1233,7 @@ struct PathData
float strokeRadius,
float featherRadius,
uint32_t zIndex,
int16_t screenToAtlasOffsetX,
int16_t screenToAtlasOffsetY,
const AtlasTransform&,
const CoverageBufferRange&);

private:
Expand All @@ -1222,8 +1244,7 @@ struct PathData
// InterlockMode::msaa.
WRITEONLY uint32_t m_zIndex;
// Only used when rendering coverage via the atlas.
WRITEONLY uint32_t m_screenToAtlasOffsetPackedXY;
WRITEONLY uint32_t pad[2];
WRITEONLY AtlasTransform m_atlasTransform;
// InterlockMode::clockwiseAtomic.
WRITEONLY CoverageBufferRange m_coverageBufferRange;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ class RenderContextMetalImpl : public RenderContextHelperImpl

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;

// Obtains an exclusive lock on the next buffer ring index, potentially
// blocking until the GPU has finished rendering with it. This ensures it is
Expand Down Expand Up @@ -218,6 +219,12 @@ class RenderContextMetalImpl : public RenderContextHelperImpl
id<MTLBuffer> m_tessSpanIndexBuffer = nullptr;
id<MTLTexture> m_tessVertexTexture = nullptr;

// Atlas rendering.
class AtlasPipeline;
std::unique_ptr<AtlasPipeline> m_atlasFillPipeline;
std::unique_ptr<AtlasPipeline> m_atlasStrokePipeline;
id<MTLTexture> m_atlasTexture = nullptr;

std::map<uint32_t, std::unique_ptr<DrawPipeline>> m_drawPipelines;

// Vertex/index buffers for drawing path patches.
Expand Down
11 changes: 8 additions & 3 deletions renderer/include/rive/renderer/render_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ class RenderContext : public RiveRenderFactory
uint32_t atlasMaxSize() const
{
constexpr static uint32_t MAX_ATLAS_MAX_SIZE = 4096;
return std::max(platformFeatures().maxTextureSize, MAX_ATLAS_MAX_SIZE);
return std::min(platformFeatures().maxTextureSize, MAX_ATLAS_MAX_SIZE);
}

// Defines the exact size of each of our GPU resources. Computed during
Expand Down Expand Up @@ -559,12 +559,17 @@ class RenderContext : public RiveRenderFactory
// registers a future callback to PathDraw::pushAtlasTessellation()
// where it will render its coverage data to this same region in the
// atlas.
//
// Attempts to leave a border of "desiredPadding" pixels surrounding the
// rectangular region, but the allocation may not be padded if the path
// is up against an edge.
bool allocateAtlasDraw(PathDraw*,
uint16_t drawWidth,
uint16_t drawHeight,
uint16_t padding,
uint16_t desiredPadding,
uint16_t* x,
uint16_t* y);
uint16_t* y,
TAABB<uint16_t>* paddedRegion);

// Reserves a range within the coverage buffer for a path to use in
// clockwiseAtomic mode.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,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 resizeCoverageBuffer(size_t sizeInBytes) override;

// Wraps a VkDescriptorPool created specifically for a PLS flush, and tracks
Expand Down
Loading

0 comments on commit e694a1b

Please sign in to comment.