Skip to content

Commit

Permalink
DisplayList verifies surfaceContentVersion before each rendering to p…
Browse files Browse the repository at this point in the history
…revent duplicate drawing.
  • Loading branch information
Hparty committed Oct 30, 2024
1 parent b4a1231 commit d26869a
Show file tree
Hide file tree
Showing 19 changed files with 259 additions and 4 deletions.
6 changes: 6 additions & 0 deletions include/tgfx/core/Surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ class Surface {
*/
bool readPixels(const ImageInfo& dstInfo, void* dstPixels, int srcX = 0, int srcY = 0);

/**
* Returns the version of the content. The version is changed when the content is changed.
* The initial version is 1;
*/
uint32_t contentVersion() const;

private:
std::shared_ptr<RenderTargetProxy> renderTargetProxy = nullptr;
uint32_t _renderFlags = 0;
Expand Down
1 change: 1 addition & 0 deletions include/tgfx/layers/DisplayList.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ class DisplayList {

private:
std::shared_ptr<Layer> _root = nullptr;
uint32_t surfaceContentVersion = 0u;
};
} // namespace tgfx
5 changes: 4 additions & 1 deletion include/tgfx/layers/Layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Layer {
*/
static std::shared_ptr<Layer> Make();

virtual ~Layer() = default;
virtual ~Layer();

/**
* Returns the type of the layer.
Expand Down Expand Up @@ -528,5 +528,8 @@ class Layer {
} bitFields = {};

friend class DisplayList;
friend class LayerFilter;
friend class ShapeStyle;
friend class PathProvider;
};
} // namespace tgfx
6 changes: 6 additions & 0 deletions include/tgfx/layers/PathProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "tgfx/core/Path.h"

namespace tgfx {
class Layer;
/**
* PathProvider is an interface for classes that generates a Path. It defers the acquisition of the
* Path until it is actually required, allowing the Path to be invalidated and regenerate if
Expand Down Expand Up @@ -56,7 +57,12 @@ class PathProvider {
virtual Path onGeneratePath();

private:
void attachToLayer(const Layer* layer);
void detachFromLayer(const Layer* layer);
bool dirty = true;
Path path = {};

std::vector<std::weak_ptr<Layer>> owners;
friend class Layer;
};
} // namespace tgfx
2 changes: 2 additions & 0 deletions include/tgfx/layers/ShapeLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ class ShapeLayer : public Layer {
*/
void setStrokeEnd(float end);

~ShapeLayer() override;

protected:
ShapeLayer() = default;

Expand Down
9 changes: 9 additions & 0 deletions include/tgfx/layers/ShapeStyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "tgfx/core/Shader.h"

namespace tgfx {
class Layer;
/**
* ShapeStyle specifies the source color(s) for what is being drawn in a shape layer. There are
* three types of ShapeStyle: SolidColor, Gradient, and ImagePattern. Note: All ShapeStyle objects
Expand All @@ -36,6 +37,14 @@ class ShapeStyle {
*/
virtual std::shared_ptr<Shader> getShader() const = 0;

void invalidate();

void attachToLayer(const Layer* layer);

void detachFromLayer(const Layer* layer);

std::vector<std::weak_ptr<Layer>> owners;

friend class ShapeLayer;
};
} // namespace tgfx
9 changes: 9 additions & 0 deletions include/tgfx/layers/filters/LayerFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "tgfx/core/ImageFilter.h"

