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
diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h
index ec1b0ba..b7a6d17 100644
--- a/include/gpu/GrEffect.h
+++ b/include/gpu/GrEffect.h
@@ -10,16 +10,14 @@
#include "GrColor.h"
#include "GrEffectUnitTest.h"
-#include "GrTexture.h"
+#include "GrProgramElement.h"
#include "GrTextureAccess.h"
#include "GrTypesPriv.h"
class GrBackendEffectFactory;
class GrContext;
class GrCoordTransform;
-class GrEffect;
-class GrVertexEffect;
-class SkString;
+
/** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
Ganesh shading pipeline.
@@ -31,7 +29,7 @@
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.
*/
-class GrEffect : public SkRefCnt {
+class GrEffect : public GrProgramElement {
public:
SK_DECLARE_INST_COUNT(GrEffect)
@@ -205,7 +203,7 @@
bool fWillUseInputColor;
bool fRequiresVertexShader;
- typedef SkRefCnt INHERITED;
+ typedef GrProgramElement INHERITED;
};
/**
@@ -217,5 +215,4 @@
static GrEffect* NAME SkNEW_PLACEMENT_ARGS(g_##NAME##_Storage.get(), EFFECT_CLASS, ARGS); \
static SkAutoTDestroy<GrEffect> NAME##_ad(NAME);
-
#endif
diff --git a/include/gpu/GrGpuResource.h b/include/gpu/GrGpuResource.h
index f18f5c5..189237a 100644
--- a/include/gpu/GrGpuResource.h
+++ b/include/gpu/GrGpuResource.h
@@ -110,7 +110,7 @@
mutable int32_t fPendingWrites;
// These functions need access to the pending read/write member functions.
- friend class GrDrawState;
+ friend class GrRODrawState;
friend class GrProgramResource;
};
diff --git a/include/gpu/GrProgramElement.h b/include/gpu/GrProgramElement.h
new file mode 100644
index 0000000..67135a3
--- /dev/null
+++ b/include/gpu/GrProgramElement.h
@@ -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
diff --git a/include/gpu/GrProgramElementRef.h b/include/gpu/GrProgramElementRef.h
new file mode 100644
index 0000000..ea11f44
--- /dev/null
+++ b/include/gpu/GrProgramElementRef.h
@@ -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
diff --git a/include/gpu/GrProgramResource.h b/include/gpu/GrProgramResource.h
new file mode 100644
index 0000000..277ae9d
--- /dev/null
+++ b/include/gpu/GrProgramResource.h
@@ -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