/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ // This is a GPU-backend specific test. #include "Test.h" #if SK_SUPPORT_GPU #include "GrRenderTargetPriv.h" #include "GrRenderTargetProxy.h" #include "GrResourceProvider.h" #include "GrSurfaceProxy.h" #include "GrTextureProxy.h" int32_t GrIORefProxy::getProxyRefCnt_TestOnly() const { return fRefCnt; } int32_t GrIORefProxy::getBackingRefCnt_TestOnly() const { if (fTarget) { return fTarget->fRefCnt; } return fRefCnt; } int32_t GrIORefProxy::getPendingReadCnt_TestOnly() const { if (fTarget) { SkASSERT(!fPendingReads); return fTarget->fPendingReads; } return fPendingReads; } int32_t GrIORefProxy::getPendingWriteCnt_TestOnly() const { if (fTarget) { SkASSERT(!fPendingWrites); return fTarget->fPendingWrites; } return fPendingWrites; } static const int kWidthHeight = 128; static void check_refs(skiatest::Reporter* reporter, GrSurfaceProxy* proxy, int32_t expectedProxyRefs, int32_t expectedBackingRefs, int32_t expectedNumReads, int32_t expectedNumWrites) { REPORTER_ASSERT(reporter, proxy->getProxyRefCnt_TestOnly() == expectedProxyRefs); REPORTER_ASSERT(reporter, proxy->getBackingRefCnt_TestOnly() == expectedBackingRefs); REPORTER_ASSERT(reporter, proxy->getPendingReadCnt_TestOnly() == expectedNumReads); REPORTER_ASSERT(reporter, proxy->getPendingWriteCnt_TestOnly() == expectedNumWrites); SkASSERT(proxy->getProxyRefCnt_TestOnly() == expectedProxyRefs); SkASSERT(proxy->getBackingRefCnt_TestOnly() == expectedBackingRefs); SkASSERT(proxy->getPendingReadCnt_TestOnly() == expectedNumReads); SkASSERT(proxy->getPendingWriteCnt_TestOnly() == expectedNumWrites); } static sk_sp make_deferred(GrResourceProvider* provider) { GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = kWidthHeight; desc.fHeight = kWidthHeight; desc.fConfig = kRGBA_8888_GrPixelConfig; return GrSurfaceProxy::MakeDeferred(provider, desc, SkBackingFit::kApprox, SkBudgeted::kYes); } static sk_sp make_wrapped(GrResourceProvider* provider) { GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = kWidthHeight; desc.fHeight = kWidthHeight; desc.fConfig = kRGBA_8888_GrPixelConfig; sk_sp tex(provider->createTexture(desc, SkBudgeted::kNo)); // Flush the IOWrite from the initial discard or it will confuse the later ref count checks tex->flushWrites(); return GrSurfaceProxy::MakeWrapped(std::move(tex)); } DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ProxyRefTest, reporter, ctxInfo) { GrResourceProvider* provider = ctxInfo.grContext()->resourceProvider(); const GrCaps& caps = *ctxInfo.grContext()->caps(); // Currently the op itself takes a pending write and the render target op list does as well. static const int kWritesForDiscard = 2; for (auto make : { make_deferred, make_wrapped }) { // A single write { sk_sp sProxy((*make)(provider)); GrPendingIOResource fWrite(sProxy.get()); check_refs(reporter, sProxy.get(), 1, 1, 0, 1); // In the deferred case, the discard op created on instantiation adds an // extra ref and write bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() && caps.discardRenderTargetSupport(); int expectedWrites = 1 + (proxyGetsDiscardRef ? kWritesForDiscard : 0); sProxy->instantiate(provider); // In the deferred case, this checks that the refs transfered to the GrSurface check_refs(reporter, sProxy.get(), 1, 1, 0, expectedWrites); } // A single read { sk_sp sProxy((*make)(provider)); GrPendingIOResource fRead(sProxy.get()); check_refs(reporter, sProxy.get(), 1, 1, 1, 0); // In the deferred case, the discard op created on instantiation adds an // extra ref and write bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() && caps.discardRenderTargetSupport(); int expectedWrites = proxyGetsDiscardRef ? kWritesForDiscard : 0; sProxy->instantiate(provider); // In the deferred case, this checks that the refs transfered to the GrSurface check_refs(reporter, sProxy.get(), 1, 1, 1, expectedWrites); } // A single read/write pair { sk_sp sProxy((*make)(provider)); GrPendingIOResource fRW(sProxy.get()); check_refs(reporter, sProxy.get(), 1, 1, 1, 1); // In the deferred case, the discard op created on instantiation adds an // extra ref and write bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() && caps.discardRenderTargetSupport(); int expectedWrites = 1 + (proxyGetsDiscardRef ? kWritesForDiscard : 0); sProxy->instantiate(provider); // In the deferred case, this checks that the refs transferred to the GrSurface check_refs(reporter, sProxy.get(), 1, 1, 1, expectedWrites); } // Multiple normal refs { sk_sp sProxy((*make)(provider)); sProxy->ref(); sProxy->ref(); check_refs(reporter, sProxy.get(), 3, 3, 0, 0); bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() && caps.discardRenderTargetSupport(); int expectedWrites = proxyGetsDiscardRef ? kWritesForDiscard : 0; sProxy->instantiate(provider); // In the deferred case, this checks that the refs transferred to the GrSurface check_refs(reporter, sProxy.get(), 3, 3, 0, expectedWrites); sProxy->unref(); sProxy->unref(); } // Continue using (reffing) proxy after instantiation { sk_sp sProxy((*make)(provider)); sProxy->ref(); GrPendingIOResource fWrite(sProxy.get()); check_refs(reporter, sProxy.get(), 2, 2, 0, 1); bool proxyGetsDiscardRef = !sProxy->isWrapped_ForTesting() && caps.discardRenderTargetSupport(); int expectedWrites = 1 + (proxyGetsDiscardRef ? kWritesForDiscard : 0); sProxy->instantiate(provider); // In the deferred case, this checks that the refs transfered to the GrSurface check_refs(reporter, sProxy.get(), 2, 2, 0, expectedWrites); sProxy->unref(); check_refs(reporter, sProxy.get(), 1, 1, 0, expectedWrites); GrPendingIOResource fRead(sProxy.get()); check_refs(reporter, sProxy.get(), 1, 1, 1, expectedWrites); } } } #endif