Skip to content

Commit

Permalink
Delete the simple gradient texture transfer
Browse files Browse the repository at this point in the history
The previous approach of transferring simple gradients directly to the texture, and then rendering complex gradients had various inefficiencies:

  * The texture resource had to be transitioned to and from TRANSFER_DST.

  * It required a pipeline barrier on the transfer stage.

  * The gradient texture had to be created with transfer capabilities.

  * Unnecessary code complexity.

It also ran into platform bugs on various Android and Unreal environments.

This PR just removes the texture transfer entirely and renders simple gradients at the same time we render complex ones. Rendering the simple ramps requires us to upload more data to the GPU, but the tradeoffs should be worth it.

Diffs=
792049458c Delete the simple gradient texture transfer (#8844)

Co-authored-by: Chris Dalton <[email protected]>
  • Loading branch information
csmartdalton and csmartdalton committed Jan 10, 2025
1 parent 9d2535c commit c0cd593
Show file tree
Hide file tree
Showing 22 changed files with 172 additions and 439 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6f306199cad05604ab7c0293b5268e00ca1abc84
792049458cf90c0fb3f06a34080db079281bd2e7
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,6 @@ class RenderContextD3DImpl : public RenderContextHelperImpl
gpu::StorageBufferStructure) override;
std::unique_ptr<BufferRing> makeVertexBufferRing(
size_t capacityInBytes) override;
std::unique_ptr<BufferRing> makeTextureTransferBufferRing(
size_t capacityInBytes) override;

void resizeGradientTexture(uint32_t width, uint32_t height) override;
void resizeTessellationTexture(uint32_t width, uint32_t height) override;
Expand Down
2 changes: 0 additions & 2 deletions renderer/include/rive/renderer/gl/render_context_gl_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,6 @@ class RenderContextGLImpl : public RenderContextHelperImpl
gpu::StorageBufferStructure) override;
std::unique_ptr<BufferRing> makeVertexBufferRing(
size_t capacityInBytes) override;
std::unique_ptr<BufferRing> makeTextureTransferBufferRing(
size_t capacityInBytes) override;

void resizeGradientTexture(uint32_t width, uint32_t height) override;
void resizeTessellationTexture(uint32_t width, uint32_t height) override;
Expand Down
27 changes: 11 additions & 16 deletions renderer/include/rive/renderer/gpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,10 @@ struct ColorRampLocation
// and images reference an additional Gradient* and Texture* respectively.
union SimplePaintValue
{
ColorInt color = 0xff000000; // PaintType::solidColor
ColorRampLocation
colorRampLocation; // Paintype::linearGradient, Paintype::radialGradient
float imageOpacity; // PaintType::image
uint32_t outerClipID; // Paintype::clipUpdate
ColorInt color = 0xff000000; // PaintType::solidColor
ColorRampLocation colorRampLocation; // Paintype::linear/radialGradient
float imageOpacity; // PaintType::image
uint32_t outerClipID; // Paintype::clipUpdate
};
static_assert(sizeof(SimplePaintValue) == 4);

Expand Down Expand Up @@ -834,10 +833,10 @@ struct TwoTexelRamp
{
void set(const ColorInt colors[2])
{
UnpackColorToRGBA8(colors[0], colorData);
UnpackColorToRGBA8(colors[1], colorData + 4);
color0 = colors[0];
color1 = colors[1];
}
uint8_t colorData[8];
ColorInt color0, color1;
};
static_assert(sizeof(TwoTexelRamp) == 8 * sizeof(uint8_t));

