Skip to content

Commit

Permalink
Remove unnecessary drawAsClear calls in the drawRect() method to opti…
Browse files Browse the repository at this point in the history
…mize performance. (#439)
  • Loading branch information
domchen authored Jan 22, 2025
1 parent 1887640 commit a53862a
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 83 deletions.
54 changes: 16 additions & 38 deletions src/gpu/RenderContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,55 +66,37 @@ Rect RenderContext::getClipBounds(const Path& clip) {
return clip.isEmpty() ? Rect::MakeEmpty() : clip.getBounds();
}

static bool HasColorOnly(const FillStyle& style) {
return style.colorFilter == nullptr && style.shader == nullptr && style.maskFilter == nullptr;
}

void RenderContext::drawStyle(const MCState& state, const FillStyle& style) {
auto rect = Rect::MakeWH(opContext->renderTarget()->width(), opContext->renderTarget()->height());
if (HasColorOnly(style) && style.isOpaque() && state.clip.isEmpty() &&
state.clip.isInverseFillType()) {
auto color = style.color.premultiply();
auto format = opContext->renderTarget()->format();
const auto& writeSwizzle = getContext()->caps()->getWriteSwizzle(format);
color = writeSwizzle.applyTo(color);
addOp(ClearOp::Make(color, rect), [] { return true; });
return;
}
auto fillStyle = style;
if (fillStyle.shader) {
fillStyle.shader = fillStyle.shader->makeWithMatrix(state.matrix);
}
if (fillStyle.maskFilter) {
fillStyle.maskFilter = fillStyle.maskFilter->makeWithMatrix(state.matrix);
}
drawRect(Rect::MakeWH(opContext->renderTarget()->width(), opContext->renderTarget()->height()),
MCState{state.clip}, fillStyle);
drawRect(rect, MCState{state.clip}, fillStyle);
}

void RenderContext::drawRect(const Rect& rect, const MCState& state, const FillStyle& style) {
DEBUG_ASSERT(!rect.isEmpty());
if (drawAsClear(rect, state, style)) {
return;
}
auto drawOp = RectDrawOp::Make(style.color.premultiply(), rect, state.matrix);
addDrawOp(std::move(drawOp), rect, state, style);
}

static bool HasColorOnly(const FillStyle& style) {
return style.colorFilter == nullptr && style.shader == nullptr && style.maskFilter == nullptr;
}

bool RenderContext::drawAsClear(const Rect& rect, const MCState& state, const FillStyle& style) {
if (!HasColorOnly(style) || !style.isOpaque() || !state.matrix.rectStaysRect()) {
return false;
}
auto color = style.color.premultiply();
auto bounds = rect;
state.matrix.mapRect(&bounds);
auto [clipRect, useScissor] = getClipRect(state.clip, &bounds);
if (clipRect.has_value()) {
auto format = opContext->renderTarget()->format();
const auto& writeSwizzle = getContext()->caps()->getWriteSwizzle(format);
color = writeSwizzle.applyTo(color);
if (useScissor) {
addOp(ClearOp::Make(color, *clipRect), [] { return false; });
return true;
}
if (clipRect->isEmpty()) {
addOp(ClearOp::Make(color, bounds), [] { return true; });
return true;
}
}
return false;
}

void RenderContext::drawRRect(const RRect& rRect, const MCState& state, const FillStyle& style) {
DEBUG_ASSERT(!rRect.rect.isEmpty());
auto drawOp = RRectDrawOp::Make(style.color.premultiply(), rRect, state.matrix);
Expand Down Expand Up @@ -309,15 +291,11 @@ static void FlipYIfNeeded(Rect* rect, const RenderTargetProxy* renderTarget) {
}
}

std::pair<std::optional<Rect>, bool> RenderContext::getClipRect(const Path& clip,
const Rect* deviceBounds) {
std::pair<std::optional<Rect>, bool> RenderContext::getClipRect(const Path& clip) {
auto rect = Rect::MakeEmpty();
if (clip.isInverseFillType() || !clip.isRect(&rect)) {
return {{}, false};
}
if (deviceBounds != nullptr && !rect.intersect(*deviceBounds)) {
return {{}, false};
}
auto renderTarget = opContext->renderTarget();
FlipYIfNeeded(&rect, renderTarget);
if (IsPixelAligned(rect)) {
Expand Down
4 changes: 1 addition & 3 deletions src/gpu/RenderContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,11 @@ class RenderContext : public DrawContext {
explicit RenderContext(Surface* surface);
Context* getContext() const;
std::shared_ptr<TextureProxy> getClipTexture(const Path& clip, AAType aaType);
std::pair<std::optional<Rect>, bool> getClipRect(const Path& clip,
const Rect* drawBounds = nullptr);
std::pair<std::optional<Rect>, bool> getClipRect(const Path& clip);
std::unique_ptr<FragmentProcessor> getClipMask(const Path& clip, const Rect& deviceBounds,
const Matrix& viewMatrix, AAType aaType,
Rect* scissorRect);
Rect getClipBounds(const Path& clip);
bool drawAsClear(const Rect& rect, const MCState& state, const FillStyle& style);
void drawColorGlyphs(std::shared_ptr<GlyphRunList> glyphRunList, const MCState& state,
const FillStyle& style);
void addDrawOp(std::unique_ptr<DrawOp> op, const Rect& localBounds, const MCState& state,
Expand Down
1 change: 0 additions & 1 deletion test/baseline/version.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"inversePath_text": "59ca683",
"merge_draw_call_rect": "d010fb8",
"merge_draw_call_rrect": "d010fb8",
"merge_draw_clear_op": "d010fb8",
"mipmap_linear": "3b0ec3b",
"mipmap_linear_hardware": "3b0ec3b",
"mipmap_linear_texture_effect": "d010fb8",
Expand Down
41 changes: 0 additions & 41 deletions test/src/CanvasTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,47 +183,6 @@ TGFX_TEST(CanvasTest, merge_draw_call_rrect) {
EXPECT_TRUE(Baseline::Compare(surface, "CanvasTest/merge_draw_call_rrect"));
}

TGFX_TEST(CanvasTest, merge_draw_clear_op) {
ContextScope scope;
auto context = scope.getContext();
ASSERT_TRUE(context != nullptr);
int width = 72;
int height = 72;
auto surface = Surface::Make(context, width, height);
auto canvas = surface->getCanvas();
canvas->clear(Color::White());
canvas->clipRect(Rect::MakeWH(width, height));
canvas->save();
Path path;
path.addRect(Rect::MakeXYWH(0.f, 0.f, 10.f, 10.f));
canvas->clipPath(path);
canvas->clear(Color::White());
canvas->restore();
Paint paint;
paint.setColor(Color{0.8f, 0.8f, 0.8f, 1.f});
int tileSize = 8;
size_t drawCallCount = 0;
for (int y = 0; y < height; y += tileSize) {
bool draw = (y / tileSize) % 2 == 1;
for (int x = 0; x < width; x += tileSize) {
if (draw) {
auto rect = Rect::MakeXYWH(static_cast<float>(x), static_cast<float>(y),
static_cast<float>(tileSize), static_cast<float>(tileSize));
canvas->drawRect(rect, paint);
drawCallCount++;
}
draw = !draw;
}
}

auto* drawingManager = context->drawingManager();
EXPECT_TRUE(drawingManager->renderTasks.size() == 1);
auto task = std::static_pointer_cast<OpsRenderTask>(drawingManager->renderTasks[0]);
EXPECT_TRUE(task->ops.size() == drawCallCount + 1);
context->flush();
EXPECT_TRUE(Baseline::Compare(surface, "CanvasTest/merge_draw_clear_op"));
}

TGFX_TEST(CanvasTest, textShape) {
auto serifTypeface =
Typeface::MakeFromPath(ProjectPath::Absolute("resources/font/NotoSerifSC-Regular.otf"));
Expand Down

0 comments on commit a53862a

Please sign in to comment.