blob: 62b3ed3c98e067e40b1ae58fa0f36b2fbfc13c39 [file] [log] [blame]
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrDrawingManager_DEFINED
#define GrDrawingManager_DEFINED
#include "include/core/SkSurface.h"
#include "include/private/SkTArray.h"
#include "include/private/SkTHash.h"
#include "src/gpu/GrBufferAllocPool.h"
#include "src/gpu/GrDeferredUpload.h"
#include "src/gpu/GrHashMapWithCache.h"
#include "src/gpu/GrPathRenderer.h"
#include "src/gpu/GrPathRendererChain.h"
#include "src/gpu/GrResourceCache.h"
#include "src/gpu/GrSurfaceProxy.h"
// Enabling this will print out which path renderers are being chosen
#define GR_PATH_RENDERER_SPEW 0
class GrCoverageCountingPathRenderer;
class GrGpuBuffer;
class GrOnFlushCallbackObject;
class GrOpFlushState;
class GrOpsTask;
class GrRecordingContext;
class GrRenderTargetContext;
class GrRenderTargetProxy;
class GrRenderTask;
class GrSemaphore;
class GrSoftwarePathRenderer;
class GrSurfaceContext;
class GrSurfaceProxyView;
class GrTextureResolveRenderTask;
class SkDeferredDisplayList;
class GrDrawingManager {
public:
~GrDrawingManager();
void freeGpuResources();
// A managed opsTask is controlled by the drawing manager (i.e., sorted & flushed with the
// others). An unmanaged one is created and used by the onFlushCallback.
sk_sp<GrOpsTask> newOpsTask(GrSurfaceProxyView, bool managedOpsTask);
// Create a render task that can resolve MSAA and/or regenerate mipmap levels on proxies. This
// method will only add the new render task to the list. It is up to the caller to call
// addProxy() on the returned object.
GrTextureResolveRenderTask* newTextureResolveRenderTask(const GrCaps&);
// Create a new render task that will cause the gpu to wait on semaphores before executing any
// more RenderTasks that target proxy. It is possible for this wait to also block additional
// work (even to other proxies) that has already been recorded or will be recorded later. The
// only guarantee is that future work to the passed in proxy will wait on the semaphores to be
// signaled.
void newWaitRenderTask(sk_sp<GrSurfaceProxy> proxy,
std::unique_ptr<std::unique_ptr<GrSemaphore>[]>,
int numSemaphores);
// Create a new render task which copies the pixels from the srcProxy into the dstBuffer. This
// is used to support the asynchronous readback API. The srcRect is the region of the srcProxy
// to be copied. The surfaceColorType says how we should interpret the data when reading back
// from the source. DstColorType describes how the data should be stored in the dstBuffer.
// DstOffset is the offset into the dstBuffer where we will start writing data.
void newTransferFromRenderTask(sk_sp<GrSurfaceProxy> srcProxy, const SkIRect& srcRect,
GrColorType surfaceColorType, GrColorType dstColorType,
sk_sp<GrGpuBuffer> dstBuffer, size_t dstOffset);
// Creates a new render task which copies a pixel rectangle from srcView into dstView. The src
// pixels copied are specified by srcRect. They are copied to a rect of the same size in
// dstProxy with top left at dstPoint. If the src rect is clipped by the src bounds then pixel
// values in the dst rect corresponding to the area clipped by the src rect are not overwritten.
// This method is not guaranteed to succeed depending on the type of surface, formats, etc, and
// the backend-specific limitations.
bool newCopyRenderTask(GrSurfaceProxyView srcView, const SkIRect& srcRect,
GrSurfaceProxyView dstView, const SkIPoint& dstPoint);
GrRecordingContext* getContext() { return fContext; }
GrPathRenderer* getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args,
bool allowSW,
GrPathRendererChain::DrawType drawType,
GrPathRenderer::StencilSupport* stencilSupport = nullptr);
GrPathRenderer* getSoftwarePathRenderer();
// Returns a direct pointer to the coverage counting path renderer, or null if it is not
// supported and turned on.
GrCoverageCountingPathRenderer* getCoverageCountingPathRenderer();
void flushIfNecessary();
static bool ProgramUnitTest(GrContext* context, int maxStages, int maxLevels);
GrSemaphoresSubmitted flushSurfaces(GrSurfaceProxy* proxies[],
int cnt,
SkSurface::BackendSurfaceAccess access,
const GrFlushInfo& info,
const GrBackendSurfaceMutableState* newState);
GrSemaphoresSubmitted flushSurface(GrSurfaceProxy* proxy,
SkSurface::BackendSurfaceAccess access,
const GrFlushInfo& info,
const GrBackendSurfaceMutableState* newState) {
return this->flushSurfaces(&proxy, 1, access, info, newState);
}
void addOnFlushCallbackObject(GrOnFlushCallbackObject*);
#if GR_TEST_UTILS
void testingOnly_removeOnFlushCallbackObject(GrOnFlushCallbackObject*);
#endif
GrRenderTask* getLastRenderTask(const GrSurfaceProxy*) const;
GrOpsTask* getLastOpsTask(const GrSurfaceProxy*) const;
void setLastRenderTask(const GrSurfaceProxy*, GrRenderTask*);
void moveRenderTasksToDDL(SkDeferredDisplayList* ddl);
void copyRenderTasksFromDDL(sk_sp<const SkDeferredDisplayList>, GrRenderTargetProxy* newDest);
private:
// This class encapsulates maintenance and manipulation of the drawing manager's DAG of
// renderTasks.
class RenderTaskDAG {
public:
RenderTaskDAG(bool sortRenderTasks);
~RenderTaskDAG();
// Currently, when explicitly allocating resources, this call will topologically sort the
// GrRenderTasks.
// MDB TODO: remove once incremental GrRenderTask sorting is enabled
void prepForFlush();
void closeAll(const GrCaps* caps);
void gatherIDs(SkSTArray<8, uint32_t, true>* idArray) const;
void reset();
// This call forceably removes GrRenderTasks from the DAG. It is problematic bc it
// just removes the GrRenderTasks but doesn't cleanup any referring pointers (i.e.
// dependency pointers in the DAG). It works right now bc it is only called after the
// topological sort is complete (so the dangling pointers aren't used).
void rawRemoveRenderTasks(int startIndex, int stopIndex);
bool empty() const { return fRenderTasks.empty(); }
int numRenderTasks() const { return fRenderTasks.count(); }
bool isUsed(GrSurfaceProxy*) const;
GrRenderTask* renderTask(int index) { return fRenderTasks[index].get(); }
const GrRenderTask* renderTask(int index) const { return fRenderTasks[index].get(); }
GrRenderTask* back() { return fRenderTasks.back().get(); }
const GrRenderTask* back() const { return fRenderTasks.back().get(); }
GrRenderTask* add(sk_sp<GrRenderTask>);
GrRenderTask* addBeforeLast(sk_sp<GrRenderTask>);
void add(const SkTArray<sk_sp<GrRenderTask>>&);
void swap(SkTArray<sk_sp<GrRenderTask>>* renderTasks);
bool sortingRenderTasks() const { return fSortRenderTasks; }
private:
SkTArray<sk_sp<GrRenderTask>> fRenderTasks;
bool fSortRenderTasks;
};
GrDrawingManager(GrRecordingContext*,
const GrPathRendererChain::Options&,
bool sortRenderTasks,
bool reduceOpsTaskSplitting);
bool wasAbandoned() const;
// Closes the target's dependent render tasks (or, if not in sorting/opsTask-splitting-reduction
// mode, closes fActiveOpsTask) in preparation for us opening a new opsTask that will write to
// 'target'.
void closeRenderTasksForNewRenderTask(GrSurfaceProxy* target);
// return true if any GrRenderTasks were actually executed; false otherwise
bool executeRenderTasks(int startIndex, int stopIndex, GrOpFlushState*,
int* numRenderTasksExecuted);
void removeRenderTasks(int startIndex, int stopIndex);
bool flush(GrSurfaceProxy* proxies[],
int numProxies,
SkSurface::BackendSurfaceAccess access,
const GrFlushInfo&,
const GrBackendSurfaceMutableState* newState);
bool submitToGpu(bool syncToCpu);
SkDEBUGCODE(void validate() const);
friend class GrContext; // access to: flush & cleanup
friend class GrContextPriv; // access to: flush
friend class GrOnFlushResourceProvider; // this is just a shallow wrapper around this class
friend class GrRecordingContext; // access to: ctor
friend class SkImage; // for access to: flush
static const int kNumPixelGeometries = 5; // The different pixel geometries
static const int kNumDFTOptions = 2; // DFT or no DFT
GrRecordingContext* fContext;
GrPathRendererChain::Options fOptionsForPathRendererChain;
// This cache is used by both the vertex and index pools. It reuses memory across multiple
// flushes.
sk_sp<GrBufferAllocPool::CpuBufferCache> fCpuBufferCache;
RenderTaskDAG fDAG;
GrOpsTask* fActiveOpsTask = nullptr;
// These are the IDs of the opsTask currently being flushed (in internalFlush)
SkSTArray<8, uint32_t, true> fFlushingRenderTaskIDs;
// These are the new renderTasks generated by the onFlush CBs
SkSTArray<4, sk_sp<GrRenderTask>> fOnFlushRenderTasks;
std::unique_ptr<GrPathRendererChain> fPathRendererChain;
sk_sp<GrSoftwarePathRenderer> fSoftwarePathRenderer;
GrTokenTracker fTokenTracker;
bool fFlushing;
bool fReduceOpsTaskSplitting;
SkTArray<GrOnFlushCallbackObject*> fOnFlushCBObjects;
void addDDLTarget(GrSurfaceProxy* newTarget, GrRenderTargetProxy* ddlTarget) {
fDDLTargets.set(newTarget->uniqueID().asUInt(), ddlTarget);
}
bool isDDLTarget(GrSurfaceProxy* newTarget) {
return SkToBool(fDDLTargets.find(newTarget->uniqueID().asUInt()));
}
GrRenderTargetProxy* getDDLTarget(GrSurfaceProxy* newTarget) {
auto entry = fDDLTargets.find(newTarget->uniqueID().asUInt());
return entry ? *entry : nullptr;
}
void clearDDLTargets() { fDDLTargets.reset(); }
// We play a trick with lazy proxies to retarget the base target of a DDL to the SkSurface
// it is replayed on. 'fDDLTargets' stores this mapping from SkSurface unique proxy ID
// to the DDL's lazy proxy.
// Note: we do not expect a whole lot of these per flush
SkTHashMap<uint32_t, GrRenderTargetProxy*> fDDLTargets;
struct SurfaceIDKeyTraits {
static uint32_t GetInvalidKey() {
return GrSurfaceProxy::UniqueID::InvalidID().asUInt();
}
};
GrHashMapWithCache<uint32_t, GrRenderTask*, SurfaceIDKeyTraits, GrCheapHash> fLastRenderTasks;
};
#endif