Expand All @@ -859,7 +858,7 @@ class CommandBufferCompletionFence : public RefCnt<CommandBufferCompletionFence>
//
// 1. Render the complex gradients from the gradSpanBuffer to the gradient
// texture
// (complexGradSpanCount, firstComplexGradSpan, complexGradRowsTop,
// (gradSpanCount, firstComplexGradSpan, complexGradRowsTop,
// complexGradRowsHeight).
//
// 2. Transfer the simple gradient texels from the simpleColorRampsBuffer to
Expand Down Expand Up @@ -909,15 +908,11 @@ struct FlushDescriptor
size_t firstPaintAux = 0;
uint32_t contourCount = 0;
size_t firstContour = 0;
uint32_t complexGradSpanCount = 0;
size_t firstComplexGradSpan = 0;
uint32_t gradSpanCount = 0;
size_t firstGradSpan = 0;
uint32_t tessVertexSpanCount = 0;
size_t firstTessVertexSpan = 0;
uint32_t simpleGradTexelsWidth = 0;
uint32_t simpleGradTexelsHeight = 0;
size_t simpleGradDataOffsetInBytes = 0;
uint32_t complexGradRowsTop = 0;
uint32_t complexGradRowsHeight = 0;
uint32_t gradDataHeight = 0;
uint32_t tessDataHeight = 0;
// Override path fill rules with "clockwise".
bool clockwiseFillOverride = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,6 @@ class RenderContextMetalImpl : public RenderContextHelperImpl
size_t capacityInBytes, StorageBufferStructure) override;
std::unique_ptr<BufferRing> makeVertexBufferRing(
size_t capacityInBytes) override;
std::unique_ptr<BufferRing> makeTextureTransferBufferRing(
size_t capacityInBytes) override;

