Add GrProgramElement base class for GrEffect with deferred exec ref.

BUG=skia:2889
R=robertphillips@google.com

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/537773004
This commit is contained in:
bsalomon 2014-09-04 13:12:37 -07:00 committed by Commit bot
parent 8f2e791baa
commit 95740981c3
8 changed files with 389 additions and 8 deletions

View File

@ -24,6 +24,9 @@
'<(skia_include_path)/gpu/GrGpuResource.h', '<(skia_include_path)/gpu/GrGpuResource.h',
'<(skia_include_path)/gpu/GrPaint.h', '<(skia_include_path)/gpu/GrPaint.h',
'<(skia_include_path)/gpu/GrPathRendererChain.h', '<(skia_include_path)/gpu/GrPathRendererChain.h',
'<(skia_include_path)/gpu/GrProgramElement.h',
'<(skia_include_path)/gpu/GrProgramElementRef.h',
'<(skia_include_path)/gpu/GrProgramResource.h',
'<(skia_include_path)/gpu/GrRect.h', '<(skia_include_path)/gpu/GrRect.h',
'<(skia_include_path)/gpu/GrRenderTarget.h', '<(skia_include_path)/gpu/GrRenderTarget.h',
'<(skia_include_path)/gpu/GrResourceKey.h', '<(skia_include_path)/gpu/GrResourceKey.h',
@ -104,6 +107,8 @@
'<(skia_src_path)/gpu/GrPathRendering.h', '<(skia_src_path)/gpu/GrPathRendering.h',
'<(skia_src_path)/gpu/GrPathUtils.cpp', '<(skia_src_path)/gpu/GrPathUtils.cpp',
'<(skia_src_path)/gpu/GrPathUtils.h', '<(skia_src_path)/gpu/GrPathUtils.h',
'<(skia_src_path)/gpu/GrProgramElement.cpp',
'<(skia_src_path)/gpu/GrProgramResource.cpp',
'<(skia_src_path)/gpu/GrPictureUtils.h', '<(skia_src_path)/gpu/GrPictureUtils.h',
'<(skia_src_path)/gpu/GrPictureUtils.cpp', '<(skia_src_path)/gpu/GrPictureUtils.cpp',
'<(skia_src_path)/gpu/GrPlotMgr.h', '<(skia_src_path)/gpu/GrPlotMgr.h',

View File

@ -10,16 +10,14 @@
#include "GrColor.h" #include "GrColor.h"
#include "GrEffectUnitTest.h" #include "GrEffectUnitTest.h"
#include "GrTexture.h" #include "GrProgramElement.h"
#include "GrTextureAccess.h" #include "GrTextureAccess.h"
#include "GrTypesPriv.h" #include "GrTypesPriv.h"
class GrBackendEffectFactory; class GrBackendEffectFactory;
class GrContext; class GrContext;
class GrCoordTransform; class GrCoordTransform;
class GrEffect;
class GrVertexEffect;
class SkString;
/** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the /** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
Ganesh shading pipeline. Ganesh shading pipeline.
@ -31,7 +29,7 @@ class SkString;
effect must reach 0 before the thread terminates and the pool is destroyed. To create a static effect must reach 0 before the thread terminates and the pool is destroyed. To create a static
effect use the macro GR_CREATE_STATIC_EFFECT declared below. effect use the macro GR_CREATE_STATIC_EFFECT declared below.
*/ */
class GrEffect : public SkRefCnt { class GrEffect : public GrProgramElement {
public: public:
SK_DECLARE_INST_COUNT(GrEffect) SK_DECLARE_INST_COUNT(GrEffect)
@ -205,7 +203,7 @@ private:
bool fWillUseInputColor; bool fWillUseInputColor;
bool fRequiresVertexShader; bool fRequiresVertexShader;
typedef SkRefCnt INHERITED; typedef GrProgramElement INHERITED;
}; };
/** /**
@ -217,5 +215,4 @@ static SkAlignedSStorage<sizeof(EFFECT_CLASS)> g_##NAME##_Storage;
static GrEffect* NAME SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS); \ static GrEffect* NAME SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS); \
static SkAutoTDestroy<GrEffect> NAME##_ad(NAME); static SkAutoTDestroy<GrEffect> NAME##_ad(NAME);
#endif #endif

View File

@ -110,7 +110,7 @@ private:
mutable int32_t fPendingWrites; mutable int32_t fPendingWrites;
// These functions need access to the pending read/write member functions. // These functions need access to the pending read/write member functions.
friend class GrDrawState; friend class GrRODrawState;
friend class GrProgramResource; friend class GrProgramResource;
}; };

View File

@ -0,0 +1,94 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrProgramElement_DEFINED
#define GrProgramElement_DEFINED
#include "SkRefCnt.h"
#include "SkTArray.h"
class GrProgramResource;
/**
* Base class for GrEffect (and future GrGeometryProcessor). GrDrawState uses this to manage
* transitioning a GrEffect from being owned by a client to being scheduled for execution. It
* converts resources owned by the effect from being ref'ed to having pending reads/writes.
*
* All GrGpuResource objects owned by a GrProgramElement or derived classes (either directly or
* indirectly) must be wrapped in a GrProgramResource and registered with the GrProgramElement using
* addGrProgramResource(). This allows the regular refs to be converted to pending IO events
* when the program element is scheduled for deferred execution.
*/
class GrProgramElement : public SkNoncopyable {
public:
SK_DECLARE_INST_COUNT_ROOT(GrProgramElement)
virtual ~GrProgramElement() {
// fRefCnt can be one when an effect is created statically using GR_CREATE_STATIC_EFFECT
SkASSERT((0 == fRefCnt || 1 == fRefCnt) && 0 == fPendingExecutions);
// Set to invalid values.
SkDEBUGCODE(fRefCnt = fPendingExecutions = -10;)
}
void ref() const {
// Once the ref cnt reaches zero it should never be ref'ed again.
SkASSERT(fRefCnt > 0);
this->validate();
++fRefCnt;
}
void unref() const {
this->validate();
--fRefCnt;
if (0 == fRefCnt && 0 == fPendingExecutions) {
SkDELETE(this);
}
}
void validate() const {
#ifdef SK_DEBUG
SkASSERT(fRefCnt >= 0);
SkASSERT(fPendingExecutions >= 0);
SkASSERT(fRefCnt + fPendingExecutions > 0);
#endif
}
protected:
GrProgramElement() : fRefCnt(1), fPendingExecutions(0) {}
/** Subclasses registers their resources using this function. It is assumed the GrProgramResouce
is and will remain owned by the subclass and this function will retain a raw ptr. Once a
GrProgramResource is registered its setResource must not be called.
*/
void addProgramResource(const GrProgramResource* res) {
fProgramResources.push_back(res);
}
private:
void convertRefToPendingExecution() const;
void completedExecution() const {
this->validate();
--fPendingExecutions;
if (0 == fRefCnt && 0 == fPendingExecutions) {
SkDELETE(this);
}
}
mutable int32_t fRefCnt;
// Count of deferred executions not yet issued to the 3D API.
mutable int32_t fPendingExecutions;
SkSTArray<4, const GrProgramResource*, true> fProgramResources;
// Only this class can access convertRefToPendingExecution() and completedExecution().
template <typename T> friend class GrProgramElementRef;
typedef SkNoncopyable INHERITED;
};
#endif

