Batch instanced image meshes and give split atomic-mode instances tight bounds
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 50/100
- Loại issue
- Tính năng
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- cpp
- Lĩnh vực
- backend, performance
Hướng nghiên cứu
Start with ImageMeshInstances in include/rive/renderer.hpp, then trace drawImageMeshInstanced in source/renderer/rive_renderer.cpp and image mesh batching in source/renderer/render_context.cpp. Check the renderer tests for atomic mode and batching behavior. Done means instances with known mesh bounds get tight pixel bounds, and compatible adjacent image mesh draws batch together without changing image rect batching.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
This drastically improves performance on atomic mode when using drawImageMeshInstanced with known mesh bounds.
Batch instanced image meshes and give split atomic-mode instances tight bounds.
- include/rive/renderer.hpp: ImageMeshInstances mesh bounds: optional local-space bounds of the mesh the instances draw, so renderers that split instances can give each one tight pixel bounds
- include/rive/renderer.hpp: ImageMeshInstances mesh bounds: storage for the optional mesh bounds
- source/renderer/rive_renderer.cpp: Atomic mode instanced image meshes: give each split instance tight pixel bounds from the mesh bounds instead of fullscreen, so non-overlapping instances share a draw group and skip the per-instance atomic barriers (render pass restarts on WebGPU)
- source/renderer/render_context.cpp: Image mesh batching: image meshes are batchable like other single ElementRange draw types (image rects still aren't)
- source/renderer/render_context.cpp: Image mesh batching: adjacent image mesh draws merge only with the same vertex, uv and index buffers, index count, blend mode and draw contents
- source/renderer/render_context.cpp: Image mesh batching: splice adjacent compatible image mesh draws into one instanced draw
diff --git a/include/rive/renderer.hpp b/include/rive/renderer.hpp
index 47b1cb6f36dd392460f4e3582bc061146d694986..02ee88a94e12a4fc1776eb0c4cf672b99ea4c8d4 100644
--- a/include/rive/renderer.hpp
+++ b/include/rive/renderer.hpp
@@ -142,6 +142,19 @@ public:
void endEdit();
+ // Optional local-space bounds of the mesh vertices the instances draw. When
+ // set, renderers that split instances into separate draws can give each one
+ // tight pixel bounds instead of covering the whole render target.
+ void meshBounds(const AABB& bounds)
+ {
+ m_meshBounds = bounds;
+ m_hasMeshBounds = true;
+ }
+ const AABB* meshBounds() const
+ {
+ return m_hasMeshBounds ? &m_meshBounds : nullptr;
+ }
+
#ifdef DEBUG
bool isEditing() const { return m_editCount != m_endEditCount; }
size_t editCount() const { return m_editCount; }
@@ -152,6 +165,8 @@ protected:
private:
std::vector<ImageMeshInstanceData> m_instanceData;
+ AABB m_meshBounds;
+ bool m_hasMeshBounds = false;
RIVE_DEBUG_CODE(size_t m_editCount = 0;)
RIVE_DEBUG_CODE(size_t m_endEditCount = 0;)
};
diff --git a/source/renderer/render_context.cpp b/source/renderer/render_context.cpp
index 75626cba751b717bac075c88ccb262e614e188e7..ce500c9156bfd07df7f3bdb8319332757491418a 100644
--- a/source/renderer/render_context.cpp
+++ b/source/renderer/render_context.cpp
@@ -4237,6 +4237,7 @@ static bool drawTypeIsBatchable(
case DrawType::stencilOuterCubicWinding:
case DrawType::stencilOuterCubicCover:
case DrawType::clipReset:
+ case DrawType::imageMesh:
// Most drawTypes only support one ElementRange per batch.
assert(!drawTypeSupportsElementRangeList(drawType));
return enums::no_flags_set(
@@ -4244,10 +4245,9 @@ static bool drawTypeIsBatchable(
gpu::BarrierFlags::drawBatchBreak |
gpu::BarrierFlags::elementRangeBreak);
- // Image draws can't be combined for now because they each have their
+ // Image rects can't be combined for now because they each have their
// own unique uniforms.
case DrawType::imageRect:
- case DrawType::imageMesh:
case DrawType::renderPassInitialize:
case DrawType::renderPassResolve:
assert(!drawTypeSupportsElementRangeList(drawType));
@@ -4298,6 +4298,23 @@ static bool canCombineDrawImages(
(currentImageSamplerKey == nextImageSamplerKey);
}
+// Image meshes keep everything that varies per draw in their instance data, so
+// adjacent draws of the same mesh splice into one instanced draw. They still
+// need the same geometry and the same pipeline.
+static bool canCombineImageMeshes(
+ const gpu::DrawBatch* batch,
+ const Draw* draw,
+ gpu::DrawContents drawContents)
+{
+ const auto* meshDraw = static_cast<const ImageMeshDrawBase*>(draw);
+ return batch->vertexBuffer == meshDraw->vertexBuffer() &&
+ batch->uvBuffer == meshDraw->uvBuffer() &&
+ batch->indexBuffer == meshDraw->indexBuffer() &&
+ batch->indexCountPerInstance == meshDraw->indexCount() &&
+ batch->firstBlendMode == draw->blendMode() &&
+ batch->drawContents == drawContents;
+}
+
constexpr uint32_t patchIndexCount(DrawType drawType)
{
switch (drawType)
@@ -4580,6 +4597,8 @@ gpu::DrawBatch& RenderContext::LogicalFlush::pushDraw(
draw->imageTexture(),
currentBatch->imageSampler,
draw->imageSampler()) &&
+ (drawType != DrawType::imageMesh ||
+ canCombineImageMeshes(currentBatch, draw, drawContents)) &&
(!m_ctx->platformFeatures().supportsClipScissor ||
currentBatch->scissorRect == draw->scissorRect()))
{
diff --git a/source/renderer/rive_renderer.cpp b/source/renderer/rive_renderer.cpp
index f96d2d6b2286425457cdc6221de9a352a4760a55..f33b8c75c5a98aee86c116053deece96ae4748a3 100644
--- a/source/renderer/rive_renderer.cpp
+++ b/source/renderer/rive_renderer.cpp
@@ -1033,15 +1033,31 @@ void RiveRenderer::drawImageMeshInstanced(
// instances may overlap. As a workaround, issue individual draw calls
// for each instance instead. This is slow, and I'm only doing it this
// way because atomic mode is soon going away.
+ //
+ // With known mesh bounds, each instance gets tight pixel bounds so
+ // instances that don't overlap can share a draw group and skip the
+ // atomic barriers (which restart the render pass on some backends).
+ const AABB* meshBounds = instances->meshBounds();
for (const auto& instanceData : instances->instanceData())
{
+ const Mat2D instanceMatrix =
+ m_renderStateStack.back().matrix * instanceData.transform;
+ const IAABB pixelBounds =
+ meshBounds != nullptr
+ ? instanceMatrix.mapBoundingBox(*meshBounds).roundOut()
+ : gpu::Draw::FULLSCREEN_PIXEL_BOUNDS;
+ if (pixelBounds.empty())
+ {
+ continue;
+ }
+
float finalOpacity = std::max(
0.0f,
instanceData.opacity * m_renderStateStack.back().modulatedOpacity);
clipAndPushDraw(gpu::DrawUniquePtr(m_context->make<gpu::ImageMeshDraw>(
- gpu::Draw::FULLSCREEN_PIXEL_BOUNDS,
- m_renderStateStack.back().matrix * instanceData.transform,
+ pixelBounds,
+ instanceMatrix,
BlendMode::srcOver,
instanceData.additiveness,
imageTexture,
- Ngôn ngữ chính
- C++
- Star
- 1.3k
- Fork
- 133
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Có Dockerfile hoặc tệp Docker Compose
- Không có mẫu pull request
- Không có hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của rive-app/rive-runtime
-
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 83/100
rive-app/rive-runtime#143 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
rive-app/rive-runtime#141 ·
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 78/100
rive-app/rive-runtime#140 ·
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 91/100
rive-app/rive-runtime#137 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
rive-app/rive-runtime#134 ·
Tất cả issue của rive-app/rive-runtime
Issue tương tự
-
mlir
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
llvm/llvm-project#241070 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Page request: clang-replĐang mởhelp wanted new command
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
tldr-pages/tldr#25111 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Ask the `ServerHelper` for fresh headers on every poll in `Future::get`, as is done for cookiesĐang mởenhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
NVIDIA/cuda-quantum#5886 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
Maintainer thường phản hồi trong vòng 1 ngày