Add "lazy" texture proxies

Adds ultra-deferred proxies that are instantiated by a user-supplied
callback during flush.

Bug: skia:7190
Change-Id: I75a7ac6dba953c3b0a99febc203a7f4d2f3789fc
Reviewed-on: https://skia-review.googlesource.com/76461
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Chris Dalton 2017-11-29 22:01:06 -07:00 committed by Skia Commit-Bot
parent de2f1dfebd
commit 706a6ff60c
18 changed files with 412 additions and 32 deletions

View File

@ -124,6 +124,7 @@ tests_sources = [
"$_tests/IsClosedSingleContourTest.cpp",
"$_tests/LayerDrawLooperTest.cpp",
"$_tests/LayerRasterizerTest.cpp",
"$_tests/LazyProxyTest.cpp",
"$_tests/LListTest.cpp",
"$_tests/LRUCacheTest.cpp",
"$_tests/MallocPixelRefTest.cpp",

View File

@ -67,6 +67,9 @@ protected:
GrRenderTargetProxy(const GrCaps&, const GrSurfaceDesc&,
SkBackingFit, SkBudgeted, uint32_t flags);
// Lazy-callback version
GrRenderTargetProxy(LazyInstantiateCallback&&, GrPixelConfig);
// Wrapped version
GrRenderTargetProxy(sk_sp<GrSurface>, GrSurfaceOrigin);
@ -74,6 +77,7 @@ protected:
private:
size_t onUninstantiatedGpuMemorySize() const override;
SkDEBUGCODE(void validateLazyTexture(const GrTexture*) override { SkASSERT(0); })
int fSampleCnt;
bool fNeedsStencil;

View File

@ -212,15 +212,34 @@ public:
static sk_sp<GrTextureProxy> MakeWrappedBackend(GrContext*, GrBackendTexture&, GrSurfaceOrigin);
using LazyInstantiateCallback = std::function<sk_sp<GrTexture>(GrResourceProvider*,
GrSurfaceOrigin* outOrigin)>;
enum class Renderable : bool {
kNo = false,
kYes = true
};
/**
* Creates a texture proxy that will be instantiated by a user-supplied callback during flush.
* (Mipmapping, MSAA, and stencil are not supported by this method.)
*/
static sk_sp<GrTextureProxy> MakeLazy(LazyInstantiateCallback&&, Renderable, GrPixelConfig);
GrPixelConfig config() const { return fConfig; }
int width() const { SkASSERT(!this->isPendingLazyInstantiation()); return fWidth; }
int height() const { SkASSERT(!this->isPendingLazyInstantiation()); return fHeight; }
int worstCaseWidth() const;
int worstCaseHeight() const;
GrSurfaceOrigin origin() const {
SkASSERT(!this->isPendingLazyInstantiation());
SkASSERT(kTopLeft_GrSurfaceOrigin == fOrigin || kBottomLeft_GrSurfaceOrigin == fOrigin);
return fOrigin;
}
int width() const { return fWidth; }
int height() const { return fHeight; }
int worstCaseWidth() const;
int worstCaseHeight() const;
GrPixelConfig config() const { return fConfig; }
// If the client gave us a LazyInstantiateCallback (via MakeLazy), then we will invoke that
// callback during flush. fWidth, fHeight, and fOrigin will be undefined until that time.
bool isPendingLazyInstantiation() const { return SkToBool(fLazyInstantiateCallback); }
class UniqueID {
public:
@ -230,7 +249,7 @@ public:
// wrapped
explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { }
// deferred
// deferred and lazy-callback
UniqueID() : fID(GrGpuResource::CreateUniqueID()) { }
uint32_t asUInt() const { return fID; }
@ -281,7 +300,10 @@ public:
/**
* Helper that gets the width and height of the surface as a bounding rectangle.
*/
SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); }
SkRect getBoundsRect() const {
SkASSERT(!this->isPendingLazyInstantiation());
return SkRect::MakeIWH(this->width(), this->height());
}
/**
* @return the texture proxy associated with the surface proxy, may be NULL.
@ -314,6 +336,7 @@ public:
* @return the amount of GPU memory used in bytes
*/
size_t gpuMemorySize() const {
SkASSERT(!this->isPendingLazyInstantiation());
if (fTarget) {
return fTarget->gpuMemorySize();
}
@ -363,6 +386,9 @@ protected:
// Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
}
// Lazy-callback version
GrSurfaceProxy(LazyInstantiateCallback&& callback, GrPixelConfig config);
// Wrapped version
GrSurfaceProxy(sk_sp<GrSurface> surface, GrSurfaceOrigin origin, SkBackingFit fit);
@ -392,23 +418,28 @@ protected:
GrSurfaceFlags flags, GrMipMapped mipMapped,
SkDestinationSurfaceColorMode mipColorMode, const GrUniqueKey*);
private:
// For wrapped resources, 'fConfig', 'fWidth', 'fHeight', and 'fOrigin; will always be filled in
// from the wrapped resource.
GrPixelConfig fConfig;
int fWidth;
int fHeight;
GrSurfaceOrigin fOrigin;
SkBackingFit fFit; // always exact for wrapped resources
mutable SkBudgeted fBudgeted; // set from the backing resource for wrapped resources
SkBackingFit fFit; // always kApprox for lazy-callback resources
// always kExact for wrapped resources
mutable SkBudgeted fBudgeted; // always kYes for lazy-callback resources
// set from the backing resource for wrapped resources
// mutable bc of SkSurface/SkImage wishy-washiness
const uint32_t fFlags;
const UniqueID fUniqueID; // set from the backing resource for wrapped resources
LazyInstantiateCallback fLazyInstantiateCallback;
SkDEBUGCODE(virtual void validateLazyTexture(const GrTexture*) = 0;)
static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; })
private:
virtual size_t onUninstantiatedGpuMemorySize() const = 0;
bool fNeedsClear;