View File

@ -0,0 +1,73 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrProgramElementRef_DEFINED
#define GrProgramElementRef_DEFINED
#include "SkRefCnt.h"
#include "GrTypes.h"
/**
* Helper for owning a GrProgramElement subclass and being able to convert a ref to pending
* execution. It is like an SkAutoTUnref for program elements whose execution can be deferred. Once
* in the pending execution state it is illegal to change the object that is owned by the
* GrProgramElementRef. Its destructor will either unref the GrProgramElement or signal that
* the pending execution has completed, depending on whether convertToPendingExec() was called.
*/
template <typename T> class GrProgramElementRef : SkNoncopyable {
public:
GrProgramElementRef() : fOwnPendingExec(false), fObj(NULL) {};
// Adopts a ref from the caller.
explicit GrProgramElementRef(T* obj) : fOwnPendingExec(false), fObj(obj) {}
// Adopts a ref from the caller. Do not call after convertToPendingExec.
void reset(T* obj) {
SkASSERT(!fOwnPendingExec);
SkSafeUnref(fObj);
fObj = obj;
}
void convertToPendingExec() {
SkASSERT(!fOwnPendingExec);
fObj->convertRefToPendingExecution();
fOwnPendingExec = true;
}
T* get() const { return fObj; }
operator T*() { return fObj; }
/** If T is const, the type returned from operator-> will also be const. */
typedef typename SkTConstType<typename SkAutoTUnref<T>::BlockRef<T>,
SkTIsConst<T>::value>::type BlockRefType;
/**
* GrProgramElementRef assumes ownership of the ref and manages converting the ref to a
* pending execution. As a result, it is an error for the user to ref or unref through
* GrProgramElementRef. Therefore operator-> returns BlockRef<T>*.
*/
BlockRefType *operator->() const {
return static_cast<BlockRefType*>(fObj);
}
~GrProgramElementRef() {
if (NULL != fObj) {
if (fOwnPendingExec) {
fObj->completedExecution();
} else {
fObj->unref();
}
}
}
private:
bool fOwnPendingExec;
T* fObj;
typedef SkNoncopyable INHERITED;
};
#endif

View File