private:
// Renders paths to the main render target.
Expand Down
24 changes: 11 additions & 13 deletions renderer/include/rive/renderer/render_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ class RenderContext : public RiveRenderFactory
// LogicalFlush::LayoutCounters.
struct ResourceAllocationCounts
{
constexpr static int NUM_ELEMENTS = 13;
constexpr static int NUM_ELEMENTS = 12;
using VecType = simd::gvec<size_t, NUM_ELEMENTS>;

RIVE_ALWAYS_INLINE VecType toVec() const
Expand All @@ -308,8 +308,7 @@ class RenderContext : public RiveRenderFactory
size_t paintBufferCount = 0;
size_t paintAuxBufferCount = 0;
size_t contourBufferCount = 0;
size_t simpleGradientBufferCount = 0;
size_t complexGradSpanBufferCount = 0;
size_t gradSpanBufferCount = 0;
size_t tessSpanBufferCount = 0;
size_t triangleVertexBufferCount = 0;
size_t gradTextureHeight = 0;
Expand Down Expand Up @@ -366,9 +365,6 @@ class RenderContext : public RiveRenderFactory
WriteOnlyMappedMemory<gpu::PaintData> m_paintData;
WriteOnlyMappedMemory<gpu::PaintAuxData> m_paintAuxData;
WriteOnlyMappedMemory<gpu::ContourData> m_contourData;
// Simple gradients get written by the CPU.
WriteOnlyMappedMemory<gpu::TwoTexelRamp> m_simpleColorRampsData;
// Complex gradients get rendered by the GPU.
WriteOnlyMappedMemory<gpu::GradientSpan> m_gradSpanData;
WriteOnlyMappedMemory<gpu::TessVertexSpan> m_tessSpanData;
WriteOnlyMappedMemory<gpu::TriangleVertex> m_triangleVertexData;
Expand Down Expand Up @@ -527,8 +523,7 @@ class RenderContext : public RiveRenderFactory
uint32_t paintPaddingCount = 0;
uint32_t paintAuxPaddingCount = 0;
uint32_t contourPaddingCount = 0;
uint32_t simpleGradCount = 0;
uint32_t complexGradSpanCount = 0;
uint32_t gradSpanCount = 0;
uint32_t gradSpanPaddingCount = 0;
uint32_t maxGradTextureHeight = 0;
uint32_t maxTessTextureHeight = 0;
Expand Down Expand Up @@ -703,16 +698,19 @@ class RenderContext : public RiveRenderFactory
// implemented with 2 texels.
std::unordered_map<uint64_t, uint32_t>
m_simpleGradients; // [color0, color1] -> texelsIdx.
std::vector<gpu::TwoTexelRamp> m_pendingSimpleGradientWrites;
std::vector<gpu::TwoTexelRamp> m_pendingSimpleGradDraws;

// Complex gradients have stop(s) between t=0 and t=1. In theory they
// should be scaled to a ramp where every stop lands exactly on a pixel
// center, but for now we just always scale them to the entire gradient
// texture width.
std::unordered_map<GradientContentKey, uint16_t, DeepHashGradient>
m_complexGradients; // [colors[0..n], stops[0..n]] -> rowIdx
std::vector<const Gradient*> m_pendingComplexColorRampDraws;
size_t m_pendingComplexGradSpanCount;
std::vector<const Gradient*> m_pendingComplexGradDraws;

// Simple and complex gradients both get uploaded to the GPU as sets of
// "GradientSpan" instances.
size_t m_pendingGradSpanCount;

std::vector<ClipInfo> m_clips;

Expand All @@ -732,10 +730,10 @@ class RenderContext : public RiveRenderFactory
uint32_t m_outerCubicTessVertexIdx;
uint32_t m_midpointFanTessVertexIdx;

gpu::FlushDescriptor m_flushDesc;
// Not determined until writeResources().
gpu::GradTextureLayout m_gradTextureLayout;

gpu::FlushDescriptor m_flushDesc;

BlockAllocatedLinkedList<DrawBatch> m_drawList;
gpu::ShaderFeatures m_combinedShaderFeatures;

Expand Down
10 changes: 0 additions & 10 deletions renderer/include/rive/renderer/render_context_helper_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class RenderContextHelperImpl : public RenderContextImpl
gpu::StorageBufferStructure) override;
void resizeContourBuffer(size_t sizeInBytes,
gpu::StorageBufferStructure) override;
void resizeSimpleColorRampsBuffer(size_t sizeInBytes) override;
void resizeGradSpanBuffer(size_t sizeInBytes) override;
void resizeTessVertexSpanBuffer(size_t sizeInBytes) override;
void resizeTriangleVertexBuffer(size_t sizeInBytes) override;
Expand All @@ -37,7 +36,6 @@ class RenderContextHelperImpl : public RenderContextImpl
void* mapPaintBuffer(size_t mapSizeInBytes) override;
void* mapPaintAuxBuffer(size_t mapSizeInBytes) override;
void* mapContourBuffer(size_t mapSizeInBytes) override;
void* mapSimpleColorRampsBuffer(size_t mapSizeInBytes) override;
void* mapGradSpanBuffer(size_t mapSizeInBytes) override;
void* mapTessVertexSpanBuffer(size_t mapSizeInBytes) override;
void* mapTriangleVertexBuffer(size_t mapSizeInBytes) override;
Expand All @@ -48,7 +46,6 @@ class RenderContextHelperImpl : public RenderContextImpl
void unmapPaintBuffer() override;
void unmapPaintAuxBuffer() override;
void unmapContourBuffer() override;
void unmapSimpleColorRampsBuffer() override;
void unmapGradSpanBuffer() override;
void unmapTessVertexSpanBuffer() override;
void unmapTriangleVertexBuffer() override;
Expand All @@ -69,10 +66,6 @@ class RenderContextHelperImpl : public RenderContextImpl
BufferRing* paintBufferRing() { return m_paintBuffer.get(); }
BufferRing* paintAuxBufferRing() { return m_paintAuxBuffer.get(); }
BufferRing* contourBufferRing() { return m_contourBuffer.get(); }
BufferRing* simpleColorRampsBufferRing()
{
return m_simpleColorRampsBuffer.get();
}
BufferRing* gradSpanBufferRing() { return m_gradSpanBuffer.get(); }
BufferRing* tessSpanBufferRing() { return m_tessSpanBuffer.get(); }
BufferRing* triangleBufferRing() { return m_triangleBuffer.get(); }
Expand All @@ -89,8 +82,6 @@ class RenderContextHelperImpl : public RenderContextImpl
gpu::StorageBufferStructure) = 0;
virtual std::unique_ptr<BufferRing> makeVertexBufferRing(
size_t capacityInBytes) = 0;
virtual std::unique_ptr<BufferRing> makeTextureTransferBufferRing(
size_t capacityInBytes) = 0;

