diff --git a/DEPS b/DEPS index f5d847c3..7259d59c 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ "common": [ { "url": "${PAG_GROUP}/vendor_tools.git", - "commit": "d288af5f03c0790e98bae413b41029e0d9270bb0", + "commit": "9787ea5507fe62bb02cb4de49cf5a87cfffbc1df", "dir": "third_party/vendor_tools" }, { diff --git a/include/tgfx/gpu/Surface.h b/include/tgfx/gpu/Surface.h index 11b5753f..8b57c6de 100644 --- a/include/tgfx/gpu/Surface.h +++ b/include/tgfx/gpu/Surface.h @@ -28,6 +28,7 @@ namespace tgfx { class Canvas; class Context; class RenderTarget; +class RenderTargetProxy; /** * The Surface class is responsible for managing the pixels that a Canvas draws into. The Surface @@ -200,10 +201,8 @@ class Surface { bool readPixels(const ImageInfo& dstInfo, void* dstPixels, int srcX = 0, int srcY = 0); private: - std::shared_ptr renderTarget = nullptr; - std::shared_ptr texture = nullptr; + std::shared_ptr renderTargetProxy = nullptr; SurfaceOptions surfaceOptions = {}; - bool externalTexture = false; Canvas* canvas = nullptr; std::shared_ptr cachedImage = nullptr; @@ -213,15 +212,14 @@ class Surface { static std::shared_ptr MakeFrom(std::shared_ptr texture, int sampleCount = 1, const SurfaceOptions* options = nullptr); - Surface(std::shared_ptr renderTarget, std::shared_ptr texture, - const SurfaceOptions* options, bool externalTexture = true); + Surface(std::shared_ptr proxy, const SurfaceOptions* options); std::shared_ptr getTexture(); void aboutToDraw(bool discardContent = false); friend class DrawingManager; + friend class SurfaceDrawContext; friend class Canvas; - friend class QGLWindow; }; } // namespace tgfx \ No newline at end of file diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp index 456fdc33..628eed9b 100644 --- a/src/core/Canvas.cpp +++ b/src/core/Canvas.cpp @@ -29,6 +29,7 @@ #include "gpu/processors/ConstColorProcessor.h" #include "gpu/processors/DeviceSpaceTextureEffect.h" #include "gpu/processors/TextureEffect.h" +#include "gpu/proxies/RenderTargetProxy.h" #include "tgfx/core/BlendMode.h" #include "tgfx/core/Mask.h" #include "tgfx/core/PathEffect.h" @@ -709,7 +710,9 @@ bool Canvas::drawAsClear(const Path& path, const GpuPaint& paint) { return false; } surface->aboutToDraw(true); - color = surface->renderTarget->writeSwizzle().applyTo(color); + auto format = surface->renderTargetProxy->format(); + const auto& writeSwizzle = getContext()->caps()->getWriteSwizzle(format); + color = writeSwizzle.applyTo(color); auto [rect, useScissor] = getClipRect(); if (rect.has_value()) { if (useScissor) { @@ -731,7 +734,7 @@ void Canvas::draw(std::unique_ptr op, GpuPaint paint, bool aa) { return; } auto aaType = AAType::None; - if (surface->renderTarget->sampleCount() > 1) { + if (surface->renderTargetProxy->sampleCount() > 1) { aaType = AAType::MSAA; } else if (aa && !IsPixelAligned(op->bounds())) { aaType = AAType::Coverage; diff --git a/src/gpu/DrawingManager.cpp b/src/gpu/DrawingManager.cpp index 754f94a7..e19d88f7 100644 --- a/src/gpu/DrawingManager.cpp +++ b/src/gpu/DrawingManager.cpp @@ -17,10 +17,10 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "DrawingManager.h" -#include "TextureResolveRenderTask.h" #include "gpu/Gpu.h" -#include "gpu/RenderTarget.h" +#include "gpu/proxies/RenderTargetProxy.h" #include "gpu/proxies/TextureProxy.h" +#include "gpu/tasks/TextureResolveRenderTask.h" #include "utils/Log.h" namespace tgfx { @@ -31,21 +31,22 @@ void DrawingManager::closeActiveOpsTask() { } } -void DrawingManager::newTextureResolveRenderTask(Surface* surface) { - auto texture = surface->texture; - if (surface->renderTarget->sampleCount() <= 1 && - (!texture || !texture->getSampler()->hasMipmaps())) { +void DrawingManager::newTextureResolveRenderTask( + std::shared_ptr renderTargetProxy) { + auto textureProxy = renderTargetProxy->getTextureProxy(); + if (renderTargetProxy->sampleCount() <= 1 && (!textureProxy || !textureProxy->hasMipmaps())) { return; } closeActiveOpsTask(); - auto task = std::make_shared(surface->renderTarget, surface->texture); + auto task = std::make_shared(renderTargetProxy); task->makeClosed(); tasks.push_back(std::move(task)); } -std::shared_ptr DrawingManager::newOpsTask(Surface* surface) { +std::shared_ptr DrawingManager::newOpsTask( + std::shared_ptr renderTargetProxy) { closeActiveOpsTask(); - auto opsTask = std::make_shared(surface->renderTarget, surface->texture); + auto opsTask = std::make_shared(renderTargetProxy); tasks.push_back(opsTask); activeOpsTask = opsTask.get(); return opsTask; @@ -55,12 +56,12 @@ bool DrawingManager::flush(Semaphore* signalSemaphore) { auto* gpu = context->gpu(); closeAllTasks(); activeOpsTask = nullptr; - std::vector proxies; + std::vector proxies = {}; std::for_each(tasks.begin(), tasks.end(), [&proxies](std::shared_ptr& task) { task->gatherProxies(&proxies); }); - std::for_each(proxies.begin(), proxies.end(), [](TextureProxy* proxy) { + std::for_each(proxies.begin(), proxies.end(), [](ProxyBase* proxy) { if (!(proxy->isInstantiated() || proxy->instantiate())) { - LOGE("Failed to instantiate texture from proxy."); + LOGE("DrawingManager::flush() Failed to instantiate proxy!"); } }); std::for_each(tasks.begin(), tasks.end(), diff --git a/src/gpu/DrawingManager.h b/src/gpu/DrawingManager.h index f8f4c6dc..7e991ae3 100644 --- a/src/gpu/DrawingManager.h +++ b/src/gpu/DrawingManager.h @@ -19,8 +19,8 @@ #pragma once #include -#include "RenderTask.h" -#include "gpu/ops/OpsTask.h" +#include "gpu/tasks/OpsTask.h" +#include "gpu/tasks/RenderTask.h" #include "tgfx/gpu/Surface.h" namespace tgfx { @@ -29,11 +29,11 @@ class DrawingManager { explicit DrawingManager(Context* context) : context(context) { } - std::shared_ptr newOpsTask(Surface* surface); + std::shared_ptr newOpsTask(std::shared_ptr renderTargetProxy); bool flush(Semaphore* signalSemaphore); - void newTextureResolveRenderTask(Surface* surface); + void newTextureResolveRenderTask(std::shared_ptr renderTargetProxy); private: void closeAllTasks(); @@ -45,5 +45,7 @@ class DrawingManager { Context* context = nullptr; std::vector> tasks; OpsTask* activeOpsTask = nullptr; + + friend class Surface; }; } // namespace tgfx diff --git a/src/gpu/RenderTarget.h b/src/gpu/RenderTarget.h index 2d868319..ee84c22f 100644 --- a/src/gpu/RenderTarget.h +++ b/src/gpu/RenderTarget.h @@ -104,14 +104,9 @@ class RenderTarget : public Resource { } private: - virtual const Swizzle& writeSwizzle() const = 0; - int _width = 0; int _height = 0; ImageOrigin _origin = ImageOrigin::TopLeft; int _sampleCount = 1; - - friend class DrawOp; - friend class Canvas; }; } // namespace tgfx diff --git a/src/gpu/Surface.cpp b/src/gpu/Surface.cpp index 0a1e2f5e..85052f06 100644 --- a/src/gpu/Surface.cpp +++ b/src/gpu/Surface.cpp @@ -19,7 +19,7 @@ #include "tgfx/gpu/Surface.h" #include "DrawingManager.h" #include "core/PixelBuffer.h" -#include "gpu/RenderTarget.h" +#include "gpu/proxies/RenderTargetProxy.h" #include "utils/Log.h" #include "utils/PixelFormatUtil.h" @@ -34,22 +34,13 @@ std::shared_ptr Surface::Make(Context* context, int width, int height, std::shared_ptr Surface::Make(Context* context, int width, int height, ColorType colorType, int sampleCount, bool mipMapped, const SurfaceOptions* options) { - auto caps = context->caps(); auto pixelFormat = ColorTypeToPixelFormat(colorType); - if (!caps->isFormatRenderable(pixelFormat)) { + auto proxy = RenderTargetProxy::Make(context, width, height, pixelFormat, sampleCount, mipMapped); + if (proxy == nullptr) { return nullptr; } - auto texture = Texture::MakeFormat(context, width, height, pixelFormat, mipMapped); - if (texture == nullptr) { - return nullptr; - } - sampleCount = caps->getSampleCount(sampleCount, pixelFormat); - auto renderTarget = RenderTarget::MakeFrom(texture.get(), sampleCount); - if (renderTarget == nullptr) { - return nullptr; - } - auto surface = new Surface(renderTarget, texture, options, false); - // 对于内部创建的 RenderTarget 默认清屏。 + auto surface = new Surface(std::move(proxy), options); + // Clear the surface by default for internally created RenderTarget. surface->getCanvas()->clear(); return std::shared_ptr(surface); } @@ -76,26 +67,25 @@ std::shared_ptr Surface::MakeFrom(Context* context, HardwareBufferRef h std::shared_ptr Surface::MakeFrom(std::shared_ptr renderTarget, const SurfaceOptions* options) { - if (renderTarget == nullptr) { + auto proxy = RenderTargetProxy::MakeFrom(std::move(renderTarget)); + if (proxy == nullptr) { return nullptr; } - return std::shared_ptr(new Surface(std::move(renderTarget), nullptr, options)); + return std::shared_ptr(new Surface(std::move(proxy), options)); } std::shared_ptr Surface::MakeFrom(std::shared_ptr texture, int sampleCount, const SurfaceOptions* options) { - auto renderTarget = RenderTarget::MakeFrom(texture.get(), sampleCount); - if (renderTarget == nullptr) { + auto proxy = RenderTargetProxy::MakeFrom(std::move(texture), sampleCount); + if (proxy == nullptr) { return nullptr; } - return std::shared_ptr(new Surface(renderTarget, std::move(texture), options)); + return std::shared_ptr(new Surface(std::move(proxy), options)); } -Surface::Surface(std::shared_ptr renderTarget, std::shared_ptr texture, - const SurfaceOptions* options, bool externalTexture) - : renderTarget(std::move(renderTarget)), texture(std::move(texture)), - externalTexture(externalTexture) { - DEBUG_ASSERT(this->renderTarget != nullptr); +Surface::Surface(std::shared_ptr proxy, const SurfaceOptions* options) + : renderTargetProxy(std::move(proxy)) { + DEBUG_ASSERT(this->renderTargetProxy != nullptr); if (options != nullptr) { surfaceOptions = *options; } @@ -106,53 +96,64 @@ Surface::~Surface() { } Context* Surface::getContext() const { - return renderTarget->getContext(); + return renderTargetProxy->getContext(); } int Surface::width() const { - return renderTarget->width(); + return renderTargetProxy->width(); } int Surface::height() const { - return renderTarget->height(); + return renderTargetProxy->height(); } ImageOrigin Surface::origin() const { - return renderTarget->origin(); + return renderTargetProxy->origin(); } std::shared_ptr Surface::getTexture() { - if (texture == nullptr) { + if (!renderTargetProxy->isTextureBacked()) { return nullptr; } flush(); - return texture; + return renderTargetProxy->getTexture(); } BackendRenderTarget Surface::getBackendRenderTarget() { flush(); + auto renderTarget = renderTargetProxy->getRenderTarget(); + if (renderTarget == nullptr) { + return {}; + } return renderTarget->getBackendRenderTarget(); } BackendTexture Surface::getBackendTexture() { - if (texture == nullptr) { + if (!renderTargetProxy->isTextureBacked()) { return {}; } flush(); + auto texture = renderTargetProxy->getTexture(); + if (texture == nullptr) { + return {}; + } return texture->getBackendTexture(); } HardwareBufferRef Surface::getHardwareBuffer() { - auto hardwareBuffer = texture ? texture->getHardwareBuffer() : nullptr; - if (hardwareBuffer == nullptr) { + if (!renderTargetProxy->isTextureBacked()) { return nullptr; } flushAndSubmit(true); - return hardwareBuffer; + auto texture = renderTargetProxy->getTexture(); + if (texture == nullptr) { + return nullptr; + } + return texture->getHardwareBuffer(); } bool Surface::wait(const BackendSemaphore& waitSemaphore) { - return renderTarget->getContext()->wait(waitSemaphore); + return renderTargetProxy->getContext()->wait(waitSemaphore); } Canvas* Surface::getCanvas() { @@ -164,8 +165,9 @@ Canvas* Surface::getCanvas() { bool Surface::flush(BackendSemaphore* signalSemaphore) { auto semaphore = Semaphore::Wrap(signalSemaphore); - renderTarget->getContext()->drawingManager()->newTextureResolveRenderTask(this); - auto result = renderTarget->getContext()->drawingManager()->flush(semaphore.get()); + auto drawingManager = renderTargetProxy->getContext()->drawingManager(); + drawingManager->newTextureResolveRenderTask(renderTargetProxy); + auto result = drawingManager->flush(semaphore.get()); if (signalSemaphore != nullptr) { *signalSemaphore = semaphore->getBackendSemaphore(); } @@ -174,27 +176,7 @@ bool Surface::flush(BackendSemaphore* signalSemaphore) { void Surface::flushAndSubmit(bool syncCpu) { flush(); - renderTarget->getContext()->submit(syncCpu); -} - -static std::shared_ptr MakeTextureFromRenderTarget(const RenderTarget* renderTarget, - bool mipMapped, - bool discardContent = false) { - auto context = renderTarget->getContext(); - auto width = renderTarget->width(); - auto height = renderTarget->height(); - if (discardContent) { - return Texture::MakeFormat(context, width, height, renderTarget->format(), mipMapped, - renderTarget->origin()); - } - auto texture = Texture::MakeFormat(context, width, height, renderTarget->format(), mipMapped, - renderTarget->origin()); - if (texture == nullptr) { - return nullptr; - } - context->gpu()->copyRenderTargetToTexture(renderTarget, texture.get(), - Rect::MakeWH(width, height), Point::Zero()); - return texture; + renderTargetProxy->getContext()->submit(syncCpu); } std::shared_ptr Surface::makeImageSnapshot() { @@ -202,11 +184,12 @@ std::shared_ptr Surface::makeImageSnapshot() { if (cachedImage != nullptr) { return cachedImage; } - if (texture != nullptr && !externalTexture) { - cachedImage = Image::MakeFrom(texture); + if (renderTargetProxy->externallyOwned()) { + auto textureCopy = renderTargetProxy->makeTextureProxy(true); + cachedImage = Image::MakeFrom(textureCopy->getTexture()); } else { - auto textureCopy = MakeTextureFromRenderTarget(renderTarget.get(), false); - cachedImage = Image::MakeFrom(textureCopy); + auto texture = renderTargetProxy->getTexture(); + cachedImage = Image::MakeFrom(texture); } return cachedImage; } @@ -220,16 +203,16 @@ void Surface::aboutToDraw(bool discardContent) { if (isUnique) { return; } - if (texture == nullptr || externalTexture) { + if (renderTargetProxy->externallyOwned()) { return; } - auto mipMapped = texture->getSampler()->hasMipmaps(); - auto newTexture = MakeTextureFromRenderTarget(renderTarget.get(), mipMapped, discardContent); - auto success = renderTarget->replaceTexture(newTexture.get()); - if (!success) { - LOGE("Surface::aboutToDraw(): Failed to replace the backing texture of the renderTarget!"); + getContext()->drawingManager()->closeActiveOpsTask(); + auto newRenderTargetProxy = renderTargetProxy->makeRenderTargetProxy(!discardContent); + if (newRenderTargetProxy == nullptr) { + LOGE("Surface::aboutToDraw(): Failed to make a copy of the renderTarget!"); + return; } - texture = newTexture; + renderTargetProxy = newRenderTargetProxy; } Color Surface::getColor(int x, int y) { @@ -245,9 +228,11 @@ bool Surface::readPixels(const ImageInfo& dstInfo, void* dstPixels, int srcX, in if (dstInfo.isEmpty() || dstPixels == nullptr) { return false; } + flush(); + auto texture = renderTargetProxy->getTexture(); auto hardwareBuffer = texture ? texture->getHardwareBuffer() : nullptr; - flushAndSubmit(hardwareBuffer != nullptr); if (hardwareBuffer != nullptr) { + getContext()->submit(true); auto pixels = HardwareBufferLock(hardwareBuffer); if (pixels != nullptr) { auto info = HardwareBufferGetInfo(hardwareBuffer); @@ -256,6 +241,10 @@ bool Surface::readPixels(const ImageInfo& dstInfo, void* dstPixels, int srcX, in return success; } } + auto renderTarget = renderTargetProxy->getRenderTarget(); + if (renderTarget == nullptr) { + return false; + } return renderTarget->readPixels(dstInfo, dstPixels, srcX, srcY); } } // namespace tgfx diff --git a/src/gpu/SurfaceDrawContext.cpp b/src/gpu/SurfaceDrawContext.cpp index c5ca4882..b5393b37 100644 --- a/src/gpu/SurfaceDrawContext.cpp +++ b/src/gpu/SurfaceDrawContext.cpp @@ -45,6 +45,6 @@ OpsTask* SurfaceDrawContext::getOpsTask() { } void SurfaceDrawContext::replaceOpsTask() { - opsTask = surface->getContext()->drawingManager()->newOpsTask(surface); + opsTask = surface->getContext()->drawingManager()->newOpsTask(surface->renderTargetProxy); } } // namespace tgfx diff --git a/src/gpu/SurfaceDrawContext.h b/src/gpu/SurfaceDrawContext.h index f3efc595..48d4bb7c 100644 --- a/src/gpu/SurfaceDrawContext.h +++ b/src/gpu/SurfaceDrawContext.h @@ -18,8 +18,8 @@ #pragma once -#include "gpu/ops/OpsTask.h" #include "gpu/processors/FragmentProcessor.h" +#include "gpu/tasks/OpsTask.h" #include "tgfx/core/Matrix.h" #include "tgfx/core/Rect.h" #include "tgfx/gpu/Surface.h" diff --git a/src/gpu/ops/DrawOp.cpp b/src/gpu/ops/DrawOp.cpp index 8b29f11b..0ff0aad8 100644 --- a/src/gpu/ops/DrawOp.cpp +++ b/src/gpu/ops/DrawOp.cpp @@ -21,7 +21,7 @@ #include "utils/Log.h" namespace tgfx { -void DrawOp::visitProxies(const std::function& func) const { +void DrawOp::visitProxies(const std::function& func) const { auto f = [&](const std::unique_ptr& fp) { fp->visitProxies(func); }; std::for_each(_colors.begin(), _colors.end(), f); std::for_each(_masks.begin(), _masks.end(), f); @@ -80,7 +80,8 @@ std::unique_ptr DrawOp::createPipeline(RenderPass* renderPass, if (!BlendModeAsCoeff(blendMode) && !caps->frameBufferFetchSupport) { dstTextureInfo = CreateDstTextureInfo(renderPass, bounds()); } - const auto& swizzle = renderPass->renderTarget()->writeSwizzle(); + auto format = renderPass->renderTarget()->format(); + const auto& swizzle = caps->getWriteSwizzle(format); return std::make_unique(std::move(gp), std::move(fragmentProcessors), numColorProcessors, blendMode, dstTextureInfo, &swizzle); } diff --git a/src/gpu/ops/DrawOp.h b/src/gpu/ops/DrawOp.h index b15e1aa5..f18e4c04 100644 --- a/src/gpu/ops/DrawOp.h +++ b/src/gpu/ops/DrawOp.h @@ -30,7 +30,7 @@ class DrawOp : public Op { explicit DrawOp(uint8_t classID) : Op(classID) { } - void visitProxies(const std::function& func) const override; + void visitProxies(const std::function& func) const override; void prepare(Gpu* gpu) final; diff --git a/src/gpu/ops/Op.h b/src/gpu/ops/Op.h index c0c509a9..d2df54ec 100644 --- a/src/gpu/ops/Op.h +++ b/src/gpu/ops/Op.h @@ -20,7 +20,7 @@ #include #include "gpu/RenderTarget.h" -#include "gpu/proxies/TextureProxy.h" +#include "gpu/proxies/ProxyBase.h" #include "tgfx/core/Rect.h" #include "tgfx/gpu/Context.h" @@ -40,7 +40,7 @@ class Op { virtual ~Op() = default; - virtual void visitProxies(const std::function&) const { + virtual void visitProxies(const std::function&) const { } virtual void prepare(Gpu*) { diff --git a/src/gpu/proxies/DeferredTextureProxy.cpp b/src/gpu/proxies/DeferredTextureProxy.cpp index 266cdfdd..1babfddc 100644 --- a/src/gpu/proxies/DeferredTextureProxy.cpp +++ b/src/gpu/proxies/DeferredTextureProxy.cpp @@ -21,22 +21,10 @@ namespace tgfx { DeferredTextureProxy::DeferredTextureProxy(ProxyProvider* provider, int width, int height, PixelFormat format, bool mipMapped, ImageOrigin origin) - : TextureProxy(provider), _width(width), _height(height), format(format), mipMapped(mipMapped), + : TextureProxy(provider), _width(width), _height(height), _format(format), mipMapped(mipMapped), _origin(origin) { } -int DeferredTextureProxy::width() const { - return _width; -} - -int DeferredTextureProxy::height() const { - return _height; -} - -ImageOrigin DeferredTextureProxy::origin() const { - return _origin; -} - bool DeferredTextureProxy::hasMipmaps() const { return texture ? texture->getSampler()->hasMipmaps() : mipMapped; } @@ -45,6 +33,6 @@ std::shared_ptr DeferredTextureProxy::onMakeTexture(Context* context) { if (context == nullptr) { return nullptr; } - return Texture::MakeFormat(context, width(), height(), format, mipMapped); + return Texture::MakeFormat(context, width(), height(), _format, mipMapped, _origin); } } // namespace tgfx diff --git a/src/gpu/proxies/DeferredTextureProxy.h b/src/gpu/proxies/DeferredTextureProxy.h index e9f8c0b4..2b122a5b 100644 --- a/src/gpu/proxies/DeferredTextureProxy.h +++ b/src/gpu/proxies/DeferredTextureProxy.h @@ -23,11 +23,17 @@ namespace tgfx { class DeferredTextureProxy : public TextureProxy { public: - int width() const override; + int width() const override { + return _width; + } - int height() const override; + int height() const override { + return _height; + } - ImageOrigin origin() const override; + ImageOrigin origin() const override { + return _origin; + } bool hasMipmaps() const override; @@ -37,7 +43,7 @@ class DeferredTextureProxy : public TextureProxy { private: int _width = 0; int _height = 0; - PixelFormat format = PixelFormat::RGBA_8888; + PixelFormat _format = PixelFormat::RGBA_8888; bool mipMapped = false; ImageOrigin _origin = ImageOrigin::TopLeft; diff --git a/src/gpu/proxies/ProxyBase.h b/src/gpu/proxies/ProxyBase.h new file mode 100644 index 00000000..ac163302 --- /dev/null +++ b/src/gpu/proxies/ProxyBase.h @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +namespace tgfx { +/** + * This class delays the acquisition of instances until they are actually required. + */ +class ProxyBase { + public: + virtual ~ProxyBase() = default; + + /** + * Returns true if the proxy is instantiated. + */ + virtual bool isInstantiated() const = 0; + + /** + * Instantiates the proxy if necessary. Returns true if the proxy is instantiated successfully. + */ + virtual bool instantiate() = 0; +}; +} // namespace tgfx diff --git a/src/gpu/proxies/RenderTargetProxy.cpp b/src/gpu/proxies/RenderTargetProxy.cpp index 5f8e90c2..3ce427a8 100644 --- a/src/gpu/proxies/RenderTargetProxy.cpp +++ b/src/gpu/proxies/RenderTargetProxy.cpp @@ -19,6 +19,7 @@ #include "RenderTargetProxy.h" #include "RenderTargetWrapper.h" #include "TextureRenderTargetProxy.h" +#include "gpu/Gpu.h" #include "gpu/ProxyProvider.h" namespace tgfx { @@ -39,33 +40,46 @@ std::shared_ptr RenderTargetProxy::MakeFrom(std::shared_ptrgetSampler()->format; + if (!context->caps()->isFormatRenderable(format)) { + return nullptr; + } auto textureProxy = context->proxyProvider()->wrapTexture(std::move(texture)); if (textureProxy == nullptr) { return nullptr; } return std::shared_ptr( - new TextureRenderTargetProxy(std::move(textureProxy), sampleCount)); + new TextureRenderTargetProxy(std::move(textureProxy), format, sampleCount, true)); } std::shared_ptr RenderTargetProxy::Make(Context* context, int width, int height, - tgfx::PixelFormat format, - int sampleCount, bool mipMapped) { + PixelFormat format, int sampleCount, + bool mipMapped) { if (context == nullptr) { return nullptr; } + auto caps = context->caps(); + if (!caps->isFormatRenderable(format)) { + return nullptr; + } + sampleCount = caps->getSampleCount(sampleCount, format); auto textureProxy = context->proxyProvider()->createTextureProxy(width, height, format, mipMapped); if (textureProxy == nullptr) { return nullptr; } return std::shared_ptr( - new TextureRenderTargetProxy(std::move(textureProxy), sampleCount)); + new TextureRenderTargetProxy(std::move(textureProxy), format, sampleCount, false)); } RenderTargetProxy::RenderTargetProxy(std::shared_ptr renderTarget) : renderTarget(std::move(renderTarget)) { } +bool RenderTargetProxy::isTextureBacked() const { + return getTextureProxy() != nullptr; +} + std::shared_ptr RenderTargetProxy::getTexture() const { auto textureProxy = getTextureProxy(); return textureProxy ? textureProxy->getTexture() : nullptr; @@ -86,4 +100,39 @@ bool RenderTargetProxy::instantiate() { renderTarget = onMakeRenderTarget(); return renderTarget != nullptr; } + +std::shared_ptr RenderTargetProxy::makeTextureProxy(bool copyContent) const { + //TODO: send an async texture copying task to the gpu context. + if (renderTarget == nullptr) { + return nullptr; + } + auto context = getContext(); + auto textureProxy = getTextureProxy(); + auto hasMipmaps = textureProxy && textureProxy->hasMipmaps(); + auto newTextureProxy = context->proxyProvider()->createTextureProxy(width(), height(), format(), + hasMipmaps, origin()); + if (newTextureProxy == nullptr) { + return nullptr; + } + if (copyContent) { + newTextureProxy->instantiate(); + auto newTexture = newTextureProxy->getTexture(); + if (newTexture == nullptr) { + return nullptr; + } + context->gpu()->copyRenderTargetToTexture(renderTarget.get(), newTexture.get(), + Rect::MakeWH(width(), height()), Point::Zero()); + } + return newTextureProxy; +} + +std::shared_ptr RenderTargetProxy::makeRenderTargetProxy( + bool copyContent) const { + auto textureProxy = makeTextureProxy(copyContent); + if (textureProxy == nullptr) { + return nullptr; + } + return std::shared_ptr( + new TextureRenderTargetProxy(std::move(textureProxy), format(), sampleCount(), false)); +} } // namespace tgfx diff --git a/src/gpu/proxies/RenderTargetProxy.h b/src/gpu/proxies/RenderTargetProxy.h index b650d849..1bd13be9 100644 --- a/src/gpu/proxies/RenderTargetProxy.h +++ b/src/gpu/proxies/RenderTargetProxy.h @@ -18,6 +18,7 @@ #pragma once +#include "ProxyBase.h" #include "TextureProxy.h" #include "gpu/RenderTarget.h" @@ -25,7 +26,7 @@ namespace tgfx { /** * This class delays the acquisition of render targets until they are actually required. */ -class RenderTargetProxy { +class RenderTargetProxy : public ProxyBase { public: /** * Creates a new RenderTargetProxy with an existing RenderTarget @@ -46,8 +47,6 @@ class RenderTargetProxy { PixelFormat format, int sampleCount = 1, bool mipMapped = false); - virtual ~RenderTargetProxy() = default; - /** * Returns the width of the render target. */ @@ -64,6 +63,11 @@ class RenderTargetProxy { */ virtual ImageOrigin origin() const = 0; + /** + * Returns the pixel format of the render target. + */ + virtual PixelFormat format() const = 0; + /** * If we are instantiated and have a render target, return the sampleCount value of that render * target. Otherwise, returns the proxy's sampleCount value from creation time. @@ -81,6 +85,16 @@ class RenderTargetProxy { */ virtual std::shared_ptr getTextureProxy() const = 0; + /** + * Returns true if the proxy is externally owned. + */ + virtual bool externallyOwned() const = 0; + + /** + * Returns true if the proxy was backed by a texture. + */ + bool isTextureBacked() const; + /** * Returns the backing Texture of the proxy. Returns nullptr if the proxy is not instantiated yet, * or it is not backed by a texture. @@ -95,13 +109,27 @@ class RenderTargetProxy { /** * Returns true if the backing texture is instantiated. */ - bool isInstantiated() const; + bool isInstantiated() const override; /** * Instantiates the backing texture, if necessary. Returns true if the backing texture is * instantiated. */ - bool instantiate(); + bool instantiate() override; + + /** + * Creates a compatible TextureProxy instance matches the properties of the RenderTargetProxy. If + * the copyContent is true, the content of the RenderTargetProxy will be copied to the new + * texture. + */ + std::shared_ptr makeTextureProxy(bool copyContent = false) const; + + /** + * Creates a compatible RenderTargetProxy instance matches the properties of this one. If + * copyContent is true, the content of this RenderTargetProxy will be copied to the new + * RenderTargetProxy. + */ + std::shared_ptr makeRenderTargetProxy(bool copyContent = false) const; protected: std::shared_ptr renderTarget = nullptr; diff --git a/src/gpu/proxies/RenderTargetWrapper.h b/src/gpu/proxies/RenderTargetWrapper.h index eb869da6..9991f835 100644 --- a/src/gpu/proxies/RenderTargetWrapper.h +++ b/src/gpu/proxies/RenderTargetWrapper.h @@ -35,6 +35,10 @@ class RenderTargetWrapper : public RenderTargetProxy { return renderTarget->origin(); } + PixelFormat format() const override { + return renderTarget->format(); + } + int sampleCount() const override { return renderTarget->sampleCount(); } @@ -43,6 +47,10 @@ class RenderTargetWrapper : public RenderTargetProxy { return renderTarget->getContext(); } + bool externallyOwned() const override { + return true; + } + std::shared_ptr getTextureProxy() const override; protected: diff --git a/src/gpu/proxies/TextureProxy.h b/src/gpu/proxies/TextureProxy.h index 131ca838..b67633bb 100644 --- a/src/gpu/proxies/TextureProxy.h +++ b/src/gpu/proxies/TextureProxy.h @@ -18,6 +18,7 @@ #pragma once +#include "ProxyBase.h" #include "gpu/Texture.h" #include "gpu/TextureSampler.h" @@ -27,9 +28,9 @@ class ProxyProvider; /** * This class delays the acquisition of textures until they are actually required. */ -class TextureProxy { +class TextureProxy : public ProxyBase { public: - virtual ~TextureProxy(); + virtual ~TextureProxy() override; /** * Returns the width of the texture. @@ -66,13 +67,13 @@ class TextureProxy { /** * Returns true if the backing texture is instantiated. */ - bool isInstantiated() const; + bool isInstantiated() const override; /** * Instantiates the backing texture, if necessary. Returns true if the backing texture is * instantiated. */ - bool instantiate(); + bool instantiate() override; /** * Assigns a UniqueKey to the proxy. The proxy will be findable via this UniqueKey using diff --git a/src/gpu/proxies/TextureRenderTargetProxy.cpp b/src/gpu/proxies/TextureRenderTargetProxy.cpp index 3a457577..1d535a06 100644 --- a/src/gpu/proxies/TextureRenderTargetProxy.cpp +++ b/src/gpu/proxies/TextureRenderTargetProxy.cpp @@ -21,8 +21,10 @@ namespace tgfx { TextureRenderTargetProxy::TextureRenderTargetProxy(std::shared_ptr textureProxy, - int sampleCount) - : textureProxy(std::move(textureProxy)), _sampleCount(sampleCount) { + PixelFormat format, int sampleCount, + bool externallyOwned) + : textureProxy(std::move(textureProxy)), _format(format), _sampleCount(sampleCount), + _externallyOwned(externallyOwned) { } std::shared_ptr TextureRenderTargetProxy::onMakeRenderTarget() { diff --git a/src/gpu/proxies/TextureRenderTargetProxy.h b/src/gpu/proxies/TextureRenderTargetProxy.h index 21aa35f3..c86ffdce 100644 --- a/src/gpu/proxies/TextureRenderTargetProxy.h +++ b/src/gpu/proxies/TextureRenderTargetProxy.h @@ -35,6 +35,10 @@ class TextureRenderTargetProxy : public RenderTargetProxy { return textureProxy->origin(); } + PixelFormat format() const override { + return _format; + } + int sampleCount() const override { return renderTarget ? renderTarget->sampleCount() : _sampleCount; } @@ -43,6 +47,10 @@ class TextureRenderTargetProxy : public RenderTargetProxy { return textureProxy->getContext(); } + bool externallyOwned() const override { + return _externallyOwned; + } + std::shared_ptr getTextureProxy() const override { return textureProxy; } @@ -52,9 +60,12 @@ class TextureRenderTargetProxy : public RenderTargetProxy { private: std::shared_ptr textureProxy = nullptr; + PixelFormat _format = PixelFormat::RGBA_8888; int _sampleCount = 0; + bool _externallyOwned = false; - TextureRenderTargetProxy(std::shared_ptr textureProxy, int sampleCount); + TextureRenderTargetProxy(std::shared_ptr textureProxy, PixelFormat format, + int sampleCount, bool externallyOwned); friend class RenderTargetProxy; }; diff --git a/src/gpu/ops/OpsTask.cpp b/src/gpu/tasks/OpsTask.cpp similarity index 84% rename from src/gpu/ops/OpsTask.cpp rename to src/gpu/tasks/OpsTask.cpp index 5a44c9cb..2f5d2d16 100644 --- a/src/gpu/ops/OpsTask.cpp +++ b/src/gpu/tasks/OpsTask.cpp @@ -32,7 +32,9 @@ bool OpsTask::execute(Gpu* gpu) { if (ops.empty()) { return false; } - auto renderPass = gpu->getRenderPass(renderTarget, renderTargetTexture); + auto renderTarget = renderTargetProxy->getRenderTarget(); + auto texture = renderTargetProxy->getTexture(); + auto renderPass = gpu->getRenderPass(renderTarget, texture); if (renderPass == nullptr) { return false; } @@ -47,11 +49,11 @@ bool OpsTask::execute(Gpu* gpu) { return true; } -void OpsTask::gatherProxies(std::vector* proxies) const { +void OpsTask::onGatherProxies(std::vector* proxies) const { if (ops.empty()) { return; } - auto func = [proxies](TextureProxy* proxy) { proxies->emplace_back(proxy); }; + auto func = [proxies](ProxyBase* proxy) { proxies->emplace_back(proxy); }; std::for_each(ops.begin(), ops.end(), [&func](auto& op) { op->visitProxies(func); }); } } // namespace tgfx diff --git a/src/gpu/ops/OpsTask.h b/src/gpu/tasks/OpsTask.h similarity index 78% rename from src/gpu/ops/OpsTask.h rename to src/gpu/tasks/OpsTask.h index 2b9dc73f..7dd128c3 100644 --- a/src/gpu/ops/OpsTask.h +++ b/src/gpu/tasks/OpsTask.h @@ -18,25 +18,25 @@ #pragma once -#include "gpu/RenderTask.h" #include "gpu/ops/Op.h" +#include "gpu/tasks/RenderTask.h" #include "tgfx/gpu/Surface.h" namespace tgfx { class OpsTask : public RenderTask { public: - OpsTask(std::shared_ptr renderTarget, std::shared_ptr texture) - : RenderTask(std::move(renderTarget)), renderTargetTexture(std::move(texture)) { + OpsTask(std::shared_ptr renderTargetProxy) + : RenderTask(std::move(renderTargetProxy)) { } void addOp(std::unique_ptr op); bool execute(Gpu* gpu) override; - void gatherProxies(std::vector* proxies) const override; + protected: + void onGatherProxies(std::vector* proxies) const override; private: - std::shared_ptr renderTargetTexture = nullptr; std::vector> ops; }; } // namespace tgfx diff --git a/src/gpu/tasks/RenderTask.cpp b/src/gpu/tasks/RenderTask.cpp new file mode 100644 index 00000000..11a0b5f5 --- /dev/null +++ b/src/gpu/tasks/RenderTask.cpp @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 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 "RenderTask.h" +#include "utils/Log.h" + +namespace tgfx { +RenderTask::RenderTask(std::shared_ptr proxy) + : renderTargetProxy(std::move(proxy)) { + DEBUG_ASSERT(renderTargetProxy != nullptr); +} + +void RenderTask::gatherProxies(std::vector* proxies) const { + proxies->push_back(renderTargetProxy.get()); + onGatherProxies(proxies); +} + +void RenderTask::onGatherProxies(std::vector*) const { +} +} // namespace tgfx \ No newline at end of file diff --git a/src/gpu/RenderTask.h b/src/gpu/tasks/RenderTask.h similarity index 78% rename from src/gpu/RenderTask.h rename to src/gpu/tasks/RenderTask.h index a0eb82d5..225a4b5f 100644 --- a/src/gpu/RenderTask.h +++ b/src/gpu/tasks/RenderTask.h @@ -18,7 +18,8 @@ #pragma once -#include "Gpu.h" +#include "gpu/Gpu.h" +#include "gpu/proxies/RenderTargetProxy.h" #include "tgfx/gpu/Surface.h" namespace tgfx { @@ -28,8 +29,7 @@ class RenderTask { virtual bool execute(Gpu* gpu) = 0; - virtual void gatherProxies(std::vector*) const { - } + void gatherProxies(std::vector* proxies) const; void makeClosed() { closed = true; @@ -40,11 +40,11 @@ class RenderTask { } protected: - explicit RenderTask(std::shared_ptr renderTarget) - : renderTarget(std::move(renderTarget)) { - } + explicit RenderTask(std::shared_ptr renderTargetProxy); + + virtual void onGatherProxies(std::vector* proxies) const; - std::shared_ptr renderTarget = nullptr; + std::shared_ptr renderTargetProxy = nullptr; private: bool closed = false; diff --git a/src/gpu/TextureResolveRenderTask.cpp b/src/gpu/tasks/TextureResolveRenderTask.cpp similarity index 78% rename from src/gpu/TextureResolveRenderTask.cpp rename to src/gpu/tasks/TextureResolveRenderTask.cpp index 6f3035c1..b57fbf5f 100644 --- a/src/gpu/TextureResolveRenderTask.cpp +++ b/src/gpu/tasks/TextureResolveRenderTask.cpp @@ -17,19 +17,23 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "TextureResolveRenderTask.h" -#include "Gpu.h" -#include "RenderTarget.h" +#include "gpu/Gpu.h" namespace tgfx { -TextureResolveRenderTask::TextureResolveRenderTask(std::shared_ptr renderTarget, - std::shared_ptr texture) - : RenderTask(std::move(renderTarget)), texture(std::move(texture)) { +TextureResolveRenderTask::TextureResolveRenderTask( + std::shared_ptr renderTargetProxy) + : RenderTask(std::move(renderTargetProxy)) { } bool TextureResolveRenderTask::execute(Gpu* gpu) { + auto renderTarget = renderTargetProxy->getRenderTarget(); + if (renderTarget == nullptr) { + return false; + } if (renderTarget->sampleCount() > 1) { gpu->resolveRenderTarget(renderTarget.get()); } + auto texture = renderTargetProxy->getTexture(); if (texture != nullptr && texture->getSampler()->hasMipmaps()) { gpu->regenerateMipMapLevels(texture->getSampler()); } diff --git a/src/gpu/TextureResolveRenderTask.h b/src/gpu/tasks/TextureResolveRenderTask.h similarity index 89% rename from src/gpu/TextureResolveRenderTask.h rename to src/gpu/tasks/TextureResolveRenderTask.h index 37ec5158..9e8fae12 100644 --- a/src/gpu/TextureResolveRenderTask.h +++ b/src/gpu/tasks/TextureResolveRenderTask.h @@ -23,12 +23,8 @@ namespace tgfx { class TextureResolveRenderTask : public RenderTask { public: - explicit TextureResolveRenderTask(std::shared_ptr renderTarget, - std::shared_ptr texture); + explicit TextureResolveRenderTask(std::shared_ptr renderTargetProxy); bool execute(Gpu* gpu) override; - - private: - std::shared_ptr texture = nullptr; }; } // namespace tgfx diff --git a/src/images/ImageSource.h b/src/images/ImageSource.h index f22959d5..ea8f3c28 100644 --- a/src/images/ImageSource.h +++ b/src/images/ImageSource.h @@ -48,7 +48,7 @@ class ImageSource { /** * Creates ImageSource from Texture, ImageSource is returned if texture is not nullptr. Note that - * this method is not thread safe, must be called while the asscociated context is locked. + * this method is not thread safe, must be called while the associated context is locked. */ static std::shared_ptr MakeFrom(UniqueKey uniqueKey, std::shared_ptr texture); diff --git a/src/opengl/GLGpu.cpp b/src/opengl/GLGpu.cpp index 68f0b120..ebde52f4 100644 --- a/src/opengl/GLGpu.cpp +++ b/src/opengl/GLGpu.cpp @@ -240,6 +240,9 @@ bool GLGpu::waitSemaphore(const Semaphore* semaphore) { RenderPass* GLGpu::getRenderPass(std::shared_ptr renderTarget, std::shared_ptr renderTargetTexture) { + if (renderTarget == nullptr) { + return nullptr; + } if (glRenderPass == nullptr) { glRenderPass = GLRenderPass::Make(_context); } diff --git a/src/opengl/GLRenderTarget.cpp b/src/opengl/GLRenderTarget.cpp index a549f92d..e4b99c31 100644 --- a/src/opengl/GLRenderTarget.cpp +++ b/src/opengl/GLRenderTarget.cpp @@ -36,9 +36,13 @@ std::shared_ptr RenderTarget::MakeFrom(Context* context, if (!renderTarget.getGLFramebufferInfo(&frameBufferInfo)) { return nullptr; } + auto format = GLSizeFormatToPixelFormat(frameBufferInfo.format); + if (!context->caps()->isFormatRenderable(format)) { + return nullptr; + } GLFrameBuffer frameBuffer = {}; frameBuffer.id = frameBufferInfo.id; - frameBuffer.format = GLSizeFormatToPixelFormat(frameBufferInfo.format); + frameBuffer.format = format; auto target = new GLRenderTarget(renderTarget.width(), renderTarget.height(), origin, 1, frameBuffer); target->frameBufferForDraw = frameBuffer; @@ -328,8 +332,4 @@ void GLRenderTarget::onReleaseGPU() { } ReleaseResource(context, &frameBufferForRead, &frameBufferForDraw, &msRenderBufferID); } - -const Swizzle& GLRenderTarget::writeSwizzle() const { - return context->caps()->getWriteSwizzle(frameBufferForDraw.format); -} } // namespace tgfx diff --git a/src/opengl/GLRenderTarget.h b/src/opengl/GLRenderTarget.h index 97db9676..c9f4cfe0 100644 --- a/src/opengl/GLRenderTarget.h +++ b/src/opengl/GLRenderTarget.h @@ -59,8 +59,6 @@ class GLRenderTarget : public RenderTarget { void onReleaseGPU() override; - const Swizzle& writeSwizzle() const override; - friend class RenderTarget; }; } // namespace tgfx diff --git a/src/opengl/qt/QGLWindow.cpp b/src/opengl/qt/QGLWindow.cpp index 75c6f44e..04c4ff42 100644 --- a/src/opengl/qt/QGLWindow.cpp +++ b/src/opengl/qt/QGLWindow.cpp @@ -180,12 +180,12 @@ std::shared_ptr QGLWindow::onCreateSurface(Context* context) { return nullptr; } if (!singleBufferMode) { - fontSurface = Surface::MakeFrom(Texture::MakeRGBA(context, width, height)); + fontSurface = Surface::Make(context, width, height, ColorType::RGBA_8888); if (fontSurface == nullptr) { return nullptr; } } - auto backSurface = Surface::MakeFrom(Texture::MakeRGBA(context, width, height)); + auto backSurface = Surface::Make(context, width, height, ColorType::RGBA_8888); if (backSurface == nullptr) { fontSurface = nullptr; return nullptr; diff --git a/test/src/SurfaceTest.cpp b/test/src/SurfaceTest.cpp index b41c7701..827c526a 100644 --- a/test/src/SurfaceTest.cpp +++ b/test/src/SurfaceTest.cpp @@ -56,11 +56,11 @@ TGFX_TEST(SurfaceTest, ImageSnapshot) { surface = Surface::Make(context, width, height); canvas = surface->getCanvas(); snapshotImage = surface->makeImageSnapshot(); - auto texture = surface->texture; + auto renderTargetProxy = surface->renderTargetProxy; snapshotImage = nullptr; canvas->drawImage(image); canvas->flush(); - EXPECT_TRUE(texture == surface->texture); + EXPECT_TRUE(renderTargetProxy == surface->renderTargetProxy); snapshotImage = surface->makeImageSnapshot(); snapshotImage2 = surface->makeImageSnapshot(); EXPECT_TRUE(snapshotImage == snapshotImage2);