@ -0,0 +1,73 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrProgramResource_DEFINED
#define GrProgramResource_DEFINED
#include "SkRefCnt.h"
class GrGpuResource;
/**
* Class that wraps a resource referenced by a GrProgramElement or GrDrawState. It manages
* converting refs to pending io operations. Like SkAutoTUnref, its constructor and setter adopt
* a ref from their caller. This class is intended only for internal use in core Gr code.
*/
class GrProgramResource : SkNoncopyable {
public:
enum IOType {
kRead_IOType,
kWrite_IOType,
kRW_IOType,
kNone_IOType, // For internal use only, don't specify to constructor or setResource().
};
SK_DECLARE_INST_COUNT_ROOT(GrProgramResource);
GrProgramResource();
/** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
pending on the resource when markPendingIO is called. */
explicit GrProgramResource(GrGpuResource*, IOType ioType);
~GrProgramResource();
GrGpuResource* getResource() const { return fResource; }
/** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
pending on the resource when markPendingIO is called. */
void setResource(GrGpuResource*, IOType ioType);
/** Does this object own a pending read or write on the resource it is wrapping. */
bool ownsPendingIO() const { return fPendingIO; }
/** Shortcut for calling setResource() with NULL. It cannot be called after markingPendingIO
is called. */
void reset();
private:
/** Called by owning GrProgramElement when the program element is first scheduled for
execution. */
void markPendingIO() const;
/** Called when the program element/draw state is no longer owned by GrDrawTarget-client code.
This lets the cache know that the drawing code will no longer schedule additional reads or
writes to the resource using the program element or draw state. */
void removeRef() const;
friend class GrDrawState;
friend class GrProgramElement;
GrGpuResource* fResource;
mutable bool fOwnRef;
mutable bool fPendingIO;
IOType fIOType;
typedef SkNoncopyable INHERITED;
};
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrProgramElement.h"
#include "GrProgramResource.h"
void GrProgramElement::convertRefToPendingExecution() const {
// This function makes it so that all the GrProgramResources own a single ref to their
// underlying GrGpuResource if there are any refs to the GrProgramElement and a single
// pending read/write if there are any pending executions of the GrProgramElement. The
// GrProgramResource will give up its single ref and/or pending read/write in its destructor.
SkASSERT(fRefCnt > 0);
if (0 == fPendingExecutions) {
for (int i = 0; i < fProgramResources.count(); ++i) {
fProgramResources[i]->markPendingIO();
}
}
++fPendingExecutions;
this->unref();
if (0 == fRefCnt) {
for (int i = 0; i < fProgramResources.count(); ++i) {
fProgramResources[i]->removeRef();
}
}
}

View File

@ -0,0 +1,109 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrProgramResource.h"
#include "GrGpuResource.h"
GrProgramResource::GrProgramResource() {
fResource = NULL;
fOwnRef = false;
fPendingIO = false;
fIOType = kNone_IOType;
}
GrProgramResource::GrProgramResource(GrGpuResource* resource, IOType ioType) {
fResource = NULL;
fOwnRef = false;
fPendingIO = false;
this->setResource(resource, ioType);
}
GrProgramResource::~GrProgramResource() {
if (fOwnRef) {
SkASSERT(NULL != fResource);
fResource->unref();
}
if (fPendingIO) {
switch (fIOType) {
case kNone_IOType:
SkFAIL("Shouldn't get here if fIOType is kNone.");
break;
case kRead_IOType:
fResource->completedRead();
break;
case kWrite_IOType:
fResource->completedWrite();
break;
case kRW_IOType:
fResource->completedRead();
fResource->completedWrite();
break;
}
}
}
void GrProgramResource::reset() {
SkASSERT(!fPendingIO);
SkASSERT((NULL != fResource) == fOwnRef);
if (fOwnRef) {
fResource->unref();
fOwnRef = false;
fResource = NULL;
fIOType = kNone_IOType;
}
}
void GrProgramResource::setResource(GrGpuResource* resource, IOType ioType) {
SkASSERT(!fPendingIO);
SkASSERT((NULL != fResource) == fOwnRef);
SkSafeUnref(fResource);
if (NULL == resource) {
fResource = NULL;
fOwnRef = false;
fIOType = kNone_IOType;
} else {
SkASSERT(kNone_IOType != ioType);
fResource = resource;
fOwnRef = true;
fIOType = ioType;
}
}
void GrProgramResource::markPendingIO() const {
// This should only be called once, when the owning GrProgramElement gets its first
// pendingExecution ref.
SkASSERT(!fPendingIO);
SkASSERT(NULL != fResource);
fPendingIO = true;
switch (fIOType) {
case kNone_IOType:
SkFAIL("GrProgramResource with neither reads nor writes?");
break;
case kRead_IOType:
fResource->addPendingRead();
break;
case kWrite_IOType:
fResource->addPendingWrite();
break;
case kRW_IOType:
fResource->addPendingRead();
fResource->addPendingWrite();
break;
}
}
void GrProgramResource::removeRef() const {
// This should only be called once, when the owners last ref goes away and
// there is a pending execution.
SkASSERT(fOwnRef);
SkASSERT(fPendingIO);
SkASSERT(kNone_IOType != fIOType);
SkASSERT(NULL != fResource);
fResource->unref();
fOwnRef = false;
}