private:
std::unique_ptr<BufferRing> m_flushUniformBuffer;
Expand All @@ -99,7 +90,6 @@ class RenderContextHelperImpl : public RenderContextImpl
std::unique_ptr<BufferRing> m_paintBuffer;
std::unique_ptr<BufferRing> m_paintAuxBuffer;
std::unique_ptr<BufferRing> m_contourBuffer;
std::unique_ptr<BufferRing> m_simpleColorRampsBuffer;
std::unique_ptr<BufferRing> m_gradSpanBuffer;
std::unique_ptr<BufferRing> m_tessSpanBuffer;
std::unique_ptr<BufferRing> m_triangleBuffer;
Expand Down
3 changes: 0 additions & 3 deletions renderer/include/rive/renderer/render_context_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ class RenderContextImpl
gpu::StorageBufferStructure) = 0;
virtual void resizeContourBuffer(size_t sizeInBytes,
gpu::StorageBufferStructure) = 0;
virtual void resizeSimpleColorRampsBuffer(size_t sizeInBytes) = 0;
virtual void resizeGradSpanBuffer(size_t sizeInBytes) = 0;
virtual void resizeTessVertexSpanBuffer(size_t sizeInBytes) = 0;
virtual void resizeTriangleVertexBuffer(size_t sizeInBytes) = 0;
Expand All @@ -68,7 +67,6 @@ class RenderContextImpl
virtual void* mapPaintBuffer(size_t mapSizeInBytes) = 0;
virtual void* mapPaintAuxBuffer(size_t mapSizeInBytes) = 0;
virtual void* mapContourBuffer(size_t mapSizeInBytes) = 0;
virtual void* mapSimpleColorRampsBuffer(size_t mapSizeInBytes) = 0;
virtual void* mapGradSpanBuffer(size_t mapSizeInBytes) = 0;
virtual void* mapTessVertexSpanBuffer(size_t mapSizeInBytes) = 0;
virtual void* mapTriangleVertexBuffer(size_t mapSizeInBytes) = 0;
Expand All @@ -80,7 +78,6 @@ class RenderContextImpl
virtual void unmapPaintBuffer() = 0;
virtual void unmapPaintAuxBuffer() = 0;
virtual void unmapContourBuffer() = 0;
virtual void unmapSimpleColorRampsBuffer() = 0;
virtual void unmapGradSpanBuffer() = 0;
virtual void unmapTessVertexSpanBuffer() = 0;
virtual void unmapTriangleVertexBuffer() = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ class RenderContextVulkanImpl : public RenderContextImpl
IMPLEMENT_PLS_STRUCTURED_BUFFER(PaintBuffer, m_paintBufferRing)
IMPLEMENT_PLS_STRUCTURED_BUFFER(PaintAuxBuffer, m_paintAuxBufferRing)
IMPLEMENT_PLS_STRUCTURED_BUFFER(ContourBuffer, m_contourBufferRing)
IMPLEMENT_PLS_BUFFER(SimpleColorRampsBuffer, m_simpleColorRampsBufferRing)
IMPLEMENT_PLS_BUFFER(GradSpanBuffer, m_gradSpanBufferRing)
IMPLEMENT_PLS_BUFFER(TessVertexSpanBuffer, m_tessSpanBufferRing)
IMPLEMENT_PLS_BUFFER(TriangleVertexBuffer, m_triangleBufferRing)
Expand Down Expand Up @@ -230,7 +229,6 @@ class RenderContextVulkanImpl : public RenderContextImpl
vkutil::BufferRing m_paintBufferRing;
vkutil::BufferRing m_paintAuxBufferRing;
vkutil::BufferRing m_contourBufferRing;
vkutil::BufferRing m_simpleColorRampsBufferRing;
vkutil::BufferRing m_gradSpanBufferRing;
vkutil::BufferRing m_tessSpanBufferRing;
vkutil::BufferRing m_triangleBufferRing;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ class RenderContextWebGPUImpl : public RenderContextHelperImpl
gpu::StorageBufferStructure) override;
std::unique_ptr<BufferRing> makeVertexBufferRing(
size_t capacityInBytes) override;
std::unique_ptr<BufferRing> makeTextureTransferBufferRing(
size_t capacityInBytes) override;

void resizeGradientTexture(uint32_t width, uint32_t height) override;
void resizeTessellationTexture(uint32_t width, uint32_t height) override;
Expand Down
20 changes: 0 additions & 20 deletions renderer/premake5_pls_renderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -126,29 +126,9 @@ function execute_and_check(cmd)
end
end

