aboutsummaryrefslogtreecommitdiffhomepage
path: root/include/gpu/GrProgramElementRef.h
blob: ecc802317b8170cb2ef4e140e24cc075c6eae2d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
 * 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;
    }

    // In the short term we need to support copying a GrProcessorStage and making the copy own
    // the same type of ref as the source. This function exists to support this. TODO: Once
    // GrDrawState and GrOptDrawState no longer share a base class they won't have to share
    // GrProcessorStage and we can have GrOptDrawState always own pending executions rather than
    // refs on GrProgramElements. At that point we should be able to delete this function.
    // This function makes assumptions that are valid in the GrProcessorStage use case and should
    // not be used elsewhere.
    void initAndRef(const GrProgramElementRef& that) {
        SkASSERT(!fObj);
        SkASSERT(that.fObj);
        if (that.fOwnPendingExec) {
            SkASSERT(that.fObj->fPendingExecutions > 0);
            that.fObj->fPendingExecutions++;
        } else {
            that.fObj->ref();
        }
        this->fOwnPendingExec = that.fOwnPendingExec;
        this->fObj = that.fObj;
    }

    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>::template 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 (fObj) {
            if (fOwnPendingExec) {
                fObj->completedExecution();
            } else {
                fObj->unref();
            }
        }
    }

private:
    bool fOwnPendingExec;
    T*   fObj;

    typedef SkNoncopyable INHERITED;
};
#endif