blob: 7ef12f7fd2b839a9862a7d0262ff681f89e47a2c [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrCommandBufferRef_DEFINED
#define GrCommandBufferRef_DEFINED
#include "include/core/SkRefCnt.h"
/** Check if the argument is non-null, and if so, call obj->addCommandBufferUsage() and return obj.
*/
template <typename T> static inline T* GrSafeRefCBUsage(T* obj) {
if (obj) {
obj->addCommandBufferUsage();
}
return obj;
}
/** Check if the argument is non-null, and if so, call obj->removeCommandBufferUsage()
*/
template <typename T> static inline void GrSafeUnrefCBUsage(T* obj) {
if (obj) {
obj->removeCommandBufferUsage();
}
}
/**
* Shared pointer class to wrap classes that support a addCommandBufferUsage() and
* removeCommandBufferUsage() interface.
*
* This class supports copying, moving, and assigning an sk_sp into it. In general these commands do
* not modify the sk_sp at all but just call addCommandBufferUsage() on the underlying object.
*
* This class is designed to be used by GrGpuResources that need to track when they are in use on
* gpu (usually via a command buffer) separately from tracking if there are any current logical
* usages in Ganesh. This allows for a scratch GrGpuResource to be reused for new draw calls even
* if it is in use on the GPU.
*/
template <typename T> class gr_cb {
public:
using element_type = T;
constexpr gr_cb() : fPtr(nullptr) {}
constexpr gr_cb(std::nullptr_t) : fPtr(nullptr) {}
/**
* Shares the underlying object by calling addCommandBufferUsage(), so that both the argument
* and the newly created gr_cb both have a reference to it.
*/
gr_cb(const gr_cb<T>& that) : fPtr(GrSafeRefCBUsage(that.get())) {}
gr_cb(const sk_sp<T>& that) : fPtr(GrSafeRefCBUsage(that.get())) {}
/**
* Move the underlying object from the argument to the newly created gr_cb. Afterwards only
* the new gr_cb will have a reference to the object, and the argument will point to null.
* No call to addCommandBufferUsage() or removeCommandBufferUsage() will be made.
*/
gr_cb(gr_cb<T>&& that) : fPtr(that.release()) {}
/**
* Copies the underlying object pointer from the argument to the gr_cb. It will then call
* addCommandBufferUsage() on the new object.
*/
gr_cb(sk_sp<T>&& that) : fPtr(GrSafeRefCBUsage(that.get())) {}
/**
* Calls removeCommandBufferUsage() on the underlying object pointer.
*/
~gr_cb() {
GrSafeUnrefCBUsage(fPtr);
SkDEBUGCODE(fPtr = nullptr);
}
gr_cb<T>& operator=(std::nullptr_t) {
this->reset();
return *this;
}
/**
* Shares the underlying object referenced by the argument by calling addCommandBufferUsage() on
* it. If this gr_cb previously had a reference to an object (i.e. not null) it will call
* removeCommandBufferUsage() on thatobject.
*/
gr_cb<T>& operator=(const gr_cb<T>& that) {
if (this != &that) {
this->reset(GrSafeRefCBUsage(that.get()));
}
return *this;
}
/**
* Copies the underlying object pointer from the argument to the gr_cb. If the gr_cb previously
* held a reference to another object, removeCommandBufferUsage() will be called on that object.
* It will then call addCommandBufferUsage() on the new object.
*/
gr_cb<T>& operator=(const sk_sp<T>& that) {
this->reset(GrSafeRefCBUsage(that.get()));
return *this;
}
/**
* Move the underlying object from the argument to the gr_cb. If the gr_cb previously held
* a reference to another object, removeCommandBufferUsage() will be called on that object. No
* call to addCommandBufferUsage() will be made.
*/
gr_cb<T>& operator=(gr_cb<T>&& that) {
this->reset(that.release());
return *this;
}
/**
* Copies the underlying object pointer from the argument to the gr_cb. If the gr_cb previously
* held a reference to another object, removeCommandBufferUsage() will be called on that object.
* It will then call addCommandBufferUsage() on the new object.
*/
gr_cb<T>& operator=(sk_sp<T>&& that) {
this->reset(GrSafeRefCBUsage(that.get()));
return *this;
}
T& operator*() const {
SkASSERT(this->get() != nullptr);
return *this->get();
}
explicit operator bool() const { return this->get() != nullptr; }
T* get() const { return fPtr; }
T* operator->() const { return fPtr; }
private:
/**
* Adopt the new bare pointer, and call removeCommandBufferUsage() on any previously held object
* (if not null). No call to addCommandBufferUsage() will be made.
*/
void reset(T* ptr = nullptr) {
T* oldPtr = fPtr;
fPtr = ptr;
GrSafeUnrefCBUsage(oldPtr);
}
/**
* Return the bare pointer, and set the internal object pointer to nullptr.
* The caller must assume ownership of the object, and manage its reference count directly.
* No call to removeCommandBufferUsage() will be made.
*/
T* SK_WARN_UNUSED_RESULT release() {
T* ptr = fPtr;
fPtr = nullptr;
return ptr;
}
T* fPtr;
};
template <typename T, typename U> inline bool operator==(const gr_cb<T>& a, const gr_cb<U>& b) {
return a.get() == b.get();
}
template <typename T> inline bool operator==(const gr_cb<T>& a, std::nullptr_t) /*noexcept*/ {
return !a;
}
template <typename T> inline bool operator==(std::nullptr_t, const gr_cb<T>& b) /*noexcept*/ {
return !b;
}
template <typename T, typename U> inline bool operator!=(const gr_cb<T>& a, const gr_cb<U>& b) {
return a.get() != b.get();
}
template <typename T> inline bool operator!=(const gr_cb<T>& a, std::nullptr_t) /*noexcept*/ {
return static_cast<bool>(a);
}
template <typename T> inline bool operator!=(std::nullptr_t, const gr_cb<T>& b) /*noexcept*/ {
return static_cast<bool>(b);
}
#endif