Skip to content

Commit

Permalink
Add a lockTextureProxy() method to the Image class. (#231)
Browse files Browse the repository at this point in the history
  • Loading branch information
domchen committed Sep 14, 2024
1 parent ae2be28 commit 6ec728b
Show file tree
Hide file tree
Showing 18 changed files with 127 additions and 75 deletions.
7 changes: 5 additions & 2 deletions include/tgfx/core/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ class FPArgs;
class Context;
class ImageFilter;
class FragmentProcessor;
class ImageCodec;
class DrawOp;
class TextureProxy;

/**
* The Image class represents a two-dimensional array of pixels for drawing. These pixels can be
Expand Down Expand Up @@ -285,12 +284,16 @@ class Image {
virtual std::shared_ptr<Image> onMakeWithFilter(std::shared_ptr<ImageFilter> filter,
Point* offset, const Rect* clipRect) const;

virtual std::shared_ptr<TextureProxy> lockTextureProxy(Context* context,
uint32_t renderFlags = 0) const;

virtual std::unique_ptr<FragmentProcessor> asFragmentProcessor(
const FPArgs& args, TileMode tileModeX, TileMode tileModeY, const SamplingOptions& sampling,
const Matrix* localMatrix) const = 0;

friend class FragmentProcessor;
friend class TransformImage;
friend class RGBAAAImage;
friend class RasterImage;
friend class ImageShader;
};
Expand Down
5 changes: 5 additions & 0 deletions include/tgfx/core/ImageFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ class ImageFilter {

bool applyCropRect(const Rect& srcRect, Rect* dstRect, const Rect* clipBounds = nullptr) const;

std::unique_ptr<FragmentProcessor> makeFPFromFilteredImage(std::shared_ptr<Image> source,
const FPArgs& args,
const SamplingOptions& sampling,
const Matrix* localMatrix) const;

friend class DropShadowImageFilter;
friend class ComposeImageFilter;
friend class FilterImage;
Expand Down
35 changes: 30 additions & 5 deletions src/core/ImageFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "gpu/DrawingManager.h"
#include "gpu/OpContext.h"
#include "gpu/processors/FragmentProcessor.h"
#include "gpu/processors/TextureEffect.h"
#include "gpu/proxies/RenderTargetProxy.h"

namespace tgfx {
Expand All @@ -37,9 +38,9 @@ std::shared_ptr<TextureProxy> ImageFilter::onFilterImage(Context* context,
std::shared_ptr<Image> source,
const Rect& filterBounds, bool mipmapped,
uint32_t renderFlags) const {
auto renderTarget = RenderTargetProxy::Make(context, static_cast<int>(filterBounds.width()),
static_cast<int>(filterBounds.height()),
PixelFormat::RGBA_8888, 1, mipmapped);
auto renderTarget = RenderTargetProxy::MakeFallback(
context, static_cast<int>(filterBounds.width()), static_cast<int>(filterBounds.height()),
source->isAlphaOnly(), 1, mipmapped);
if (renderTarget == nullptr) {
return nullptr;
}
Expand All @@ -51,8 +52,8 @@ std::shared_ptr<TextureProxy> ImageFilter::onFilterImage(Context* context,
if (!processor) {
return nullptr;
}
OpContext opContext(renderTarget);
opContext.fillWithFP(std::move(processor), Matrix::I(), true);
OpContext opContext(renderTarget, true);
opContext.fillWithFP(std::move(processor), Matrix::I());
return renderTarget->getTextureProxy();
}

Expand All @@ -66,4 +67,28 @@ bool ImageFilter::applyCropRect(const Rect& srcRect, Rect* dstRect, const Rect*
dstRect->roundOut();
return true;
}

std::unique_ptr<FragmentProcessor> ImageFilter::makeFPFromFilteredImage(
std::shared_ptr<Image> source, const FPArgs& args, const SamplingOptions& sampling,
const Matrix* localMatrix) const {
auto inputBounds = Rect::MakeWH(source->width(), source->height());
auto clipBounds = args.drawRect;
if (localMatrix) {
clipBounds = localMatrix->mapRect(clipBounds);
}
Rect dstBounds = Rect::MakeEmpty();
if (!applyCropRect(inputBounds, &dstBounds, &clipBounds)) {
return nullptr;
}
auto mipmapped = source->hasMipmaps() && sampling.mipmapMode != MipmapMode::None;
auto textureProxy = onFilterImage(args.context, source, dstBounds, mipmapped, args.renderFlags);
if (textureProxy == nullptr) {
return nullptr;
}
auto fpMatrix = Matrix::MakeTrans(-dstBounds.x(), -dstBounds.y());
if (localMatrix != nullptr) {
fpMatrix.preConcat(*localMatrix);
}
return TextureEffect::Make(std::move(textureProxy), sampling, &fpMatrix);
}
} // namespace tgfx
34 changes: 9 additions & 25 deletions src/filters/BlurImageFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ void BlurImageFilter::draw(std::shared_ptr<RenderTargetProxy> renderTarget,
auto blurProcessor =
DualBlurFragmentProcessor::Make(isDown ? DualBlurPassMode::Down : DualBlurPassMode::Up,
std::move(imageProcessor), blurOffset, texelSize);
OpContext opContext(std::move(renderTarget));
opContext.fillWithFP(std::move(blurProcessor), localMatrix, true);
OpContext opContext(std::move(renderTarget), true);
opContext.fillWithFP(std::move(blurProcessor), localMatrix);
}

Rect BlurImageFilter::onFilterBounds(const Rect& srcRect) const {
Expand All @@ -109,9 +109,10 @@ std::shared_ptr<TextureProxy> BlurImageFilter::onFilterImage(Context* context,
const Rect& filterBounds,
bool mipmapped,
uint32_t renderFlags) const {
auto lastRenderTarget = RenderTargetProxy::Make(context, static_cast<int>(filterBounds.width()),
static_cast<int>(filterBounds.height()),
PixelFormat::RGBA_8888, 1, mipmapped);
auto isAlphaOnly = source->isAlphaOnly();
auto lastRenderTarget = RenderTargetProxy::MakeFallback(
context, static_cast<int>(filterBounds.width()), static_cast<int>(filterBounds.height()),
isAlphaOnly, 1, mipmapped);
if (lastRenderTarget == nullptr) {
return nullptr;
}
Expand All @@ -127,7 +128,8 @@ std::shared_ptr<TextureProxy> BlurImageFilter::onFilterImage(Context* context,
}
auto downWidth = std::max(static_cast<int>(roundf(imageBounds.width() * downScaling)), 1);
auto downHeight = std::max(static_cast<int>(roundf(imageBounds.height() * downScaling)), 1);
auto renderTarget = RenderTargetProxy::Make(args.context, downWidth, downHeight);
auto renderTarget =
RenderTargetProxy::MakeFallback(args.context, downWidth, downHeight, isAlphaOnly);
if (renderTarget == nullptr) {
return nullptr;
}
Expand All @@ -148,24 +150,6 @@ std::shared_ptr<TextureProxy> BlurImageFilter::onFilterImage(Context* context,
std::unique_ptr<FragmentProcessor> BlurImageFilter::asFragmentProcessor(
std::shared_ptr<Image> source, const FPArgs& args, const SamplingOptions& sampling,
const Matrix* localMatrix) const {
auto inputBounds = Rect::MakeWH(source->width(), source->height());
auto clipBounds = args.drawRect;
if (localMatrix) {
clipBounds = localMatrix->mapRect(clipBounds);
}
Rect dstBounds = Rect::MakeEmpty();
if (!applyCropRect(inputBounds, &dstBounds, &clipBounds)) {
return nullptr;
}
auto mipmapped = source->hasMipmaps() && sampling.mipmapMode != MipmapMode::None;
auto textureProxy = onFilterImage(args.context, source, dstBounds, mipmapped, args.renderFlags);
if (textureProxy == nullptr) {
return nullptr;
}
auto fpMatrix = Matrix::MakeTrans(-dstBounds.x(), -dstBounds.y());
if (localMatrix != nullptr) {
fpMatrix.preConcat(*localMatrix);
}
return TextureEffect::Make(std::move(textureProxy), sampling, &fpMatrix);
return makeFPFromFilteredImage(source, args, sampling, localMatrix);
}
} // namespace tgfx
15 changes: 8 additions & 7 deletions src/filters/BlurImageFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,15 @@

#pragma once

#include "gpu/proxies/RenderTargetProxy.h"
#include "tgfx/core/ImageFilter.h"
#include "tgfx/gpu/Surface.h"

namespace tgfx {
class BlurImageFilter : public ImageFilter {
public:
BlurImageFilter(Point blurOffset, float downScaling, int iteration, TileMode tileMode);

private:
Point blurOffset;
float downScaling;
int iteration;
TileMode tileMode;

protected:
Rect onFilterBounds(const Rect& srcRect) const override;

std::shared_ptr<TextureProxy> onFilterImage(Context* context, std::shared_ptr<Image> source,
Expand All @@ -46,5 +41,11 @@ class BlurImageFilter : public ImageFilter {
void draw(std::shared_ptr<RenderTargetProxy> renderTarget,
std::unique_ptr<FragmentProcessor> imageProcessor, const Rect& imageBounds,
bool isDown) const;

private:
Point blurOffset;
float downScaling;
int iteration;
TileMode tileMode;
};
} // namespace tgfx
10 changes: 8 additions & 2 deletions src/gpu/OpContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@
#include "gpu/ops/FillRectOp.h"

namespace tgfx {
void OpContext::fillWithFP(std::unique_ptr<FragmentProcessor> fp, const Matrix& localMatrix,
bool autoResolve) {
OpContext::~OpContext() {
if (autoResolve) {
auto drawingManager = renderTargetProxy->getContext()->drawingManager();
drawingManager->addTextureResolveTask(renderTargetProxy);
}
}

void OpContext::fillWithFP(std::unique_ptr<FragmentProcessor> fp, const Matrix& localMatrix) {
fillRectWithFP(Rect::MakeWH(renderTargetProxy->width(), renderTargetProxy->height()),
std::move(fp), localMatrix);
if (autoResolve) {
Expand Down
13 changes: 9 additions & 4 deletions src/gpu/OpContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@ namespace tgfx {
*/
class OpContext {
public:
explicit OpContext(std::shared_ptr<RenderTargetProxy> renderTargetProxy)
: renderTargetProxy(std::move(renderTargetProxy)) {
/**
* If autoResolve is true, the RenderTarget will be resolved after OpContext is destroyed.
*/
explicit OpContext(std::shared_ptr<RenderTargetProxy> renderTargetProxy, bool autoResolve = false)
: renderTargetProxy(std::move(renderTargetProxy)), autoResolve(autoResolve) {
}

~OpContext();

RenderTargetProxy* renderTarget() const {
return renderTargetProxy.get();
}

void fillWithFP(std::unique_ptr<FragmentProcessor> fp, const Matrix& localMatrix,
bool autoResolve = false);
void fillWithFP(std::unique_ptr<FragmentProcessor> fp, const Matrix& localMatrix);

void fillRectWithFP(const Rect& dstRect, std::unique_ptr<FragmentProcessor> fp,
const Matrix& localMatrix);
Expand All @@ -47,5 +51,6 @@ class OpContext {
private:
std::shared_ptr<RenderTargetProxy> renderTargetProxy = nullptr;
std::shared_ptr<OpsRenderTask> opsTask = nullptr;
bool autoResolve = false;
};
} // namespace tgfx
7 changes: 2 additions & 5 deletions src/gpu/RenderContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,12 +404,9 @@ std::shared_ptr<TextureProxy> RenderContext::getClipTexture(const Path& clip) {
auto drawOp =
TriangulatingPathOp::Make(Color::White(), clip, rasterizeMatrix, nullptr, renderFlags);
drawOp->setAA(AAType::Coverage);
auto renderTarget = RenderTargetProxy::Make(getContext(), width, height, PixelFormat::ALPHA_8);
auto renderTarget = RenderTargetProxy::MakeFallback(getContext(), width, height, true);
if (renderTarget == nullptr) {
renderTarget = RenderTargetProxy::Make(getContext(), width, height, PixelFormat::RGBA_8888);
if (renderTarget == nullptr) {
return nullptr;
}
return nullptr;
}
OpContext context(renderTarget);
// Since the clip may not coverage the entire render target, we need to clear the render target
Expand Down
1 change: 1 addition & 0 deletions src/gpu/RenderContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <optional>
#include "core/DrawContext.h"
#include "gpu/OpContext.h"
#include "gpu/ops/DrawOp.h"

namespace tgfx {
class RenderContext : public DrawContext {
Expand Down
3 changes: 1 addition & 2 deletions src/gpu/ops/ClearOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ class ClearOp : public Op {
void execute(RenderPass* renderPass) override;

private:
explicit ClearOp(Color color, const Rect& scissor)
: Op(ClassID()), color(color), scissor(scissor) {
ClearOp(Color color, const Rect& scissor) : Op(ClassID()), color(color), scissor(scissor) {
}

bool onCombineIfPossible(Op* op) override;
Expand Down
10 changes: 10 additions & 0 deletions src/gpu/proxies/RenderTargetProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ std::shared_ptr<RenderTargetProxy> RenderTargetProxy::MakeFallback(Context* cont
return nullptr;
}

std::shared_ptr<RenderTargetProxy> RenderTargetProxy::MakeFallback(Context* context, int width,
int height, bool isAlphaOnly,
int sampleCount, bool mipmapped,
ImageOrigin origin) {
auto formats = isAlphaOnly
? std::vector<PixelFormat>{PixelFormat::ALPHA_8, PixelFormat::RGBA_8888}
: std::vector<PixelFormat>{PixelFormat::RGBA_8888};
return MakeFallback(context, width, height, std::move(formats), sampleCount, mipmapped, origin);
}

std::shared_ptr<RenderTargetProxy> RenderTargetProxy::Create(Context* context, int width,
int height, PixelFormat format,
int sampleCount, bool mipmapped,
Expand Down
11 changes: 11 additions & 0 deletions src/gpu/proxies/RenderTargetProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ class RenderTargetProxy : public ResourceProxy {
bool mipmapped = false,
ImageOrigin origin = ImageOrigin::TopLeft);

/**
* Creates a new RenderTargetProxy instance with the specified context, width, height, sample
* count, mipmap state, and origin. If `isAlphaOnly` is true, it will try to use the ALPHA_8
* format and fall back to RGBA_8888 if not supported. Otherwise, it will use the RGBA_8888
* format.
*/
static std::shared_ptr<RenderTargetProxy> MakeFallback(Context* context, int width, int height,
bool isAlphaOnly, int sampleCount = 1,
bool mipmapped = false,
ImageOrigin origin = ImageOrigin::TopLeft);

/**
* Returns the width of the render target.
*/
Expand Down
29 changes: 20 additions & 9 deletions src/images/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
/////////////////////////////////////////////////////////////////////////////////////////////////

#include "tgfx/core/Image.h"
#include "gpu/OpContext.h"
#include "gpu/ProxyProvider.h"
#include "gpu/ops/FillRectOp.h"
#include "images/BufferImage.h"
#include "images/FilterImage.h"
#include "images/GeneratorImage.h"
Expand All @@ -27,7 +27,6 @@
#include "images/TextureImage.h"
#include "tgfx/core/ImageCodec.h"
#include "tgfx/core/Pixmap.h"
#include "tgfx/gpu/Surface.h"

namespace tgfx {
class PixelDataConverter : public ImageGenerator {
Expand Down Expand Up @@ -156,13 +155,7 @@ std::shared_ptr<Image> Image::makeRasterized(float rasterizationScale,
}

std::shared_ptr<Image> Image::makeTextureImage(Context* context) const {
auto surface = Surface::Make(context, width(), height(), isAlphaOnly(), 1, hasMipmaps());
if (surface == nullptr) {
return nullptr;
}
auto canvas = surface->getCanvas();
canvas->drawImage(weakThis.lock(), 0, 0);
return surface->makeImageSnapshot();
return TextureImage::Wrap(lockTextureProxy(context));
}

std::shared_ptr<Image> Image::makeDecoded(Context* context) const {
Expand Down Expand Up @@ -236,4 +229,22 @@ std::shared_ptr<Image> Image::makeRGBAAA(int displayWidth, int displayHeight, in
std::shared_ptr<Image> Image::onMakeRGBAAA(int, int, int, int) const {
return nullptr;
}

std::shared_ptr<TextureProxy> Image::lockTextureProxy(Context* context,
uint32_t renderFlags) const {
auto renderTarget =
RenderTargetProxy::MakeFallback(context, width(), height(), isAlphaOnly(), 1, hasMipmaps());
if (renderTarget == nullptr) {
return nullptr;
}
auto drawRect = Rect::MakeWH(width(), height());
FPArgs args(context, renderFlags, drawRect, Matrix::I());
auto processor = FragmentProcessor::Make(weakThis.lock(), args, {});
if (processor == nullptr) {
return nullptr;
}
OpContext opContext(renderTarget, true);
opContext.fillWithFP(std::move(processor), Matrix::I());
return renderTarget->getTextureProxy();
}
} // namespace tgfx
3 changes: 1 addition & 2 deletions src/images/RGBAAAImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ std::shared_ptr<Image> RGBAAAImage::onCloneWith(std::shared_ptr<Image> newSource
std::unique_ptr<FragmentProcessor> RGBAAAImage::asFragmentProcessor(
const FPArgs& args, TileMode, TileMode, const SamplingOptions& sampling,
const Matrix* localMatrix) const {
auto proxy = std::static_pointer_cast<ResourceImage>(source)->lockTextureProxy(args.context,
args.renderFlags);
auto proxy = source->lockTextureProxy(args.context, args.renderFlags);
auto matrix = concatLocalMatrix(localMatrix);
return TextureEffect::MakeRGBAAA(std::move(proxy), alphaStart, sampling, AddressOf(matrix));
}
Expand Down
4 changes: 2 additions & 2 deletions src/images/RasterImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ std::shared_ptr<TextureProxy> RasterImage::onLockTextureProxy(Context* context,
if (processor == nullptr) {
return nullptr;
}
OpContext opContext(renderTarget);
opContext.fillWithFP(std::move(processor), Matrix::I(), true);
OpContext opContext(renderTarget, true);
opContext.fillWithFP(std::move(processor), Matrix::I());
return textureProxy;
}

Expand Down
Loading

0 comments on commit 6ec728b

Please sign in to comment.