-- Wipe out the shader directory if this make command differs from the one that built it.
local existing_makecommand = nil
local makecommand_filename = pls_shaders_absolute_dir .. '/./.makecommand'
local makecommand_file = io.open(makecommand_filename)
if makecommand_file then
existing_makecommand = makecommand_file:read('*all')
-- Trim whitespace
existing_makecommand = string.gsub(existing_makecommand, '^%s*(.-)%s*$', '%1')
makecommand_file:close()
end
if not existing_makecommand or existing_makecommand ~= makecommand then
if existing_makecommand then
print('"make" command for PLS shaders differs from before: cleaning...')
end
execute_and_check('rm -fr ' .. pls_shaders_absolute_dir)
end

-- Build shaders.
execute_and_check(makecommand)

-- Save the make command for incremental shader builds.
execute_and_check('echo \'' .. makecommand .. '\' > ' .. makecommand_filename)

newoption({
trigger = 'nop-obj-c',
description = 'include Metal classes, but as no-ops (for compilers that don\'t support Obj-C)',
Expand Down
49 changes: 9 additions & 40 deletions renderer/src/d3d/render_context_d3d_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,14 +809,6 @@ std::unique_ptr<BufferRing> RenderContextD3DImpl::makeVertexBufferRing(
: nullptr;
}

std::unique_ptr<BufferRing> RenderContextD3DImpl::makeTextureTransferBufferRing(
size_t capacityInBytes)
{
// It appears impossible to update a D3D texture from a GPU buffer; store
// this data on the heap and upload it to the texture at flush time.
return std::make_unique<HeapBufferRing>(capacityInBytes);
}

RenderTargetD3D::RenderTargetD3D(RenderContextD3DImpl* renderContextImpl,
uint32_t width,
uint32_t height) :
Expand Down Expand Up @@ -1420,7 +1412,7 @@ void RenderContextD3DImpl::flush(const FlushDescriptor& desc)
}

// Render the complex color ramps to the gradient texture.
if (desc.complexGradSpanCount > 0)
if (desc.gradSpanCount > 0)
{
ID3D11Buffer* gradSpanBuffer =
flush_buffer(m_gpuContext.Get(), gradSpanBufferRing());
Expand All @@ -1437,13 +1429,12 @@ void RenderContextD3DImpl::flush(const FlushDescriptor& desc)

m_gpuContext->VSSetShader(m_colorRampVertexShader.Get(), NULL, 0);

D3D11_VIEWPORT viewport = {
0,
static_cast<float>(desc.complexGradRowsTop),
static_cast<float>(kGradTextureWidth),
static_cast<float>(desc.complexGradRowsHeight),
0,
1};
D3D11_VIEWPORT viewport = {0,
0,
static_cast<float>(kGradTextureWidth),
static_cast<float>(desc.gradDataHeight),
0,
1};
m_gpuContext->RSSetViewports(1, &viewport);

// Unbind the gradient texture before rendering it.
Expand All @@ -1460,31 +1451,9 @@ void RenderContextD3DImpl::flush(const FlushDescriptor& desc)

m_gpuContext->DrawInstanced(
4,
desc.complexGradSpanCount,
0,
math::lossless_numeric_cast<UINT>(desc.firstComplexGradSpan));
}

// Copy the simple color ramps to the gradient texture.
if (desc.simpleGradTexelsHeight > 0)
{
assert(desc.simpleGradTexelsHeight * desc.simpleGradTexelsWidth * 4 <=
simpleColorRampsBufferRing()->capacityInBytes());
D3D11_BOX box;
box.left = 0;
box.right = desc.simpleGradTexelsWidth;
box.top = 0;
box.bottom = desc.simpleGradTexelsHeight;
box.front = 0;
box.back = 1;
m_gpuContext->UpdateSubresource(
m_gradTexture.Get(),
desc.gradSpanCount,
0,
&box,
heap_buffer_contents(simpleColorRampsBufferRing()) +
desc.simpleGradDataOffsetInBytes,
kGradTextureWidth * 4,
0);
math::lossless_numeric_cast<UINT>(desc.firstGradSpan));
}

// Tessellate all curves into vertices in the tessellation texture.
Expand Down
Loading

0 comments on commit c0cd593

Please sign in to comment.