Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isFlat() and isYUV() methods to Image and rename makeRasterized() to makeFlattened(). #343

Merged
merged 1 commit into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 36 additions & 31 deletions include/tgfx/core/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,14 @@ class Image {
*/
virtual bool isAlphaOnly() const = 0;

/**
* Returns true if the Image is in the YUV format.
*/
virtual bool isYUV() const = 0;

/**
* Returns true if the Image has mipmap levels. The flag was set by the makeMipmapped() method,
* which may be ignored if the GPU or the associated image source does not support mipmaps.
* which may be ignored if the GPU or the associated image source doesn’t support mipmaps.
*/
virtual bool hasMipmaps() const {
return false;
Expand All @@ -202,39 +207,32 @@ class Image {
}

/**
* Returns true if the Image has complex transforms that can't be drawn as a single texture with a
* UV matrix. Complex transforms may include subsets, filters, and RGBAAA layouts. Returns false
* if the Image is rasterized or only has orientation and scale transforms.
* Returns true if the Image is guaranteed to produce a single-plane texture without extra
* transforms and can be cached for repeat drawing. Extra transforms may include orientation,
* scale, subsets, filters, or RGBAAA layouts. A YUV Image is also not flat since it has multiple
* planes.
*/
virtual bool isComplex() const = 0;
virtual bool isFlat() const = 0;

/**
* Retrieves the backend texture of the Image. Returns an invalid BackendTexture if the Image is
* not backed by a Texture. If the origin is not nullptr, the origin of the backend texture is
* returned.
*/
virtual BackendTexture getBackendTexture(Context* context, ImageOrigin* origin = nullptr) const;

/**
* Returns a rasterized Image with the same content as this Image, as if this Image were drawn to
* the returned Image. Unlike the makeTextureImage() method, this method does not perform a draw
* Returns a flattened Image with the same content as this Image, as if this Image were drawn to
* the returned Image. Unlike the makeTextureImage() method, this method doesn’t perform a draw
* operation immediately. Instead, it defers the draw operation until it is actually required.
* A rasterized Image can be represented as a single GPU texture without any transforms and can be
* cached for repeated drawing. By default, an Image directly backed by an ImageBuffer, an
* ImageGenerator, or a GPU texture is rasterized. Other images are not rasterized unless this
* method explicitly creates them.
* For example, if you create a subset Image from a rasterized Image, the subset Image does not
* create its own GPU cache but uses the full resolution cache created by the original Image.
* If you want the subset Image to create its own GPU cache, you should call makeRasterized() on
* the subset Image.
* @param mipmapped Specifies whether the rasterized Image should have mipmaps. Ignored if the
* Image is already rasterized.
* The flattened Image is guaranteed to produce a single-plane texture without extra transforms
* and can be cached for repeat drawing. This method is useful for caching the drawing result of
* a complex Image for repeated use.
* For example, if you create a subset Image from a flat Image, the subset Image doesn’t create
* its own GPU cache but uses the full resolution cache created by the original Image. If you want
* the subset Image to create its own GPU cache, you should call makeFlattened() on the subset
* Image.
* @param mipmapped Specifies whether the flattened Image should have mipmaps. Ignored if the
* Image is already flat.
* @param sampling The sampling options may be applied if the image has scaling transforms.
* Ignored if the Image is already rasterized.
* @return If the Image is already rasterized, the original Image is returned.
* Ignored if the Image is already flat.
* @return If the Image is already flat, the original Image is returned.
*/
virtual std::shared_ptr<Image> makeRasterized(bool mipmapped = false,
const SamplingOptions& sampling = {}) const;
std::shared_ptr<Image> makeFlattened(bool mipmapped = false,
const SamplingOptions& sampling = {}) const;

/**
* Returns an Image backed by a GPU texture associated with the given context. If a corresponding
Expand All @@ -247,6 +245,13 @@ class Image {
virtual std::shared_ptr<Image> makeTextureImage(Context* context,
const SamplingOptions& sampling = {}) const;

/**
* Retrieves the backend texture of the Image. Returns an invalid BackendTexture if the Image is
* not backed by a Texture. If the origin is not nullptr, the origin of the backend texture is
* returned.
*/
virtual BackendTexture getBackendTexture(Context* context, ImageOrigin* origin = nullptr) const;

/**
* Returns a fully decoded Image from this Image. The returned Image shares the same GPU cache
* with the original Image and immediately schedules an asynchronous decoding task, which will not
Expand Down Expand Up @@ -322,10 +327,10 @@ class Image {
Point* offset, const Rect* clipRect) const;

/**
* Returns a rasterized texture proxy for the entire Image.
* Returns a texture proxy for the entire Image.
* @param args The TPArgs used to create the texture proxy.
* @param sampling The sampling options applied when rasterizing the Image. This option
* may be ignored if the Image or its nested Images are already rasterized.
* may be ignored if the Image has no scaling transforms.
*/
virtual std::shared_ptr<TextureProxy> lockTextureProxy(const TPArgs& args,
const SamplingOptions& sampling) const;
Expand All @@ -348,7 +353,7 @@ class Image {
friend class RuntimeImageFilter;
friend class TransformImage;
friend class RGBAAAImage;
friend class RasterImage;
friend class FlattenImage;
friend class ImageShader;
};
} // namespace tgfx
5 changes: 5 additions & 0 deletions include/tgfx/core/ImageBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ class ImageBuffer {
*/
virtual bool isAlphaOnly() const = 0;

/**
* Returns true if the ImageBuffer is in the YUV format.
*/
virtual bool isYUV() const = 0;

/**
* Returns true if the ImageBuffer is expired, indicating that it cannot create any new textures.
* However, you can still safely access all of its properties across threads.
Expand Down
4 changes: 4 additions & 0 deletions include/tgfx/core/ImageCodec.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ class ImageCodec : public ImageGenerator {
return false;
}

bool isYUV() const override {
return false;
}

/**
* Decodes the image with the specified image info into the given pixels. Returns true if the
* decoding was successful. Note that we do not recommend calling this method due to performance
Expand Down
7 changes: 7 additions & 0 deletions include/tgfx/core/ImageFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ class ImageFilter {
return false;
}

/**
* Returns true if this filter requires the source image to be flattened.
*/
virtual bool requireFlatSource() const {
return false;
}

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

std::unique_ptr<FragmentProcessor> makeFPFromTextureProxy(std::shared_ptr<Image> source,
Expand Down
5 changes: 5 additions & 0 deletions include/tgfx/core/ImageGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ class ImageGenerator {
*/
virtual bool isAlphaOnly() const = 0;

/**
* Returns true if the ImageBuffer generated by this ImageGenerator is in the YUV format.
*/
virtual bool isYUV() const = 0;

/**
* Returns true if the ImageGenerator supports asynchronous decoding. If so, the makeBuffer()
* method can be called from an arbitrary thread. Otherwise, the makeBuffer() method must be
Expand Down
2 changes: 1 addition & 1 deletion include/tgfx/gpu/RuntimeEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class RuntimeEffect {
// RuntimeProgram will not be released.
UniqueType uniqueType = {};

std::vector<std::shared_ptr<Image>> extraInputs;
std::vector<std::shared_ptr<Image>> extraInputs = {};

friend class RuntimeDrawTask;
friend class RuntimeImageFilter;
Expand Down
4 changes: 4 additions & 0 deletions src/core/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class GlyphImageGenerator : public ImageGenerator {
return !scalerContext->hasColor();
}

bool isYUV() const override {
return false;
}

protected:
std::shared_ptr<ImageBuffer> onMakeBuffer(bool tryHardware) const override {
return scalerContext->generateImage(glyphID, tryHardware);
Expand Down
8 changes: 8 additions & 0 deletions src/core/ImageBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class PixelData : public ImageBuffer {
return info.isAlphaOnly();
}

bool isYUV() const override {
return false;
}

protected:
std::shared_ptr<Texture> onMakeTexture(Context* context, bool mipmapped) const override {
switch (info.colorType()) {
Expand Down Expand Up @@ -85,6 +89,10 @@ class YUVBuffer : public ImageBuffer {
return false;
}

bool isYUV() const override {
return true;
}

protected:
std::shared_ptr<Texture> onMakeTexture(Context* context, bool) const override {
if (format == YUVPixelFormat::NV12) {
Expand Down
12 changes: 12 additions & 0 deletions src/core/ImageDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class ImageBufferWrapper : public ImageDecoder {
return imageBuffer->isAlphaOnly();
}

bool isYUV() const override {
return imageBuffer->isYUV();
}

std::shared_ptr<ImageBuffer> decode() const override {
return imageBuffer;
}
Expand All @@ -66,6 +70,10 @@ class ImageGeneratorWrapper : public ImageDecoder {
return imageGenerator->isAlphaOnly();
}

bool isYUV() const override {
return imageGenerator->isYUV();
}

std::shared_ptr<ImageBuffer> decode() const override {
return imageGenerator->makeBuffer(tryHardware);
}
Expand Down Expand Up @@ -95,6 +103,10 @@ class AsyncImageDecoder : public ImageDecoder {
return imageGenerator->isAlphaOnly();
}

bool isYUV() const override {
return imageGenerator->isYUV();
}

std::shared_ptr<ImageBuffer> decode() const override {
return task->wait();
}
Expand Down
5 changes: 5 additions & 0 deletions src/core/ImageDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ class ImageDecoder {
*/
virtual bool isAlphaOnly() const = 0;

/**
* Returns true if the decoded image is in the YUV format.
*/
virtual bool isYUV() const = 0;

/**
* Returns the decoded ImageBuffer.
*/
Expand Down
4 changes: 4 additions & 0 deletions src/core/ImageReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class ImageReaderBuffer : public ImageBuffer {
return imageReader->stream->isAlphaOnly();
}

bool isYUV() const override {
return imageReader->stream->isYUV();
}

bool expired() const override {
return imageReader->checkExpired(contentVersion);
}
Expand Down
5 changes: 5 additions & 0 deletions src/core/ImageStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ class ImageStream {
*/
virtual bool isAlphaOnly() const = 0;

/**
* Returns true if pixels are in the YUV format.
*/
virtual bool isYUV() const = 0;

/**
* Returns true if the ImageStream is backed by a platform-specified hardware buffer. Hardware
* buffers allow sharing memory across CPU and GPU, which can be used to speed up the texture
Expand Down
4 changes: 4 additions & 0 deletions src/core/PixelBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ class PixelBuffer : public ImageBuffer {
return _info.isAlphaOnly();
}

bool isYUV() const override {
return false;
}

/**
* Returns an ImageInfo describing the width, height, color type, alpha type, and row bytes of the
* PixelBuffer.
Expand Down
4 changes: 4 additions & 0 deletions src/core/PixelRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ class PixelRef : public ImageStream {
return pixelBuffer->isAlphaOnly();
}

bool isYUV() const override {
return pixelBuffer->isYUV();
}

bool isHardwareBacked() const override {
return pixelBuffer->isHardwareBacked();
}
Expand Down
4 changes: 4 additions & 0 deletions src/core/Rasterizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class Rasterizer : public ImageGenerator {
return true;
}

bool isYUV() const override {
return false;
}

bool asyncSupport() const override;

protected:
Expand Down
4 changes: 2 additions & 2 deletions src/core/filters/DropShadowImageFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ Rect DropShadowImageFilter::onFilterBounds(const Rect& srcRect) const {
std::unique_ptr<FragmentProcessor> DropShadowImageFilter::asFragmentProcessor(
std::shared_ptr<Image> source, const FPArgs& args, const SamplingOptions& sampling,
const Matrix* uvMatrix) const {
if (source->isComplex()) {
if (!source->isFlat()) {
auto needMipmaps = NeedMipmaps(sampling, args.viewMatrix, uvMatrix);
source = source->makeRasterized(needMipmaps, sampling);
source = source->makeFlattened(needMipmaps, sampling);
}
std::unique_ptr<FragmentProcessor> shadowProcessor;
auto shadowMatrix = Matrix::MakeTrans(-dx, -dy);
Expand Down
4 changes: 2 additions & 2 deletions src/core/filters/InnerShadowImageFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ InnerShadowImageFilter::InnerShadowImageFilter(float dx, float dy, float blurrin
std::unique_ptr<FragmentProcessor> InnerShadowImageFilter::asFragmentProcessor(
std::shared_ptr<Image> source, const FPArgs& args, const SamplingOptions& sampling,
const Matrix* uvMatrix) const {
if (source->isComplex()) {
if (!source->isFlat()) {
auto needMipmaps = NeedMipmaps(sampling, args.viewMatrix, uvMatrix);
source = source->makeRasterized(needMipmaps, sampling);
source = source->makeFlattened(needMipmaps, sampling);
}

// get inverted shadow mask
Expand Down
4 changes: 4 additions & 0 deletions src/core/filters/RuntimeImageFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class RuntimeImageFilter : public ImageFilter {
const SamplingOptions& sampling,
const Matrix* uvMatrix) const override;

bool requireFlatSource() const override {
return true;
}

private:
std::shared_ptr<RuntimeEffect> effect = nullptr;
};
Expand Down
8 changes: 8 additions & 0 deletions src/core/images/BufferImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ class BufferImage : public ResourceImage {
return imageBuffer->isAlphaOnly();
}

bool isYUV() const override {
return imageBuffer->isYUV();
}

bool isFlat() const override {
return !imageBuffer->isYUV();
}

protected:
std::shared_ptr<TextureProxy> onLockTextureProxy(const TPArgs& args) const override;

Expand Down
8 changes: 8 additions & 0 deletions src/core/images/DecoderImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ class DecoderImage : public ResourceImage {
return decoder->isAlphaOnly();
}

bool isYUV() const override {
return decoder->isYUV();
}

bool isFlat() const override {
return !decoder->isYUV();
}

protected:
std::shared_ptr<TextureProxy> onLockTextureProxy(const TPArgs& args) const override;

Expand Down
5 changes: 4 additions & 1 deletion src/core/images/FilterImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@

#include "FilterImage.h"
#include "SubsetImage.h"
#include "core/utils/AddressOf.h"
#include "core/utils/NeedMipmaps.h"
#include "gpu/OpContext.h"
#include "gpu/processors/TiledTextureEffect.h"
#include "gpu/proxies/RenderTargetProxy.h"

namespace tgfx {
std::shared_ptr<Image> FilterImage::MakeFrom(std::shared_ptr<Image> source,
Expand All @@ -48,6 +48,9 @@ std::shared_ptr<Image> FilterImage::MakeFrom(std::shared_ptr<Image> source,
offset->x = bounds.left;
offset->y = bounds.top;
}
if (filter->requireFlatSource()) {
source = source->makeFlattened();
}
return Wrap(std::move(source), bounds, std::move(filter));
}

Expand Down
Loading