blob: af8161d163ecf94b0f1f5f638977f88625dbcc9c [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPrepareCallback_DEFINED
#define GrPrepareCallback_DEFINED
#include "SkAutoPixmapStorage.h"
#include "SkRefCnt.h"
#include "SkSemaphore.h"
#include "GrOpFlushState.h"
class GrTextureProxy;
/**
* An instance of any class derived from GrPrepareCallback can be passed to
* GrOpList::addPrepareCallback. At flush time, all callbacks (on op lists being flushed) will be
* invoked (via operator()). Note that the callback receives the GrOpFlushState, so it can trigger
* ASAP uploads (similar to an Op's onPrepare).
*
* All callbacks are invoked at the beginning of flush, before prepare is called.
*/
class GrPrepareCallback : SkNoncopyable {
public:
virtual ~GrPrepareCallback() {}
virtual void operator()(GrOpFlushState*) = 0;
};
/**
* GrMaskUploaderPrepareCallback assists with threaded generation of mask textures. Currently used
* by both software clip masks, and the software path renderer. The calling code typically needs
* to store some additional data (T) for use on the worker thread. That payload is accessed by the
* worker thread to populate the mask in fPixels (using GrSWMaskHelper). This callback's operator()
* handles scheduling the texture upload at flush time.
*/
template <typename T>
class GrMaskUploaderPrepareCallback : public GrPrepareCallback {
public:
template <typename... Args>
GrMaskUploaderPrepareCallback(sk_sp<GrTextureProxy> proxy, Args&&... args)
: fProxy(std::move(proxy))
, fWaited(false)
, fData(std::forward<Args>(args)...) {}
~GrMaskUploaderPrepareCallback() override {
if (!fWaited) {
// This can happen if our owning op list fails to instantiate (so it never prepares)
fPixelsReady.wait();
}
}
void operator()(GrOpFlushState* flushState) override {
auto uploadMask = [this](GrDrawOp::WritePixelsFn& writePixelsFn) {
this->fPixelsReady.wait();
this->fWaited = true;
// If the worker thread was unable to allocate pixels, this check will fail, and we'll
// end up drawing with an uninitialized mask texture, but at least we won't crash.
if (this->fPixels.addr()) {
writePixelsFn(this->fProxy.get(), 0, 0,
this->fPixels.width(), this->fPixels.height(),
kAlpha_8_GrPixelConfig,
this->fPixels.addr(), this->fPixels.rowBytes());
// Free this memory immediately, so it can be recycled. This avoids memory pressure
// when there is a large amount of threaded work still running during flush.
this->fPixels.reset();
}
};
flushState->addASAPUpload(std::move(uploadMask));
}
SkAutoPixmapStorage* getPixels() { return &fPixels; }
SkSemaphore* getSemaphore() { return &fPixelsReady; }
T& data() { return fData; }
private:
sk_sp<GrTextureProxy> fProxy;
SkAutoPixmapStorage fPixels;
SkSemaphore fPixelsReady;
bool fWaited;
T fData;
};
#endif