namespace tgfx {
class Layer;
/**
* LayerFilter represents a filter that applies effects to a layer, such as blurs, shadows, or color
* adjustments. LayerFilters are mutable and can be changed at any time.
Expand Down Expand Up @@ -52,12 +53,20 @@ class LayerFilter {
virtual std::shared_ptr<ImageFilter> onCreateImageFilter(float scale) = 0;

private:
void attachToLayer(const Layer* layer);

void detachFromLayer(const Layer* layer);

bool dirty = true;

float lastScale = 1.0f;

std::unique_ptr<Rect> _clipBounds = nullptr;

std::shared_ptr<ImageFilter> lastFilter;

std::vector<std::weak_ptr<Layer>> owners;

friend class Layer;
};
} // namespace tgfx
1 change: 1 addition & 0 deletions src/gpu/OpContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,6 @@ void OpContext::addOp(std::unique_ptr<Op> op) {
opsTask = drawingManager->addOpsTask(renderTargetProxy);
}
opsTask->addOp(std::move(op));
_contentVersion++;
}
} // namespace tgfx
5 changes: 5 additions & 0 deletions src/gpu/OpContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,13 @@ class OpContext {

void addOp(std::unique_ptr<Op> op);

uint32_t contentVersion() const {
return _contentVersion;
}

private:
std::shared_ptr<RenderTargetProxy> renderTargetProxy = nullptr;
std::shared_ptr<OpsRenderTask> opsTask = nullptr;
uint32_t _contentVersion = 1u;
};
} // namespace tgfx
7 changes: 7 additions & 0 deletions src/gpu/Surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,13 @@ bool Surface::readPixels(const ImageInfo& dstInfo, void* dstPixels, int srcX, in
return renderTarget->readPixels(dstInfo, dstPixels, srcX, srcY);
}

uint32_t Surface::contentVersion() const {
if (renderContext == nullptr) {
return 1u;
}
return renderContext->opContext->contentVersion();
}

bool Surface::aboutToDraw(const std::function<bool()>& willDiscardContent) {
if (cachedImage == nullptr) {
return true;
Expand Down
4 changes: 3 additions & 1 deletion src/layers/DisplayList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ Layer* DisplayList::root() const {
}

void DisplayList::render(Surface* surface, bool replaceAll) {
if (surface == nullptr) {
if (!surface || (surface->contentVersion() == surfaceContentVersion && !_root->bitFields.dirty &&
replaceAll)) {
return;
}
auto canvas = surface->getCanvas();
Expand All @@ -39,5 +40,6 @@ void DisplayList::render(Surface* surface, bool replaceAll) {
}
DrawArgs args(surface->getContext(), surface->renderFlags(), true);
_root->drawLayer(args, canvas, 1.0f, BlendMode::SrcOver);
surfaceContentVersion = surface->contentVersion();
}
} // namespace tgfx
38 changes: 38 additions & 0 deletions src/layers/Gradient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
/////////////////////////////////////////////////////////////////////////////////////////////////

#include "tgfx/layers/Gradient.h"
#include <tgfx/layers/Layer.h>

namespace tgfx {
std::shared_ptr<LinearGradient> Gradient::MakeLinear(const Point& startPoint,
Expand All @@ -35,20 +36,57 @@ std::shared_ptr<ConicGradient> Gradient::MakeConic(const Point& center, float st

void Gradient::setColors(std::vector<Color> colors) {
_colors = std::move(colors);
invalidate();
}

void Gradient::setPositions(std::vector<float> positions) {
_positions = std::move(positions);
invalidate();
}

void LinearGradient::setEndPoint(const Point& endPoint) {
_endPoint = endPoint;
invalidate();
}

void LinearGradient::setStartPoint(const Point& startPoint) {
_startPoint = startPoint;
invalidate();
}

std::shared_ptr<Shader> LinearGradient::getShader() const {
return Shader::MakeLinearGradient(_startPoint, _endPoint, _colors, _positions);
}

void RadialGradient::setCenter(const Point& center) {
_center = center;
invalidate();
}

void RadialGradient::setRadius(float radius) {
_radius = radius;
invalidate();
}

std::shared_ptr<Shader> RadialGradient::getShader() const {
return Shader::MakeRadialGradient(_center, _radius, _colors, _positions);
}

void ConicGradient::setStartAngle(float startAngle) {
_startAngle = startAngle;
invalidate();
}

void ConicGradient::setCenter(const Point& center) {
_center = center;
invalidate();
}

void ConicGradient::setEndAngle(float endAngle) {
_endAngle = endAngle;
invalidate();
}

std::shared_ptr<Shader> ConicGradient::getShader() const {
return Shader::MakeConicGradient(_center, _startAngle, _endAngle, _colors, _positions);
}
Expand Down
12 changes: 12 additions & 0 deletions src/layers/Layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ std::shared_ptr<Layer> Layer::Make() {
return layer;
}

Layer::~Layer() {
for (auto filter : _filters) {
filter->detachFromLayer(this);
}
}

Layer::Layer() {
memset(&bitFields, 0, sizeof(bitFields));
bitFields.visible = true;
Expand Down Expand Up @@ -137,7 +143,13 @@ void Layer::setFilters(std::vector<std::shared_ptr<LayerFilter>> value) {
std::equal(_filters.begin(), _filters.end(), value.begin())) {
return;
}
for (const auto& filter : _filters) {
filter->detachFromLayer(this);
}
_filters = std::move(value);
for (const auto& filter : _filters) {
filter->attachToLayer(this);
}
rasterizedContent = nullptr;
invalidate();
}
Expand Down
21 changes: 21 additions & 0 deletions src/layers/PathProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
/////////////////////////////////////////////////////////////////////////////////////////////////

#include "tgfx/layers/PathProvider.h"
#include "tgfx/layers/Layer.h"

namespace tgfx {
std::shared_ptr<PathProvider> PathProvider::Wrap(const Path& path) {
Expand All @@ -39,9 +40,29 @@ Path PathProvider::getPath() {

void PathProvider::invalidate() {
dirty = true;
for (auto& owner : owners) {
auto layer = owner.lock();
if (layer) {
layer->invalidateContent();
}
}
}

Path PathProvider::onGeneratePath() {
return path;
}

void PathProvider::attachToLayer(const Layer* layer) {
owners.push_back(layer->weakThis);
}

void PathProvider::detachFromLayer(const Layer* layer) {
for (auto it = owners.begin(); it != owners.end(); ++it) {
if (it->lock().get() == layer) {
owners.erase(it);
break;
}
}
}

} // namespace tgfx
21 changes: 21 additions & 0 deletions src/layers/ShapeLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,27 @@ void ShapeLayer::setFillStyle(std::shared_ptr<ShapeStyle> style) {
if (_fillStyle == style) {
return;
}
if (_fillStyle) {
_fillStyle->detachFromLayer(this);
}
_fillStyle = std::move(style);
if (_fillStyle) {
_fillStyle->attachToLayer(this);
}
invalidateContent();
}

void ShapeLayer::setStrokeStyle(std::shared_ptr<ShapeStyle> style) {
if (_strokeStyle == style) {
return;
}
if (_strokeStyle) {
_strokeStyle->detachFromLayer(this);
}
_strokeStyle = std::move(style);
if (_strokeStyle) {
_strokeStyle->attachToLayer(this);
}
invalidateContent();
}

Expand Down Expand Up @@ -139,6 +151,15 @@ void ShapeLayer::setStrokeEnd(float end) {
invalidateContent();
}

ShapeLayer::~ShapeLayer() {
if (_strokeStyle) {
_strokeStyle->detachFromLayer(this);
}
if (_fillStyle) {
_fillStyle->detachFromLayer(this);
}
}

std::unique_ptr<LayerContent> ShapeLayer::onUpdateContent() {
std::vector<std::unique_ptr<LayerContent>> contents = {};
auto path = _path.isEmpty() ? _pathProvider->getPath() : _path;
Expand Down
45 changes: 45 additions & 0 deletions src/layers/ShapeStyle.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making tgfx available.
//
// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////

#include "tgfx/layers/ShapeStyle.h"
#include "tgfx/layers/Layer.h"

namespace tgfx {
void ShapeStyle::invalidate() {
for (auto& owner : owners) {
auto layer = owner.lock();
if (layer) {
layer->invalidateContent();
}
}
}

void ShapeStyle::attachToLayer(const Layer* layer) {
owners.push_back(layer->weakThis);
}

void ShapeStyle::detachFromLayer(const Layer* layer) {
for (auto it = owners.begin(); it != owners.end(); ++it) {
if (it->lock().get() == layer) {
owners.erase(it);
break;
}
}
}

} // namespace tgfx
Loading

0 comments on commit d26869a

Please sign in to comment.