diff options
-rw-r--r-- | gn/gpu.gni | 2 | ||||
-rw-r--r-- | gn/tests.gni | 1 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 5 | ||||
-rw-r--r-- | src/gpu/GrContextPriv.h | 9 | ||||
-rw-r--r-- | src/gpu/GrDrawingManager.cpp | 47 | ||||
-rw-r--r-- | src/gpu/GrDrawingManager.h | 8 | ||||
-rw-r--r-- | src/gpu/GrPreFlushResourceProvider.cpp | 65 | ||||
-rw-r--r-- | src/gpu/GrPreFlushResourceProvider.h | 77 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetOpList.cpp | 21 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetOpList.h | 2 | ||||
-rw-r--r-- | src/gpu/GrTextureOpList.cpp | 6 | ||||
-rw-r--r-- | src/gpu/ops/GrTestMeshDrawOp.h | 2 | ||||
-rw-r--r-- | tests/PreFlushCallbackTest.cpp | 606 |
13 files changed, 13 insertions, 838 deletions
diff --git a/gn/gpu.gni b/gn/gpu.gni index 3046be8b78..6dc08a4b11 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -131,8 +131,6 @@ skia_gpu_sources = [ "$_src/gpu/GrPathUtils.cpp", "$_src/gpu/GrPathUtils.h", "$_src/gpu/GrPendingProgramElement.h", - "$_src/gpu/GrPreFlushResourceProvider.cpp", - "$_src/gpu/GrPreFlushResourceProvider.h", "$_src/gpu/GrPipeline.cpp", "$_src/gpu/GrPipeline.h", "$_src/gpu/GrPipelineBuilder.h", diff --git a/gn/tests.gni b/gn/tests.gni index e086e0a715..b2a814e1ba 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -152,7 +152,6 @@ tests_sources = [ "$_tests/PDFMetadataAttributeTest.cpp", "$_tests/PDFOpaqueSrcModeToSrcOverTest.cpp", "$_tests/PDFPrimitivesTest.cpp", - "$_tests/PreFlushCallbackTest.cpp", "$_tests/PictureBBHTest.cpp", "$_tests/PictureShaderTest.cpp", "$_tests/PictureTest.cpp", diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index bcb93b30be..c0d63a33b0 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -711,11 +711,6 @@ sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRend surfaceProps); } -void GrContextPriv::addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject) { - fContext->fDrawingManager->addPreFlushCallbackObject(std::move(preFlushCBObject)); -} - - static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) { switch (config) { case kAlpha_8_GrPixelConfig: diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h index 3357636605..c70381fe43 100644 --- a/src/gpu/GrContextPriv.h +++ b/src/gpu/GrContextPriv.h @@ -13,7 +13,6 @@ class GrSemaphore; class GrSurfaceProxy; -class GrPreFlushCallbackObject; /** Class that adds methods to GrContext that are only intended for use internal to Skia. This class is purely a privileged window into GrContext. It should never have additional @@ -59,15 +58,9 @@ public: bool disableGpuYUVConversion() const { return fContext->fDisableGpuYUVConversion; } - /* - * A ref will be taken on the preFlushCallbackObject which will be removed when the - * context is destroyed. - */ - void addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject>); - private: explicit GrContextPriv(GrContext* context) : fContext(context) {} - GrContextPriv(const GrContextPriv&); // unimpl + GrContextPriv(const GrContextPriv&) {} // unimpl GrContextPriv& operator=(const GrContextPriv&); // unimpl // No taking addresses of this type. diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp index 449cae6b61..d670e16b73 100644 --- a/src/gpu/GrDrawingManager.cpp +++ b/src/gpu/GrDrawingManager.cpp @@ -75,53 +75,10 @@ void GrDrawingManager::internalFlush(GrResourceCache::FlushType type) { } fFlushing = true; bool flushed = false; - - for (int i = 0; i < fOpLists.count(); ++i) { - // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh - // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed - // but need to be flushed anyway. Closing such GrOpLists here will mean new - // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again. - fOpLists[i]->makeClosed(); - } - SkDEBUGCODE(bool result =) SkTTopoSort<GrOpList, GrOpList::TopoSortTraits>(&fOpLists); SkASSERT(result); - GrPreFlushResourceProvider preFlushProvider(this); - - if (fPreFlushCBObjects.count()) { - // MDB TODO: pre-MDB '1' is the correct pre-allocated size. Post-MDB it will need - // to be larger. - SkAutoSTArray<1, uint32_t> opListIds(fOpLists.count()); - for (int i = 0; i < fOpLists.count(); ++i) { - opListIds[i] = fOpLists[i]->uniqueID(); - } - - SkSTArray<1, sk_sp<GrRenderTargetContext>> renderTargetContexts; - for (int i = 0; i < fPreFlushCBObjects.count(); ++i) { - fPreFlushCBObjects[i]->preFlush(&preFlushProvider, - opListIds.get(), opListIds.count(), - &renderTargetContexts); - if (!renderTargetContexts.count()) { - continue; // This is fine. No atlases of this type are required for this flush - } - - for (int j = 0; j < renderTargetContexts.count(); ++j) { - GrRenderTargetOpList* opList = renderTargetContexts[j]->getOpList(); - if (!opList) { - continue; // Odd - but not a big deal - } - SkDEBUGCODE(opList->validateTargetsSingleRenderTarget()); - opList->prepareOps(&fFlushState); - if (!opList->executeOps(&fFlushState)) { - continue; // This is bad - } - } - renderTargetContexts.reset(); - } - } - for (int i = 0; i < fOpLists.count(); ++i) { fOpLists[i]->prepareOps(&fFlushState); } @@ -188,10 +145,6 @@ void GrDrawingManager::prepareSurfaceForExternalIO(GrSurface* surface) { } } -void GrDrawingManager::addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject) { - fPreFlushCBObjects.push_back(preFlushCBObject); -} - GrRenderTargetOpList* GrDrawingManager::newOpList(GrRenderTargetProxy* rtp) { SkASSERT(fContext); diff --git a/src/gpu/GrDrawingManager.h b/src/gpu/GrDrawingManager.h index d914b03a75..061e878793 100644 --- a/src/gpu/GrDrawingManager.h +++ b/src/gpu/GrDrawingManager.h @@ -11,10 +11,9 @@ #include "GrOpFlushState.h" #include "GrPathRenderer.h" #include "GrPathRendererChain.h" -#include "GrPreFlushResourceProvider.h" #include "GrRenderTargetOpList.h" #include "GrResourceCache.h" -#include "SkTArray.h" +#include "SkTDArray.h" #include "text/GrAtlasTextContext.h" class GrContext; @@ -68,8 +67,6 @@ public: void prepareSurfaceForExternalIO(GrSurface*); - void addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject); - private: GrDrawingManager(GrContext* context, const GrRenderTargetOpList::Options& optionsForOpLists, @@ -95,7 +92,6 @@ private: void internalFlush(GrResourceCache::FlushType); friend class GrContext; // for access to: ctor, abandon, reset & flush - friend class GrPreFlushResourceProvider; // this is just a shallow wrapper around this class static const int kNumPixelGeometries = 5; // The different pixel geometries static const int kNumDFTOptions = 2; // DFT or no DFT @@ -119,8 +115,6 @@ private: bool fFlushing; bool fIsImmediateMode; - - SkTArray<sk_sp<GrPreFlushCallbackObject>> fPreFlushCBObjects; }; #endif diff --git a/src/gpu/GrPreFlushResourceProvider.cpp b/src/gpu/GrPreFlushResourceProvider.cpp deleted file mode 100644 index e907f3925d..0000000000 --- a/src/gpu/GrPreFlushResourceProvider.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 "GrPreFlushResourceProvider.h" - -#include "GrDrawingManager.h" -#include "GrSurfaceProxy.h" - -sk_sp<GrRenderTargetContext> GrPreFlushResourceProvider::makeRenderTargetContext( - const GrSurfaceDesc& desc, - sk_sp<SkColorSpace> colorSpace, - const SkSurfaceProps* props) { - GrSurfaceDesc tmpDesc = desc; - tmpDesc.fFlags |= kRenderTarget_GrSurfaceFlag; - - // Because this is being allocated at the start of a flush we must ensure the proxy - // will, when instantiated, have no pending IO. - // TODO: fold the kNoPendingIO_Flag into GrSurfaceFlags? - sk_sp<GrSurfaceProxy> proxy = GrSurfaceProxy::MakeDeferred( - fDrawingMgr->getContext()->resourceProvider(), - tmpDesc, - SkBackingFit::kExact, - SkBudgeted::kYes, - GrResourceProvider::kNoPendingIO_Flag); - if (!proxy->asRenderTargetProxy()) { - return nullptr; - } - - sk_sp<GrRenderTargetOpList> opList(new GrRenderTargetOpList( - proxy->asRenderTargetProxy(), - fDrawingMgr->fContext->getGpu(), - fDrawingMgr->fContext->resourceProvider(), - fDrawingMgr->fContext->getAuditTrail(), - fDrawingMgr->fOptionsForOpLists)); - proxy->setLastOpList(opList.get()); - - return fDrawingMgr->makeRenderTargetContext(std::move(proxy), - std::move(colorSpace), - props); -} - -// TODO: we only need this entry point as long as we have to pre-allocate the atlas. -// Remove it ASAP. -sk_sp<GrRenderTargetContext> GrPreFlushResourceProvider::makeRenderTargetContext( - sk_sp<GrSurfaceProxy> proxy, - sk_sp<SkColorSpace> colorSpace, - const SkSurfaceProps* props) { - - sk_sp<GrRenderTargetOpList> opList(new GrRenderTargetOpList( - proxy->asRenderTargetProxy(), - fDrawingMgr->fContext->getGpu(), - fDrawingMgr->fContext->resourceProvider(), - fDrawingMgr->fContext->getAuditTrail(), - fDrawingMgr->fOptionsForOpLists)); - proxy->setLastOpList(opList.get()); - - return fDrawingMgr->makeRenderTargetContext(std::move(proxy), - std::move(colorSpace), - props); -} - diff --git a/src/gpu/GrPreFlushResourceProvider.h b/src/gpu/GrPreFlushResourceProvider.h deleted file mode 100644 index 86a299a422..0000000000 --- a/src/gpu/GrPreFlushResourceProvider.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrPreFlushResourceProvider_DEFINED -#define GrPreFlushResourceProvider_DEFINED - -#include "GrTypes.h" -#include "GrNonAtomicRef.h" - -// These two are just for GrPreFlushCallbackObject -#include "SkRefCnt.h" -#include "SkTDArray.h" - -class GrDrawingManager; -class GrOpList; -class GrPreFlushResourceProvider; -class GrRenderTargetOpList; -class GrRenderTargetContext; -class GrSurfaceProxy; - -class SkColorSpace; -class SkSurfaceProps; - -/* - * This is the base class from which all per-flush callback objects must be derived. It - * provides the "preFlush" interface. - */ -class GrPreFlushCallbackObject : public GrNonAtomicRef<GrPreFlushCallbackObject> { -public: - virtual ~GrPreFlushCallbackObject() { } - - /* - * The preFlush callback allows subsystems (e.g., text, path renderers) to create atlases - * for a specific flush. All the GrOpList IDs required for the flush are passed into the - * callback. The callback should return the render target contexts used to render the atlases - * in 'results'. - */ - virtual void preFlush(GrPreFlushResourceProvider*, - const uint32_t* opListIDs, int numOpListIDs, - SkTArray<sk_sp<GrRenderTargetContext>>* results) = 0; - -private: - typedef SkRefCnt INHERITED; -}; - -/* - * This class is a shallow wrapper around the drawing manager. It is passed into the - * preFlush callbacks and is intended to limit the functionality available to them. - * It should never have additional data members or virtual methods. - */ -class GrPreFlushResourceProvider { -public: - sk_sp<GrRenderTargetContext> makeRenderTargetContext(const GrSurfaceDesc& desc, - sk_sp<SkColorSpace> colorSpace, - const SkSurfaceProps* props); - - // TODO: we only need this entry point as long as we have to pre-allocate the atlas. - // Remove it ASAP. - sk_sp<GrRenderTargetContext> makeRenderTargetContext(sk_sp<GrSurfaceProxy> proxy, - sk_sp<SkColorSpace> colorSpace, - const SkSurfaceProps* props); - -private: - explicit GrPreFlushResourceProvider(GrDrawingManager* drawingMgr) : fDrawingMgr(drawingMgr) {} - GrPreFlushResourceProvider(const GrPreFlushResourceProvider&); // unimpl - GrPreFlushResourceProvider& operator=(const GrPreFlushResourceProvider&); // unimpl - - GrDrawingManager* fDrawingMgr; - - friend class GrDrawingManager; // to construct this type. -}; - -#endif diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp index 8d47ffffce..1c9835389e 100644 --- a/src/gpu/GrRenderTargetOpList.cpp +++ b/src/gpu/GrRenderTargetOpList.cpp @@ -70,25 +70,14 @@ void GrRenderTargetOpList::dump() const { } } } - -void GrRenderTargetOpList::validateTargetsSingleRenderTarget() const { - GrRenderTarget* rt = nullptr; - for (int i = 0; i < fRecordedOps.count(); ++i) { - if (!fRecordedOps[i].fOp) { - continue; // combined forward - } - - if (!rt) { - rt = fRecordedOps[i].fRenderTarget.get(); - } else { - SkASSERT(fRecordedOps[i].fRenderTarget.get() == rt); - } - } -} #endif void GrRenderTargetOpList::prepareOps(GrOpFlushState* flushState) { - // MDB TODO: add SkASSERT(this->isClosed()); + // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh + // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed + // but need to be flushed anyway. Closing such GrOpLists here will mean new + // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again. + this->makeClosed(); // Loop over the ops that haven't yet been prepared. for (int i = 0; i < fRecordedOps.count(); ++i) { diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h index ab744f35e6..f4458b5775 100644 --- a/src/gpu/GrRenderTargetOpList.h +++ b/src/gpu/GrRenderTargetOpList.h @@ -102,8 +102,6 @@ public: SkDEBUGCODE(void dump() const override;) - SkDEBUGCODE(void validateTargetsSingleRenderTarget() const;) - private: friend class GrRenderTargetContextPriv; // for clearStencilClip and stencil clip state. diff --git a/src/gpu/GrTextureOpList.cpp b/src/gpu/GrTextureOpList.cpp index d396b2a5ea..d70daa2c79 100644 --- a/src/gpu/GrTextureOpList.cpp +++ b/src/gpu/GrTextureOpList.cpp @@ -45,7 +45,11 @@ void GrTextureOpList::dump() const { #endif void GrTextureOpList::prepareOps(GrOpFlushState* flushState) { - // MDB TODO: add SkASSERT(this->isClosed()); + // Semi-usually the GrOpLists are already closed at this point, but sometimes Ganesh + // needs to flush mid-draw. In that case, the SkGpuDevice's GrOpLists won't be closed + // but need to be flushed anyway. Closing such GrOpLists here will mean new + // GrOpLists will be created to replace them if the SkGpuDevice(s) write to them again. + this->makeClosed(); // Loop over the ops that haven't yet generated their geometry for (int i = 0; i < fRecordedOps.count(); ++i) { diff --git a/src/gpu/ops/GrTestMeshDrawOp.h b/src/gpu/ops/GrTestMeshDrawOp.h index 039f88d672..d78d3e9164 100644 --- a/src/gpu/ops/GrTestMeshDrawOp.h +++ b/src/gpu/ops/GrTestMeshDrawOp.h @@ -19,7 +19,7 @@ */ class GrTestMeshDrawOp : public GrMeshDrawOp { public: - const char* name() const override = 0; + virtual const char* name() const override = 0; protected: GrTestMeshDrawOp(uint32_t classID, const SkRect& bounds, GrColor color) diff --git a/tests/PreFlushCallbackTest.cpp b/tests/PreFlushCallbackTest.cpp deleted file mode 100644 index 78f5002277..0000000000 --- a/tests/PreFlushCallbackTest.cpp +++ /dev/null @@ -1,606 +0,0 @@ -/* - * 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 "GrDefaultGeoProcFactory.h" -#include "GrPreFlushResourceProvider.h" -#include "GrRenderTargetContextPriv.h" -#include "GrResourceProvider.h" -#include "GrQuad.h" -#include "effects/GrSimpleTextureEffect.h" -#include "ops/GrTestMeshDrawOp.h" - -// This is a simplified mesh drawing op that can be used in the atlas generation test. -// Please see AtlasedRectOp below. -class NonAARectOp : public GrMeshDrawOp { -public: - DEFINE_OP_CLASS_ID - const char* name() const override { return "NonAARectOp"; } - - // This creates an instance of a simple non-AA solid color rect-drawing Op - static std::unique_ptr<GrDrawOp> Make(const SkRect& r, GrColor color) { - return std::unique_ptr<GrDrawOp>(new NonAARectOp(ClassID(), r, color)); - } - - // This creates an instance of a simple non-AA textured rect-drawing Op - static std::unique_ptr<GrDrawOp> Make(const SkRect& r, GrColor color, const SkRect& local) { - return std::unique_ptr<GrDrawOp>(new NonAARectOp(ClassID(), r, color, local)); - } - - GrColor color() const { return fColor; } - -protected: - NonAARectOp(uint32_t classID, const SkRect& r, GrColor color) - : INHERITED(classID) - , fColor(color) - , fHasLocalRect(false) - , fRect(r) { - // Choose some conservative values for aa bloat and zero area. - this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes); - } - - NonAARectOp(uint32_t classID, const SkRect& r, GrColor color, const SkRect& local) - : INHERITED(classID) - , fColor(color) - , fHasLocalRect(true) - , fLocalQuad(local) - , fRect(r) { - // Choose some conservative values for aa bloat and zero area. - this->setBounds(r, HasAABloat::kYes, IsZeroArea::kYes); - } - - GrColor fColor; - bool fHasLocalRect; - GrQuad fLocalQuad; - SkRect fRect; - -private: - void getFragmentProcessorAnalysisInputs(FragmentProcessorAnalysisInputs* input) const override { - input->colorInput()->setToUnknown(); - input->coverageInput()->setToUnknown(); - } - - void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override { - optimizations.getOverrideColorIfSet(&fColor); - } - - bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; } - - void onPrepareDraws(Target* target) const override { - using namespace GrDefaultGeoProcFactory; - - // The vertex attrib order is always pos, color, local coords. - static const int kColorOffset = sizeof(SkPoint); - static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); - - sk_sp<GrGeometryProcessor> gp = - GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, - Coverage::kSolid_Type, - fHasLocalRect ? LocalCoords::kHasExplicit_Type - : LocalCoords::kUnused_Type, - SkMatrix::I()); - if (!gp) { - SkDebugf("Couldn't create GrGeometryProcessor for GrAtlasedOp\n"); - return; - } - - size_t vertexStride = gp->getVertexStride(); - - SkASSERT(fHasLocalRect - ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) - : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); - - const GrBuffer* indexBuffer; - int firstIndex; - uint16_t* indices = target->makeIndexSpace(6, &indexBuffer, &firstIndex); - if (!indices) { - SkDebugf("Indices could not be allocated for GrAtlasedOp.\n"); - return; - } - - const GrBuffer* vertexBuffer; - int firstVertex; - void* vertices = target->makeVertexSpace(vertexStride, 4, &vertexBuffer, &firstVertex); - if (!vertices) { - SkDebugf("Vertices could not be allocated for GrAtlasedOp.\n"); - return; - } - - // Setup indices - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 0; - indices[4] = 2; - indices[5] = 3; - - // Setup positions - SkPoint* position = (SkPoint*) vertices; - position->setRectFan(fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom, vertexStride); - - // Setup vertex colors - GrColor* color = (GrColor*)((intptr_t)vertices + kColorOffset); - for (int i = 0; i < 4; ++i) { - *color = fColor; - color = (GrColor*)((intptr_t)color + vertexStride); - } - - // Setup local coords - if (fHasLocalRect) { - SkPoint* coords = (SkPoint*)((intptr_t) vertices + kLocalOffset); - for (int i = 0; i < 4; i++) { - *coords = fLocalQuad.point(i); - coords = (SkPoint*)((intptr_t) coords + vertexStride); - } - } - - GrMesh mesh; - mesh.initIndexed(kTriangles_GrPrimitiveType, - vertexBuffer, indexBuffer, - firstVertex, firstIndex, - 4, 6); - - target->draw(gp.get(), mesh); - } - - typedef GrMeshDrawOp INHERITED; -}; - -#ifdef SK_DEBUG -#include "SkImageEncoder.h" -#include "sk_tool_utils.h" - -static void save_bm(const SkBitmap& bm, const char name[]) { - bool result = sk_tool_utils::EncodeImageToFile(name, bm, SkEncodedImageFormat::kPNG, 100); - SkASSERT(result); -} -#endif - -/* - * Atlased ops just draw themselves as textured rects with the texture pixels being - * pulled out of the atlas. Their color is based on their ID. - */ -class AtlasedRectOp final : public NonAARectOp { -public: - DEFINE_OP_CLASS_ID - - ~AtlasedRectOp() override { - fID = -1; - } - - const char* name() const override { return "AtlasedRectOp"; } - - int id() const { return fID; } - - static std::unique_ptr<AtlasedRectOp> Make(const SkRect& r, int id) { - return std::unique_ptr<AtlasedRectOp>(new AtlasedRectOp(r, id)); - } - - void setColor(GrColor color) { fColor = color; } - void setLocalRect(const SkRect& localRect) { - SkASSERT(fHasLocalRect); // This should've been created to anticipate this - fLocalQuad.set(localRect); - } - - AtlasedRectOp* next() const { return fNext; } - void setNext(AtlasedRectOp* next) { - fNext = next; - } - -private: - // We set the initial color of the NonAARectOp based on the ID. - // Note that we force creation of a NonAARectOp that has local coords in anticipation of - // pulling from the atlas. - AtlasedRectOp(const SkRect& r, int id) - : INHERITED(ClassID(), r, kColors[id], SkRect::MakeEmpty()) - , fID(id) - , fNext(nullptr) { - SkASSERT(fID < kMaxIDs); - } - - static const int kMaxIDs = 9; - static const SkColor kColors[kMaxIDs]; - - int fID; - // The Atlased ops have an internal singly-linked list of ops that land in the same opList - AtlasedRectOp* fNext; - - typedef NonAARectOp INHERITED; -}; - -const GrColor AtlasedRectOp::kColors[kMaxIDs] = { - GrColorPackRGBA(255, 0, 0, 255), - GrColorPackRGBA(0, 255, 0, 255), - GrColorPackRGBA(0, 0, 255, 255), - GrColorPackRGBA(0, 255, 255, 255), - GrColorPackRGBA(255, 0, 255, 255), - GrColorPackRGBA(255, 255, 0, 255), - GrColorPackRGBA(0, 0, 0, 255), - GrColorPackRGBA(128, 128, 128, 255), - GrColorPackRGBA(255, 255, 255, 255) -}; - -static const int kDrawnTileSize = 16; - -/* - * Rather than performing any rect packing, this atlaser just lays out constant-sized - * tiles in an Nx1 row - */ -static const int kAtlasTileSize = 2; - -/* - * This class aggregates the op information required for atlasing - */ -class AtlasObject final : public GrPreFlushCallbackObject { -public: - AtlasObject() : fDone(false) { } - - ~AtlasObject() override { - SkASSERT(fDone); - } - - void markAsDone() { - fDone = true; - } - - // Insert the new op in an internal singly-linked list for 'opListID' - void addOp(uint32_t opListID, AtlasedRectOp* op) { - LinkedListHeader* header = nullptr; - for (int i = 0; i < fOps.count(); ++i) { - if (opListID == fOps[i].fID) { - header = &(fOps[i]); - } - } - - if (!header) { - fOps.push({opListID, nullptr}); - header = &(fOps[fOps.count()-1]); - } - - op->setNext(header->fHead); - header->fHead = op; - } - - // For the time being we need to pre-allocate the atlas. - void setAtlasDest(sk_sp<GrTextureProxy> atlasDest) { - fAtlasDest = atlasDest; - } - - void saveRTC(sk_sp<GrRenderTargetContext> rtc) { - SkASSERT(!fRTC); - fRTC = rtc; - } - -#ifdef SK_DEBUG - void saveAtlasToDisk() { - SkBitmap readBack; - readBack.allocN32Pixels(fRTC->width(), fRTC->height()); - - bool result = fRTC->readPixels(readBack.info(), - readBack.getPixels(), readBack.rowBytes(), 0, 0); - SkASSERT(result); - save_bm(readBack, "atlas-real.png"); - } -#endif - - /* - * This callback back creates the atlas and updates the AtlasedRectOps to read from it - */ - void preFlush(GrPreFlushResourceProvider* resourceProvider, - const uint32_t* opListIDs, int numOpListIDs, - SkTArray<sk_sp<GrRenderTargetContext>>* results) override { - SkASSERT(!results->count()); - - // Until MDB is landed we will most-likely only have one opList. - SkTDArray<LinkedListHeader*> lists; - for (int i = 0; i < numOpListIDs; ++i) { - if (LinkedListHeader* list = this->getList(opListIDs[i])) { - lists.push(list); - } - } - - if (!lists.count()) { - return; // nothing to atlas - } - - // TODO: right now we have to pre-allocate the atlas bc the TextureSamplers need a - // hard GrTexture -#if 0 - GrSurfaceDesc desc; - desc.fFlags = kRenderTarget_GrSurfaceFlag; - desc.fWidth = this->numOps() * kAtlasTileSize; - desc.fHeight = kAtlasTileSize; - desc.fConfig = kRGBA_8888_GrPixelConfig; - - sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext(desc, - nullptr, - nullptr); -#else - // At this point all the GrAtlasedOp's should have lined up to read from 'atlasDest' and - // there should either be two writes to clear it or no writes. - SkASSERT(9 == fAtlasDest->getPendingReadCnt_TestOnly()); - SkASSERT(2 == fAtlasDest->getPendingWriteCnt_TestOnly() || - 0 == fAtlasDest->getPendingWriteCnt_TestOnly()); - sk_sp<GrRenderTargetContext> rtc = resourceProvider->makeRenderTargetContext( - fAtlasDest, - nullptr, nullptr); -#endif - - rtc->clear(nullptr, 0xFFFFFFFF, true); // clear the atlas - - int blocksInAtlas = 0; - for (int i = 0; i < lists.count(); ++i) { - for (AtlasedRectOp* op = lists[i]->fHead; op; op = op->next()) { - SkIRect r = SkIRect::MakeXYWH(blocksInAtlas*kAtlasTileSize, 0, - kAtlasTileSize, kAtlasTileSize); - - // For now, we avoid the resource buffer issues and just use clears -#if 1 - rtc->clear(&r, op->color(), false); -#else - std::unique_ptr<GrDrawOp> drawOp(GrNonAARectOp::Make(SkRect::Make(r), - atlasedOp->color())); - - GrPaint paint; - rtc->priv().testingOnly_addDrawOp(std::move(paint), - GrAAType::kNone, - std::move(drawOp)); -#endif - blocksInAtlas++; - - // Set the atlased Op's color to white (so we know we're not using it for - // the final draw). - op->setColor(0xFFFFFFFF); - - // Set the atlased Op's localRect to point to where it landed in the atlas - op->setLocalRect(SkRect::Make(r)); - - // TODO: we also need to set the op's GrSuperDeferredSimpleTextureEffect to point - // to the rtc's proxy! - } - - // We've updated all these ops and we certainly don't want to process them again - this->clearOpsFor(lists[i]); - } - - // Hide a ref to the RTC in AtlasData so we can check on it later - this->saveRTC(rtc); - - results->push_back(std::move(rtc)); - } - -private: - typedef struct { - uint32_t fID; - AtlasedRectOp* fHead; - } LinkedListHeader; - - LinkedListHeader* getList(uint32_t opListID) { - for (int i = 0; i < fOps.count(); ++i) { - if (opListID == fOps[i].fID) { - return &(fOps[i]); - } - } - return nullptr; - } - - void clearOpsFor(LinkedListHeader* header) { - // The AtlasedRectOps have yet to execute (and this class doesn't own them) so just - // forget about them in the laziest way possible. - header->fHead = nullptr; - header->fID = 0; // invalid opList ID - } - - // Each opList containing AtlasedRectOps gets its own internal singly-linked list - SkTDArray<LinkedListHeader> fOps; - - // The RTC used to create the atlas - sk_sp<GrRenderTargetContext> fRTC; - - // For the time being we need to pre-allocate the atlas bc the TextureSamplers require - // a GrTexture - sk_sp<GrTextureProxy> fAtlasDest; - - // Set to true when the testing harness expects this object to be no longer used - bool fDone; -}; - -// This creates an off-screen rendertarget whose ops which eventually pull from the atlas. -static sk_sp<GrTextureProxy> make_upstream_image(GrContext* context, AtlasObject* object, int start, - sk_sp<GrTextureProxy> fakeAtlas) { - - sk_sp<GrRenderTargetContext> rtc(context->makeRenderTargetContext(SkBackingFit::kApprox, - 3*kDrawnTileSize, - kDrawnTileSize, - kRGBA_8888_GrPixelConfig, - nullptr)); - - rtc->clear(nullptr, GrColorPackRGBA(255, 0, 0, 255), true); - - for (int i = 0; i < 3; ++i) { - SkRect r = SkRect::MakeXYWH(i*kDrawnTileSize, 0, kDrawnTileSize, kDrawnTileSize); - - std::unique_ptr<AtlasedRectOp> op(AtlasedRectOp::Make(r, start+i)); - - // TODO: here is the blocker for deferring creation of the atlas. The TextureSamplers - // created here currently require a hard GrTexture. - sk_sp<GrFragmentProcessor> fp = GrSimpleTextureEffect::Make(context->resourceProvider(), - fakeAtlas, - nullptr, SkMatrix::I()); - - GrPaint paint; - paint.addColorFragmentProcessor(std::move(fp)); - paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - - AtlasedRectOp* sparePtr = op.get(); - - uint32_t opListID = rtc->priv().testingOnly_addMeshDrawOp(std::move(paint), - GrAAType::kNone, - std::move(op)); - - object->addOp(opListID, sparePtr); - } - - return rtc->asTextureProxyRef(); -} - -// Enable this if you want to debug the final draws w/o having the atlasCallback create the -// atlas -#if 0 -#include "SkGrPriv.h" - -sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) { - SkBitmap bm; - bm.allocN32Pixels(18, 2, true); - bm.erase(SK_ColorRED, SkIRect::MakeXYWH(0, 0, 2, 2)); - bm.erase(SK_ColorGREEN, SkIRect::MakeXYWH(2, 0, 2, 2)); - bm.erase(SK_ColorBLUE, SkIRect::MakeXYWH(4, 0, 2, 2)); - bm.erase(SK_ColorCYAN, SkIRect::MakeXYWH(6, 0, 2, 2)); - bm.erase(SK_ColorMAGENTA, SkIRect::MakeXYWH(8, 0, 2, 2)); - bm.erase(SK_ColorYELLOW, SkIRect::MakeXYWH(10, 0, 2, 2)); - bm.erase(SK_ColorBLACK, SkIRect::MakeXYWH(12, 0, 2, 2)); - bm.erase(SK_ColorGRAY, SkIRect::MakeXYWH(14, 0, 2, 2)); - bm.erase(SK_ColorWHITE, SkIRect::MakeXYWH(16, 0, 2, 2)); - -#if 1 - save_bm(bm, "atlas-fake.png"); -#endif - - GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps()); - desc.fFlags |= kRenderTarget_GrSurfaceFlag; - - sk_sp<GrSurfaceProxy> tmp = GrSurfaceProxy::MakeDeferred(*context->caps(), - context->textureProvider(), - desc, SkBudgeted::kYes, - bm.getPixels(), bm.rowBytes()); - - return sk_ref_sp(tmp->asTextureProxy()); -} -#else -// TODO: this is unfortunate and must be removed. We want the atlas to be created later. -sk_sp<GrTextureProxy> pre_create_atlas(GrContext* context) { - GrSurfaceDesc desc; - desc.fFlags = kRenderTarget_GrSurfaceFlag; - desc.fConfig = kSkia8888_GrPixelConfig; - desc.fOrigin = kBottomLeft_GrSurfaceOrigin; - desc.fWidth = 32; - desc.fHeight = 16; - sk_sp<GrSurfaceProxy> atlasDest = GrSurfaceProxy::MakeDeferred( - context->resourceProvider(), - desc, SkBackingFit::kExact, - SkBudgeted::kYes, - GrResourceProvider::kNoPendingIO_Flag); - return sk_ref_sp(atlasDest->asTextureProxy()); -} -#endif - -static void test_color(skiatest::Reporter* reporter, const SkBitmap& bm, int x, SkColor expected) { - SkColor readback = bm.getColor(x, kDrawnTileSize/2); - REPORTER_ASSERT(reporter, expected == readback); - if (expected != readback) { - SkDebugf("Color mismatch: %x %x\n", expected, readback); - } -} - -/* - * For the atlasing test we make a DAG that looks like: - * - * RT1 with ops: 0,1,2 RT2 with ops: 3,4,5 RT3 with ops: 6,7,8 - * \ / - * \ / - * RT4 - * We then flush RT4 and expect only ops 0-5 to be atlased together. - * Each op is just a solid colored rect so both the atlas and the final image should appear as: - * R G B C M Y - * with the atlas having width = 6*kAtlasTileSize and height = kAtlasTileSize. - * - * Note: until MDB lands, the atlas will actually have width= 9*kAtlasTileSize and look like: - * R G B C M Y K Grey White - */ -DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PreFlushCallbackTest, reporter, ctxInfo) { - static const int kNumProxies = 3; - - GrContext* context = ctxInfo.grContext(); - - sk_sp<AtlasObject> object = sk_make_sp<AtlasObject>(); - - // For now (until we add a GrSuperDeferredSimpleTextureEffect), we create the final atlas - // proxy ahead of time. - sk_sp<GrTextureProxy> atlasDest = pre_create_atlas(context); - - object->setAtlasDest(atlasDest); - - context->contextPriv().addPreFlushCallbackObject(object); - - sk_sp<GrTextureProxy> proxies[kNumProxies]; - for (int i = 0; i < kNumProxies; ++i) { - proxies[i] = make_upstream_image(context, object.get(), i*3, atlasDest); - } - - static const int kFinalWidth = 6*kDrawnTileSize; - static const int kFinalHeight = kDrawnTileSize; - - sk_sp<GrRenderTargetContext> rtc(context->makeRenderTargetContext(SkBackingFit::kApprox, - kFinalWidth, - kFinalHeight, - kRGBA_8888_GrPixelConfig, - nullptr)); - - rtc->clear(nullptr, 0xFFFFFFFF, true); - - // Note that this doesn't include the third texture proxy - for (int i = 0; i < kNumProxies-1; ++i) { - SkRect r = SkRect::MakeXYWH(i*3*kDrawnTileSize, 0, 3*kDrawnTileSize, kDrawnTileSize); - - SkMatrix t = SkMatrix::MakeTrans(-i*3*kDrawnTileSize, 0); - - GrPaint paint; - sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(context->resourceProvider(), - std::move(proxies[i]), - nullptr, t)); - paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - paint.addColorFragmentProcessor(std::move(fp)); - - rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r); - } - - rtc->prepareForExternalIO(); - - SkBitmap readBack; - readBack.allocN32Pixels(kFinalWidth, kFinalHeight); - - SkDEBUGCODE(bool result =) rtc->readPixels(readBack.info(), readBack.getPixels(), - readBack.rowBytes(), 0, 0); - SkASSERT(result); - - object->markAsDone(); - -#if 0 - save_bm(readBack, "atlas-final-image.png"); - data.saveAtlasToDisk(); -#endif - - int x = kDrawnTileSize/2; - test_color(reporter, readBack, x, SK_ColorRED); - x += kDrawnTileSize; - test_color(reporter, readBack, x, SK_ColorGREEN); - x += kDrawnTileSize; - test_color(reporter, readBack, x, SK_ColorBLUE); - x += kDrawnTileSize; - test_color(reporter, readBack, x, SK_ColorCYAN); - x += kDrawnTileSize; - test_color(reporter, readBack, x, SK_ColorMAGENTA); - x += kDrawnTileSize; - test_color(reporter, readBack, x, SK_ColorYELLOW); -} - -#endif |