View File

@ -67,6 +67,10 @@ protected:
// Deferred version
GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit, SkBudgeted,
const void* srcData, size_t srcRowBytes, uint32_t flags);
// Lazy-callback version
GrTextureProxy(LazyInstantiateCallback&&, GrPixelConfig);
// Wrapped version
GrTextureProxy(sk_sp<GrSurface>, GrSurfaceOrigin);
@ -94,6 +98,8 @@ private:
void setUniqueKey(GrResourceCache*, const GrUniqueKey&);
void clearUniqueKey();
SkDEBUGCODE(void validateLazyTexture(const GrTexture*) override;)
// For wrapped proxies the GrTexture pointer is stored in GrIORefProxy.
// For deferred proxies that pointer will be filled in when we need to instantiate
// the deferred resource

View File

@ -24,6 +24,8 @@ using GrStdSteadyClock = std::chrono::monotonic_clock;
using GrStdSteadyClock = std::chrono::steady_clock;
#endif
static constexpr GrSurfaceOrigin kGrUnknownSurfaceOrigin = static_cast<GrSurfaceOrigin>(-1);
/** This enum is used to specify the load operation to be used when an
* opList/GrGpuCommandBuffer begins execution.
*/

View File

@ -21,6 +21,8 @@
#include "GrSurfaceProxyPriv.h"
#include "GrTextureContext.h"
#include "GrTextureOpList.h"
#include "GrTextureProxy.h"
#include "GrTextureProxyPriv.h"
#include "SkSurface_Gpu.h"
#include "SkTTopoSort.h"
@ -150,10 +152,18 @@ GrSemaphoresSubmitted GrDrawingManager::internalFlush(GrSurfaceProxy*,
fFlushingOpListIDs.begin(), fFlushingOpListIDs.count(),
&renderTargetContexts);
for (const sk_sp<GrRenderTargetContext>& rtc : renderTargetContexts) {
sk_sp<GrOpList> onFlushOpList = sk_ref_sp(rtc->getOpList());
sk_sp<GrRenderTargetOpList> onFlushOpList = sk_ref_sp(rtc->getRTOpList());
if (!onFlushOpList) {
continue; // Odd - but not a big deal
}
#ifdef SK_DEBUG
// OnFlush callbacks are already invoked during flush, and are therefore expected to
// handle resource allocation & usage on their own. (No deferred or lazy proxies!)
onFlushOpList->visitProxies_debugOnly([](GrSurfaceProxy* p) {
SkASSERT(!p->asTextureProxy() || !p->asTextureProxy()->texPriv().isDeferred());
SkASSERT(!p->isPendingLazyInstantiation());
});
#endif
onFlushOpList->makeClosed(*fContext->caps());
onFlushOpList->prepare(&fFlushState);
fOnFlushCBOpLists.push_back(std::move(onFlushOpList));

View File

@ -109,6 +109,7 @@ public:
}
uint32_t testingOnly_addDrawOp(std::unique_ptr<GrDrawOp>);
uint32_t testingOnly_addDrawOp(const GrClip&, std::unique_ptr<GrDrawOp>);
bool refsWrappedObjects() const {
return fRenderTargetContext->fRenderTargetProxy->refsWrappedObjects();

View File

@ -60,6 +60,12 @@ void GrRenderTargetOpList::dump() const {
}
}
}
void GrRenderTargetOpList::visitProxies_debugOnly(const GrOp::VisitProxyFunc& func) const {
for (const RecordedOp& recordedOp : fRecordedOps) {
recordedOp.visitProxies(func);
}
}
#endif
void GrRenderTargetOpList::onPrepare(GrOpFlushState* flushState) {

View File

@ -125,6 +125,7 @@ public:
SkDEBUGCODE(int numOps() const override { return fRecordedOps.count(); })
SkDEBUGCODE(int numClips() const override { return fNumClips; })
SkDEBUGCODE(void visitProxies_debugOnly(const GrOp::VisitProxyFunc&) const;)
private:
friend class GrRenderTargetContextPriv; // for stencil clip state. TODO: this is invasive

View File

@ -34,12 +34,20 @@ GrRenderTargetProxy::GrRenderTargetProxy(const GrCaps& caps, const GrSurfaceDesc
}
}
// Lazy-callback version
GrRenderTargetProxy::GrRenderTargetProxy(LazyInstantiateCallback&& callback, GrPixelConfig config)
: INHERITED(std::move(callback), config)
, fSampleCnt(0)
, fNeedsStencil(false)
, fRenderTargetFlags(GrRenderTargetFlags::kNone) {
}
// Wrapped version
GrRenderTargetProxy::GrRenderTargetProxy(sk_sp<GrSurface> surf, GrSurfaceOrigin origin)
: INHERITED(std::move(surf), origin, SkBackingFit::kExact)
, fSampleCnt(fTarget->asRenderTarget()->numStencilSamples())
, fNeedsStencil(false)
, fRenderTargetFlags(fTarget->asRenderTarget()->renderTargetPriv().flags()) {
: INHERITED(std::move(surf), origin, SkBackingFit::kExact)
, fSampleCnt(fTarget->asRenderTarget()->numStencilSamples())
, fNeedsStencil(false)
, fRenderTargetFlags(fTarget->asRenderTarget()->renderTargetPriv().flags()) {
}
int GrRenderTargetProxy::maxWindowRectangles(const GrCaps& caps) const {
@ -85,8 +93,8 @@ size_t GrRenderTargetProxy::onUninstantiatedGpuMemorySize() const {
int colorSamplesPerPixel = this->numColorSamples() + 1;
// TODO: do we have enough information to improve this worst case estimate?
return GrSurface::ComputeSize(fConfig, fWidth, fHeight, colorSamplesPerPixel, GrMipMapped::kNo,
SkBackingFit::kApprox == fFit);
return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
colorSamplesPerPixel, GrMipMapped::kNo, !this->priv().isExact());
}
bool GrRenderTargetProxy::refsWrappedObjects() const {

View File

@ -73,6 +73,13 @@ void GrResourceAllocator::addInterval(GrSurfaceProxy* proxy, unsigned int start,
fIntvlList.insertByIncreasingStart(newIntvl);
fIntvlHash.add(newIntvl);
#ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
// FIXME: remove this once we can do the lazy instantiation from assign instead.
if (proxy->isPendingLazyInstantiation()) {
proxy->priv().doLazyInstantiation(fResourceProvider);
}
#endif
}
GrResourceAllocator::Interval* GrResourceAllocator::IntervalList::popHead() {
@ -224,8 +231,9 @@ bool GrResourceAllocator::assign(int* startIndex, int* stopIndex) {
continue;
}
sk_sp<GrSurface> surface = this->findSurfaceFor(cur->proxy(), needsStencil);
if (surface) {
if (cur->proxy()->isPendingLazyInstantiation()) {
cur->proxy()->priv().doLazyInstantiation(fResourceProvider);
} else if (sk_sp<GrSurface> surface = this->findSurfaceFor(cur->proxy(), needsStencil)) {
// TODO: make getUniqueKey virtual on GrSurfaceProxy
GrTextureProxy* tex = cur->proxy()->asTextureProxy();
if (tex && tex->getUniqueKey().isValid()) {

View File

@ -21,6 +21,23 @@
#include "SkMathPriv.h"
#include "SkMipMap.h"
// Lazy-callback version
GrSurfaceProxy::GrSurfaceProxy(LazyInstantiateCallback&& callback, GrPixelConfig config)
: fConfig(config)
, fWidth(-1) // Width, height, and origin will be initialized upon lazy instantiation.
, fHeight(-1)
, fOrigin(kGrUnknownSurfaceOrigin)
, fFit(SkBackingFit::kApprox)
, fBudgeted(SkBudgeted::kYes)
, fFlags(GrResourceProvider::kNoPendingIO_Flag)
, fLazyInstantiateCallback(std::move(callback))
, fNeedsClear(false)
, fGpuMemorySize(kInvalidGpuMemorySize)
, fLastOpList(nullptr) {
// NOTE: the default fUniqueID ctor pulls a value from the same pool as the GrGpuResources.
}
// Wrapped version
GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, GrSurfaceOrigin origin, SkBackingFit fit)
: INHERITED(std::move(surface))
, fConfig(fTarget->config())
@ -64,6 +81,7 @@ sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(
int sampleCnt, bool needsStencil,
GrSurfaceFlags flags, GrMipMapped mipMapped,
SkDestinationSurfaceColorMode mipColorMode) const {
SkASSERT(!this->isPendingLazyInstantiation());
SkASSERT(GrMipMapped::kNo == mipMapped);
GrSurfaceDesc desc;
desc.fFlags = flags;
@ -96,6 +114,7 @@ sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(
}
void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
SkASSERT(!this->isPendingLazyInstantiation());
SkASSERT(!fTarget && surface);
fTarget = surface.release();
this->INHERITED::transferRefs();
@ -111,6 +130,7 @@ bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int s
bool needsStencil, GrSurfaceFlags flags, GrMipMapped mipMapped,
SkDestinationSurfaceColorMode mipColorMode,
const GrUniqueKey* uniqueKey) {
SkASSERT(!this->isPendingLazyInstantiation());
if (fTarget) {
if (uniqueKey) {
SkASSERT(fTarget->getUniqueKey() == *uniqueKey);
@ -135,6 +155,7 @@ bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int s
}
void GrSurfaceProxy::computeScratchKey(GrScratchKey* key) const {
SkASSERT(!this->isPendingLazyInstantiation());
const GrRenderTargetProxy* rtp = this->asRenderTargetProxy();
int sampleCount = 0;
if (rtp) {
@ -377,7 +398,15 @@ sk_sp<GrTextureProxy> GrSurfaceProxy::MakeWrappedBackend(GrContext* context,
return GrSurfaceProxy::MakeWrapped(std::move(tex), origin);
}
sk_sp<GrTextureProxy> GrSurfaceProxy::MakeLazy(LazyInstantiateCallback&& callback,
Renderable renderable, GrPixelConfig config) {
return sk_sp<GrTextureProxy>(Renderable::kYes == renderable ?
new GrTextureRenderTargetProxy(std::move(callback), config) :
new GrTextureProxy(std::move(callback), config));
}
int GrSurfaceProxy::worstCaseWidth() const {
SkASSERT(!this->isPendingLazyInstantiation());
if (fTarget) {
return fTarget->width();
}
@ -389,6 +418,7 @@ int GrSurfaceProxy::worstCaseWidth() const {
}
int GrSurfaceProxy::worstCaseHeight() const {
SkASSERT(!this->isPendingLazyInstantiation());
if (fTarget) {
return fTarget->height();
}
@ -414,6 +444,7 @@ sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context,
GrMipMapped mipMapped,
SkIRect srcRect,
SkBudgeted budgeted) {
SkASSERT(!src->isPendingLazyInstantiation());
if (!srcRect.intersect(SkIRect::MakeWH(src->width(), src->height()))) {
return nullptr;
}
@ -442,12 +473,13 @@ sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context,
sk_sp<GrTextureProxy> GrSurfaceProxy::Copy(GrContext* context, GrSurfaceProxy* src,
GrMipMapped mipMapped, SkBudgeted budgeted) {
SkASSERT(!src->isPendingLazyInstantiation());
return Copy(context, src, mipMapped, SkIRect::MakeWH(src->width(), src->height()), budgeted);
}
sk_sp<GrSurfaceContext> GrSurfaceProxy::TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc,
GrSurfaceProxy* srcProxy) {
SkASSERT(!srcProxy->isPendingLazyInstantiation());
sk_sp<GrSurfaceContext> dstContext(context->contextPriv().makeDeferredSurfaceContext(
dstDesc,
GrMipMapped::kNo,
@ -465,6 +497,7 @@ sk_sp<GrSurfaceContext> GrSurfaceProxy::TestCopy(GrContext* context, const GrSur
}
void GrSurfaceProxyPriv::exactify() {
SkASSERT(!fProxy->isPendingLazyInstantiation());
if (this->isExact()) {
return;
}
@ -491,3 +524,30 @@ void GrSurfaceProxyPriv::exactify() {
// exact amount.
}
void GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) {
SkASSERT(fProxy->fLazyInstantiateCallback);
SkASSERT(!fProxy->fTarget);
sk_sp<GrTexture> texture = fProxy->fLazyInstantiateCallback(resourceProvider, &fProxy->fOrigin);
// Indicate we are no longer pending lazy instantiation.
fProxy->fLazyInstantiateCallback = nullptr;
if (!texture) {
fProxy->fWidth = 0;
fProxy->fHeight = 0;
fProxy->fOrigin = kTopLeft_GrSurfaceOrigin;
return;
}
fProxy->fWidth = texture->width();
fProxy->fHeight = texture->height();
SkASSERT(texture->config() == fProxy->fConfig);
SkASSERT(kGrUnknownSurfaceOrigin != fProxy->origin());
SkASSERT(kTopLeft_GrSurfaceOrigin == fProxy->fOrigin ||
kBottomLeft_GrSurfaceOrigin == fProxy->fOrigin);
SkDEBUGCODE(fProxy->validateLazyTexture(texture.get());)
this->assign(std::move(texture));
}

View File

@ -68,6 +68,8 @@ public:
// Don't. Just don't.
void exactify();
void doLazyInstantiation(GrResourceProvider*);
static bool AttachStencilIfNeeded(GrResourceProvider*, GrSurface*, bool needsStencil);
private:

View File

@ -13,6 +13,7 @@
#include "GrResourceCache.h"
#include "GrTexturePriv.h"
// Deferred version
GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit fit, SkBudgeted budgeted,
const void* srcData, size_t /*rowBytes*/, uint32_t flags)
: INHERITED(srcDesc, fit, budgeted, flags)
@ -23,6 +24,16 @@ GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit fit, S
SkASSERT(!srcData); // currently handled in Make()
}
// Lazy-callback version
GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback, GrPixelConfig config)
: INHERITED(std::move(callback), config)
, fMipMapped(GrMipMapped::kNo)
, fMipColorMode(SkDestinationSurfaceColorMode::kLegacy)
, fCache(nullptr)
, fDeferredUploader(nullptr) {
}
// Wrapped version
GrTextureProxy::GrTextureProxy(sk_sp<GrSurface> surf, GrSurfaceOrigin origin)
: INHERITED(std::move(surf), origin, SkBackingFit::kExact)
, fMipMapped(fTarget->asTexture()->texturePriv().mipMapped())
@ -109,8 +120,8 @@ GrSamplerState::Filter GrTextureProxy::highestFilterMode() const {
}
size_t GrTextureProxy::onUninstantiatedGpuMemorySize() const {
return GrSurface::ComputeSize(fConfig, fWidth, fHeight, 1, this->mipMapped(),
SkBackingFit::kApprox == fFit);
return GrSurface::ComputeSize(this->config(), this->width(), this->height(), 1,
this->mipMapped(), !this->priv().isExact());
}
void GrTextureProxy::setUniqueKey(GrResourceCache* cache, const GrUniqueKey& key) {
@ -131,3 +142,10 @@ void GrTextureProxy::clearUniqueKey() {
fCache = nullptr;
}
#ifdef SK_DEBUG
void GrTextureProxy::validateLazyTexture(const GrTexture* texture) {
SkASSERT(!texture->asRenderTarget());
SkASSERT(GrMipMapped::kNo == this->mipMapped());
}
#endif

View File

@ -7,6 +7,10 @@
#include "GrTextureRenderTargetProxy.h"
#include "GrTexture.h"
#include "GrRenderTarget.h"
#include "GrSurfaceProxyPriv.h"
// Deferred version
// This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and
// GrRenderTargetProxy) so its constructor must be explicitly called.
@ -15,10 +19,20 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps,
SkBackingFit fit,
SkBudgeted budgeted,
uint32_t flags)
: GrSurfaceProxy(desc, fit, budgeted, flags)
// for now textures w/ data are always wrapped
, GrTextureProxy(desc, fit, budgeted, nullptr, 0, flags)
, GrRenderTargetProxy(caps, desc, fit, budgeted, flags) {
: GrSurfaceProxy(desc, fit, budgeted, flags)
// for now textures w/ data are always wrapped
, GrTextureProxy(desc, fit, budgeted, nullptr, 0, flags)
, GrRenderTargetProxy(caps, desc, fit, budgeted, flags) {
}
// Lazy-callback version
GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(LazyInstantiateCallback&& callback,
GrPixelConfig config)
: GrSurfaceProxy(std::move(callback), config)
// Since we have virtual inheritance, we initialize GrSurfaceProxy directly. Send null
// callbacks to the texture and RT proxies simply to route to the appropriate constructors.
, GrTextureProxy(LazyInstantiateCallback(), config)
, GrRenderTargetProxy(LazyInstantiateCallback(), config) {
}
// Wrapped version
@ -26,9 +40,9 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps,
// GrRenderTargetProxy) so its constructor must be explicitly called.
GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(sk_sp<GrSurface> surf,
GrSurfaceOrigin origin)
: GrSurfaceProxy(surf, origin, SkBackingFit::kExact)
, GrTextureProxy(surf, origin)
, GrRenderTargetProxy(surf, origin) {
: GrSurfaceProxy(surf, origin, SkBackingFit::kExact)
, GrTextureProxy(surf, origin)
, GrRenderTargetProxy(surf, origin) {
SkASSERT(surf->asTexture());
SkASSERT(surf->asRenderTarget());
}
@ -37,8 +51,8 @@ size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize() const {
int colorSamplesPerPixel = this->numColorSamples() + 1;
// TODO: do we have enough information to improve this worst case estimate?
return GrSurface::ComputeSize(fConfig, fWidth, fHeight, colorSamplesPerPixel, this->mipMapped(),
SkBackingFit::kApprox == fFit);
return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
colorSamplesPerPixel, this->mipMapped(), !this->priv().isExact());
}
bool GrTextureRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) {
@ -77,3 +91,11 @@ sk_sp<GrSurface> GrTextureRenderTargetProxy::createSurface(
return surface;
}
#ifdef SK_DEBUG
void GrTextureRenderTargetProxy::validateLazyTexture(const GrTexture* texture) {
SkASSERT(texture->asRenderTarget());
SkASSERT(texture->asRenderTarget()->numStencilSamples() == this->numStencilSamples());
SkASSERT(GrMipMapped::kNo == this->mipMapped());
}
#endif

View File

@ -29,6 +29,9 @@ private:
GrTextureRenderTargetProxy(const GrCaps&, const GrSurfaceDesc&,
SkBackingFit, SkBudgeted, uint32_t flags);
// Lazy-callback version
GrTextureRenderTargetProxy(LazyInstantiateCallback&&, GrPixelConfig);
// Wrapped version
GrTextureRenderTargetProxy(sk_sp<GrSurface>, GrSurfaceOrigin);
@ -36,6 +39,8 @@ private:
sk_sp<GrSurface> createSurface(GrResourceProvider*) const override;
size_t onUninstantiatedGpuMemorySize() const override;
SkDEBUGCODE(void validateLazyTexture(const GrTexture*) override;)
};
#ifdef SK_BUILD_FOR_WIN

189
tests/LazyProxyTest.cpp Normal file
View File

@ -0,0 +1,189 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Test.h"
#if SK_SUPPORT_GPU
#include "GrClip.h"
#include "GrContextPriv.h"
#include "GrOnFlushResourceProvider.h"
#include "GrRenderTargetContext.h"
#include "GrRenderTargetContextPriv.h"
#include "GrSurfaceProxy.h"
#include "GrTexture.h"
#include "GrTextureProxy.h"
#include "GrTextureProxyPriv.h"
#include "SkMakeUnique.h"
#include "mock/GrMockTypes.h"
// This test verifies that lazy proxy callbacks get invoked during flush, after onFlush callbacks,
// but before Ops are executed. It also ensures that lazy proxy callbacks are invoked both for
// regular Ops and for clips.
class LazyProxyTest final : public GrOnFlushCallbackObject {
public:
LazyProxyTest(skiatest::Reporter* reporter)
: fReporter(reporter)
, fHasOpTexture(false)
, fHasClipTexture(false) {
}
~LazyProxyTest() override {
REPORTER_ASSERT(fReporter, fHasOpTexture);
REPORTER_ASSERT(fReporter, fHasClipTexture);
}
void preFlush(GrOnFlushResourceProvider*, const uint32_t*, int,
SkTArray<sk_sp<GrRenderTargetContext>>*) override {
REPORTER_ASSERT(fReporter, !fHasOpTexture);
REPORTER_ASSERT(fReporter, !fHasClipTexture);
}
void postFlush(GrDeferredUploadToken, const uint32_t* opListIDs, int numOpListIDs) override {
REPORTER_ASSERT(fReporter, fHasOpTexture);
REPORTER_ASSERT(fReporter, fHasClipTexture);
}
class Op final : public GrDrawOp {
public:
DEFINE_OP_CLASS_ID
Op(LazyProxyTest* test, bool nullTexture) : GrDrawOp(ClassID()), fTest(test) {
fProxy = GrSurfaceProxy::MakeLazy([this, nullTexture](GrResourceProvider* rp,
GrSurfaceOrigin* origin) {
REPORTER_ASSERT(fTest->fReporter, !fTest->fHasOpTexture);
fTest->fHasOpTexture = true;
*origin = kTopLeft_GrSurfaceOrigin;
if (nullTexture) {
return sk_sp<GrTexture>();
} else {
GrSurfaceDesc desc;
desc.fWidth = 1234;
desc.fHeight = 567;
desc.fOrigin = kTopLeft_GrSurfaceOrigin;
desc.fConfig = kRGB_565_GrPixelConfig;
sk_sp<GrTexture> texture = rp->createTexture(desc, SkBudgeted::kYes);
REPORTER_ASSERT(fTest->fReporter, texture);
return texture;
}
}, GrSurfaceProxy::Renderable::kNo, kRGB_565_GrPixelConfig);
this->setBounds(SkRect::MakeLargest(), GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
}
void visitProxies(const VisitProxyFunc& func) const override {
func(fProxy.get());
}
void onExecute(GrOpFlushState*) override {
REPORTER_ASSERT(fTest->fReporter, fTest->fHasOpTexture);
REPORTER_ASSERT(fTest->fReporter, fTest->fHasClipTexture);
}
private:
const char* name() const override { return "LazyProxyTest::Op"; }
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
GrPixelConfigIsClamped) override {
return RequiresDstTexture::kNo;
}
void wasRecorded(GrRenderTargetOpList*) override {}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
LazyProxyTest* const fTest;
sk_sp<GrTextureProxy> fProxy;
};
class ClipFP : public GrFragmentProcessor {
public:
ClipFP(LazyProxyTest* test, GrTextureProxy* atlas)
: GrFragmentProcessor(kTestFP_ClassID, kNone_OptimizationFlags)
, fTest(test)
, fAtlas(atlas) {
fLazyProxy = GrSurfaceProxy::MakeLazy([this](GrResourceProvider* rp,
GrSurfaceOrigin* origin) {
REPORTER_ASSERT(fTest->fReporter, !fTest->fHasClipTexture);
fTest->fHasClipTexture = true;
*origin = kBottomLeft_GrSurfaceOrigin;
fAtlas->instantiate(rp);
return sk_ref_sp(fAtlas->priv().peekTexture());
}, GrSurfaceProxy::Renderable::kYes, kAlpha_half_GrPixelConfig);
fAccess.reset(fLazyProxy, GrSamplerState::Filter::kNearest,
GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag);
this->addTextureSampler(&fAccess);
}
private:
const char* name() const override { return "LazyProxyTest::ClipFP"; }
std::unique_ptr<GrFragmentProcessor> clone() const override {
return skstd::make_unique<ClipFP>(fTest, fAtlas);
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return nullptr; }
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
LazyProxyTest* const fTest;
GrTextureProxy* const fAtlas;
sk_sp<GrTextureProxy> fLazyProxy;
TextureSampler fAccess;
};
class Clip : public GrClip {
public:
Clip(LazyProxyTest* test, GrTextureProxy* atlas)
: fTest(test)
, fAtlas(atlas) {}
private:
bool apply(GrContext*, GrRenderTargetContext*, bool, bool, GrAppliedClip* out,
SkRect* bounds) const override {
out->addCoverageFP(skstd::make_unique<ClipFP>(fTest, fAtlas));
return true;
}
bool quickContains(const SkRect&) const final { return false; }
bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const final { return false; }
void getConservativeBounds(int width, int height, SkIRect* rect, bool* iior) const final {
rect->set(0, 0, width, height);
if (iior) {
*iior = false;
}
}
LazyProxyTest* const fTest;
GrTextureProxy* fAtlas;
};
private:
skiatest::Reporter* fReporter;
bool fHasOpTexture;
bool fHasClipTexture;
};
DEF_GPUTEST(LazyProxyTest, reporter, /* options */) {
GrMockOptions mockOptions;
mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fRenderable[0] = true;
mockOptions.fConfigOptions[kAlpha_half_GrPixelConfig].fTexturable = true;
sk_sp<GrContext> ctx = GrContext::MakeMock(&mockOptions, GrContextOptions());
for (bool nullTexture : {false, true}) {
LazyProxyTest test(reporter);
ctx->contextPriv().addOnFlushCallbackObject(&test);
sk_sp<GrRenderTargetContext> rtc =
ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 100, 100,
kRGBA_8888_GrPixelConfig, nullptr);
REPORTER_ASSERT(reporter, rtc);
sk_sp<GrRenderTargetContext> mockAtlas =
ctx->makeDeferredRenderTargetContext(SkBackingFit::kExact, 10, 10,
kAlpha_half_GrPixelConfig, nullptr);
REPORTER_ASSERT(reporter, mockAtlas);
rtc->priv().testingOnly_addDrawOp(LazyProxyTest::Clip(&test, mockAtlas->asTextureProxy()),
skstd::make_unique<LazyProxyTest::Op>(&test, nullTexture));
ctx->contextPriv().testingOnly_flushAndRemoveOnFlushCallbackObject(&test);
}
}
#endif

View File

@ -274,7 +274,13 @@ int GrResourceCache::countUniqueKeysWithTag(const char* tag) const {
#define ASSERT_SINGLE_OWNER \
SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
uint32_t GrRenderTargetContextPriv::testingOnly_addDrawOp(std::unique_ptr<GrDrawOp> op) {
return this->testingOnly_addDrawOp(GrNoClip(), std::move(op));
}
uint32_t GrRenderTargetContextPriv::testingOnly_addDrawOp(const GrClip& clip,
std::unique_ptr<GrDrawOp> op) {
ASSERT_SINGLE_OWNER
if (fRenderTargetContext->drawingManager()->wasAbandoned()) {
return SK_InvalidUniqueID;
@ -282,7 +288,7 @@ uint32_t GrRenderTargetContextPriv::testingOnly_addDrawOp(std::unique_ptr<GrDraw
SkDEBUGCODE(fRenderTargetContext->validate());
GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
"GrRenderTargetContext::testingOnly_addDrawOp");
return fRenderTargetContext->addDrawOp(GrNoClip(), std::move(op));
return fRenderTargetContext->addDrawOp(clip, std::move(op));
}
#undef ASSERT_SINGLE_OWNER