DeferredDisplayList API proposal
Chrome would like to perform cpu-side preprocessing for gpu draws in parallel. They do not want to go through a picture (since they have their own display list format). The general idea is that we add a new SkDeferredDisplayListRecorder class to perform all of Ganesh's cpu-side preprocessing ahead of time and in parallel. The SkDDLRecorder operates like SkPictureRecorder. The user can get an SkCanvas from the SkDDLRecorder and feed it draw operations. Once finished, the user calls 'detach' to get an SkDeferredDisplayList. All the work up to and including the 'detach' call can be done in parallel and will not touch the GPU. To actually get pixels the client must call SkSurface::draw(SkDDL) on an SkSurface that is "compatible" with the surface characterization initially given to the SkDDLMaker. The surface characterization contains the minimum amount of information Ganesh needs to know about the ultimate destination in order to perform its cpu-side work (i.e., caps, width, height, config). Change-Id: I75faa483ab5a6b779c8de56ea56b9d90b990f43a Reviewed-on: https://skia-review.googlesource.com/30140 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
f1942de288
commit
ad8a43f769
@ -92,6 +92,8 @@ DEFINE_int32(shard, 0, "Which shard do I run?");
|
|||||||
DEFINE_string(mskps, "", "Directory to read mskps from, or a single mskp file.");
|
DEFINE_string(mskps, "", "Directory to read mskps from, or a single mskp file.");
|
||||||
DEFINE_bool(forceRasterPipeline, false, "sets gSkForceRasterPipelineBlitter");
|
DEFINE_bool(forceRasterPipeline, false, "sets gSkForceRasterPipelineBlitter");
|
||||||
|
|
||||||
|
DEFINE_bool(ddl, false, "If true, use DeferredDisplayLists for GPU SKP rendering.");
|
||||||
|
|
||||||
#if SK_SUPPORT_GPU
|
#if SK_SUPPORT_GPU
|
||||||
DEFINE_pathrenderer_flag;
|
DEFINE_pathrenderer_flag;
|
||||||
#endif
|
#endif
|
||||||
@ -773,7 +775,11 @@ static bool gather_srcs() {
|
|||||||
push_src("gm", "", new GMSrc(r->factory()));
|
push_src("gm", "", new GMSrc(r->factory()));
|
||||||
}
|
}
|
||||||
|
|
||||||
gather_file_srcs<SKPSrc>(FLAGS_skps, "skp");
|
if (FLAGS_ddl) {
|
||||||
|
gather_file_srcs<DDLSKPSrc>(FLAGS_skps, "skp");
|
||||||
|
} else {
|
||||||
|
gather_file_srcs<SKPSrc>(FLAGS_skps, "skp");
|
||||||
|
}
|
||||||
gather_file_srcs<MSKPSrc>(FLAGS_mskps, "mskp");
|
gather_file_srcs<MSKPSrc>(FLAGS_mskps, "mskp");
|
||||||
#if defined(SK_XML)
|
#if defined(SK_XML)
|
||||||
gather_file_srcs<SVGSrc>(FLAGS_svgs, "svg");
|
gather_file_srcs<SVGSrc>(FLAGS_svgs, "svg");
|
||||||
|
158
dm/DMSrcSink.cpp
158
dm/DMSrcSink.cpp
@ -19,6 +19,7 @@
|
|||||||
#include "SkData.h"
|
#include "SkData.h"
|
||||||
#include "SkDebugCanvas.h"
|
#include "SkDebugCanvas.h"
|
||||||
#include "SkDeferredCanvas.h"
|
#include "SkDeferredCanvas.h"
|
||||||
|
#include "SkDeferredDisplayListRecorder.h"
|
||||||
#include "SkDocument.h"
|
#include "SkDocument.h"
|
||||||
#include "SkExecutor.h"
|
#include "SkExecutor.h"
|
||||||
#include "SkImageGenerator.h"
|
#include "SkImageGenerator.h"
|
||||||
@ -39,9 +40,11 @@
|
|||||||
#include "SkRandom.h"
|
#include "SkRandom.h"
|
||||||
#include "SkRecordDraw.h"
|
#include "SkRecordDraw.h"
|
||||||
#include "SkRecorder.h"
|
#include "SkRecorder.h"
|
||||||
|
#include "SkSurfaceCharacterization.h"
|
||||||
#include "SkSVGCanvas.h"
|
#include "SkSVGCanvas.h"
|
||||||
#include "SkStream.h"
|
#include "SkStream.h"
|
||||||
#include "SkSwizzler.h"
|
#include "SkSwizzler.h"
|
||||||
|
#include "SkTaskGroup.h"
|
||||||
#include "SkTLogic.h"
|
#include "SkTLogic.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -1140,37 +1143,51 @@ Name ColorCodecSrc::name() const {
|
|||||||
|
|
||||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
static const SkRect kSKPViewport = {0,0, 1000,1000};
|
static const SkRect kSKPViewport = {0, 0, 1000, 1000};
|
||||||
|
|
||||||
SKPSrc::SKPSrc(Path path) : fPath(path) {}
|
SKPSrc::SKPSrc(Path path) : fPath(path) { }
|
||||||
|
|
||||||
Error SKPSrc::draw(SkCanvas* canvas) const {
|
static sk_sp<SkPicture> read_skp(const char* path) {
|
||||||
std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str());
|
std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path);
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
return SkStringPrintf("Couldn't read %s.", fPath.c_str());
|
return nullptr;
|
||||||
}
|
}
|
||||||
sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get()));
|
sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get()));
|
||||||
if (!pic) {
|
if (!pic) {
|
||||||
return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
|
return nullptr;
|
||||||
}
|
}
|
||||||
stream = nullptr; // Might as well drop this when we're done with it.
|
stream = nullptr; // Might as well drop this when we're done with it.
|
||||||
|
|
||||||
|
return pic;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error SKPSrc::draw(SkCanvas* canvas) const {
|
||||||
|
sk_sp<SkPicture> pic = read_skp(fPath.c_str());
|
||||||
|
if (!pic) {
|
||||||
|
return SkStringPrintf("Couldn't read %s.", fPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
canvas->clipRect(kSKPViewport);
|
canvas->clipRect(kSKPViewport);
|
||||||
canvas->drawPicture(pic);
|
canvas->drawPicture(pic);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
SkISize SKPSrc::size() const {
|
static SkRect get_cull_rect_for_skp(const char* path) {
|
||||||
std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str());
|
std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path);
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
return {0, 0};
|
return SkRect::MakeEmpty();
|
||||||
}
|
}
|
||||||
SkPictInfo info;
|
SkPictInfo info;
|
||||||
if (!SkPicture::InternalOnly_StreamIsSKP(stream.get(), &info)) {
|
if (!SkPicture::InternalOnly_StreamIsSKP(stream.get(), &info)) {
|
||||||
return {0, 0};
|
return SkRect::MakeEmpty();
|
||||||
}
|
}
|
||||||
SkRect viewport = kSKPViewport;
|
|
||||||
if (!viewport.intersect(info.fCullRect)) {
|
return info.fCullRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkISize SKPSrc::size() const {
|
||||||
|
SkRect viewport = get_cull_rect_for_skp(fPath.c_str());
|
||||||
|
if (!viewport.intersect(kSKPViewport)) {
|
||||||
return {0, 0};
|
return {0, 0};
|
||||||
}
|
}
|
||||||
return viewport.roundOut().size();
|
return viewport.roundOut().size();
|
||||||
@ -1178,6 +1195,123 @@ SkISize SKPSrc::size() const {
|
|||||||
|
|
||||||
Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
|
Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
|
||||||
|
|
||||||
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
|
|
||||||
|
static const int kNumDDLXTiles = 4;
|
||||||
|
static const int kNumDDLYTiles = 4;
|
||||||
|
static const int kDDLTileSize = 1024;
|
||||||
|
static const SkRect kDDLSKPViewport = { 0, 0,
|
||||||
|
kNumDDLXTiles * kDDLTileSize,
|
||||||
|
kNumDDLYTiles * kDDLTileSize };
|
||||||
|
|
||||||
|
DDLSKPSrc::DDLSKPSrc(Path path) : fPath(path) { }
|
||||||
|
|
||||||
|
Error DDLSKPSrc::draw(SkCanvas* canvas) const {
|
||||||
|
class TileData {
|
||||||
|
public:
|
||||||
|
// Note: we could just pass in surface characterization
|
||||||
|
TileData(sk_sp<SkSurface> surf, const SkIRect& clip)
|
||||||
|
: fSurface(std::move(surf))
|
||||||
|
, fClip(clip) {
|
||||||
|
SkAssertResult(fSurface->characterize(&fCharacterization));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method operates in parallel
|
||||||
|
void preprocess(SkPicture* pic) {
|
||||||
|
SkDeferredDisplayListRecorder recorder(fCharacterization);
|
||||||
|
|
||||||
|
SkCanvas* subCanvas = recorder.getCanvas();
|
||||||
|
|
||||||
|
subCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height()));
|
||||||
|
subCanvas->translate(-fClip.fLeft, -fClip.fTop);
|
||||||
|
|
||||||
|
// Note: in this use case we only render a picture to the deferred canvas
|
||||||
|
// but, more generally, clients will use arbitrary draw calls.
|
||||||
|
subCanvas->drawPicture(pic);
|
||||||
|
|
||||||
|
fDisplayList = recorder.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method operates serially
|
||||||
|
void draw() {
|
||||||
|
fSurface->draw(fDisplayList.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method also operates serially
|
||||||
|
void compose(SkCanvas* dst) {
|
||||||
|
sk_sp<SkImage> img = fSurface->makeImageSnapshot();
|
||||||
|
dst->save();
|
||||||
|
dst->clipRect(SkRect::Make(fClip));
|
||||||
|
dst->drawImage(std::move(img), fClip.fLeft, fClip.fTop);
|
||||||
|
dst->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sk_sp<SkSurface> fSurface;
|
||||||
|
SkIRect fClip; // in the device space of the destination canvas
|
||||||
|
std::unique_ptr<SkDeferredDisplayList> fDisplayList;
|
||||||
|
SkSurfaceCharacterization fCharacterization;
|
||||||
|
};
|
||||||
|
|
||||||
|
SkTArray<TileData> tileData;
|
||||||
|
tileData.reserve(16);
|
||||||
|
|
||||||
|
sk_sp<SkPicture> pic = read_skp(fPath.c_str());
|
||||||
|
if (!pic) {
|
||||||
|
return SkStringPrintf("Couldn't read %s.", fPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const SkRect cullRect = pic->cullRect();
|
||||||
|
|
||||||
|
// All the destination tiles are the same size
|
||||||
|
const SkImageInfo tileII = SkImageInfo::MakeN32Premul(kDDLTileSize, kDDLTileSize);
|
||||||
|
|
||||||
|
// First, create the destination tiles
|
||||||
|
for (int y = 0; y < kNumDDLYTiles; ++y) {
|
||||||
|
for (int x = 0; x < kNumDDLXTiles; ++x) {
|
||||||
|
SkRect clip = SkRect::MakeXYWH(x * kDDLTileSize, y * kDDLTileSize,
|
||||||
|
kDDLTileSize, kDDLTileSize);
|
||||||
|
|
||||||
|
if (!clip.intersect(cullRect)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tileData.push_back(TileData(canvas->makeSurface(tileII), clip.roundOut()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second, run the cpu pre-processing in threads
|
||||||
|
SkTaskGroup().batch(tileData.count(), [&](int i) {
|
||||||
|
tileData[i].preprocess(pic.get());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Third, synchronously render the display lists into the dest tiles
|
||||||
|
// TODO: it would be cool to not wait until all the tiles are drawn to begin
|
||||||
|
// drawing to the GPU
|
||||||
|
for (int i = 0; i < tileData.count(); ++i) {
|
||||||
|
tileData[i].draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, compose the drawn tiles into the result
|
||||||
|
// Note: the separation between the tiles and the final composition better
|
||||||
|
// matches Chrome but costs us a copy
|
||||||
|
for (int i = 0; i < tileData.count(); ++i) {
|
||||||
|
tileData[i].compose(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
SkISize DDLSKPSrc::size() const {
|
||||||
|
SkRect viewport = get_cull_rect_for_skp(fPath.c_str());
|
||||||
|
if (!viewport.intersect(kDDLSKPViewport)) {
|
||||||
|
return {0, 0};
|
||||||
|
}
|
||||||
|
return viewport.roundOut().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Name DDLSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
|
||||||
|
|
||||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||||
#if defined(SK_XML)
|
#if defined(SK_XML)
|
||||||
// Used when the image doesn't have an intrinsic size.
|
// Used when the image doesn't have an intrinsic size.
|
||||||
|
@ -248,6 +248,18 @@ private:
|
|||||||
Path fPath;
|
Path fPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DeferredDisplayList flavor
|
||||||
|
class DDLSKPSrc : public Src {
|
||||||
|
public:
|
||||||
|
explicit DDLSKPSrc(Path path);
|
||||||
|
|
||||||
|
Error draw(SkCanvas*) const override;
|
||||||
|
SkISize size() const override;
|
||||||
|
Name name() const override;
|
||||||
|
private:
|
||||||
|
Path fPath;
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(SK_XML)
|
#if defined(SK_XML)
|
||||||
} // namespace DM
|
} // namespace DM
|
||||||
|
|
||||||
|
@ -96,6 +96,7 @@ skia_core_sources = [
|
|||||||
"$_src/core/SkData.cpp",
|
"$_src/core/SkData.cpp",
|
||||||
"$_src/core/SkDataTable.cpp",
|
"$_src/core/SkDataTable.cpp",
|
||||||
"$_src/core/SkDebug.cpp",
|
"$_src/core/SkDebug.cpp",
|
||||||
|
"$_src/core/SkDeferredDisplayListRecorder.cpp",
|
||||||
"$_src/core/SkDeque.cpp",
|
"$_src/core/SkDeque.cpp",
|
||||||
"$_src/core/SkDescriptor.h",
|
"$_src/core/SkDescriptor.h",
|
||||||
"$_src/core/SkDevice.cpp",
|
"$_src/core/SkDevice.cpp",
|
||||||
@ -371,6 +372,7 @@ skia_core_sources = [
|
|||||||
"$_include/core/SkColorFilter.h",
|
"$_include/core/SkColorFilter.h",
|
||||||
"$_include/core/SkColorPriv.h",
|
"$_include/core/SkColorPriv.h",
|
||||||
"$_include/core/SkData.h",
|
"$_include/core/SkData.h",
|
||||||
|
"$_include/core/SkDeferredDisplayListRecorder.h",
|
||||||
"$_include/core/SkDeque.h",
|
"$_include/core/SkDeque.h",
|
||||||
"$_include/core/SkDrawable.h",
|
"$_include/core/SkDrawable.h",
|
||||||
"$_include/core/SkDrawFilter.h",
|
"$_include/core/SkDrawFilter.h",
|
||||||
@ -429,6 +431,7 @@ skia_core_sources = [
|
|||||||
# private
|
# private
|
||||||
"$_include/private/SkAtomics.h",
|
"$_include/private/SkAtomics.h",
|
||||||
"$_include/private/SkChecksum.h",
|
"$_include/private/SkChecksum.h",
|
||||||
|
"$_include/private/SkDeferredDisplayList.h",
|
||||||
"$_include/private/SkFixed.h",
|
"$_include/private/SkFixed.h",
|
||||||
"$_include/private/SkFloatBits.h",
|
"$_include/private/SkFloatBits.h",
|
||||||
"$_include/private/SkFloatingPoint.h",
|
"$_include/private/SkFloatingPoint.h",
|
||||||
@ -440,6 +443,7 @@ skia_core_sources = [
|
|||||||
"$_include/private/SkSemaphore.h",
|
"$_include/private/SkSemaphore.h",
|
||||||
"$_include/private/SkShadowFlags.h",
|
"$_include/private/SkShadowFlags.h",
|
||||||
"$_include/private/SkSpinlock.h",
|
"$_include/private/SkSpinlock.h",
|
||||||
|
"$_include/private/SkSurfaceCharacterization.h",
|
||||||
"$_include/private/SkTemplates.h",
|
"$_include/private/SkTemplates.h",
|
||||||
"$_include/private/SkTArray.h",
|
"$_include/private/SkTArray.h",
|
||||||
"$_include/private/SkTDArray.h",
|
"$_include/private/SkTDArray.h",
|
||||||
|
52
include/core/SkDeferredDisplayListRecorder.h
Normal file
52
include/core/SkDeferredDisplayListRecorder.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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 SkDeferredDisplayListMaker_DEFINED
|
||||||
|
#define SkDeferredDisplayListMaker_DEFINED
|
||||||
|
|
||||||
|
#include "SkRefCnt.h"
|
||||||
|
|
||||||
|
#include "../private/SkDeferredDisplayList.h"
|
||||||
|
#include "../private/SkSurfaceCharacterization.h"
|
||||||
|
|
||||||
|
class SkCanvas;
|
||||||
|
class SkSurface; // TODO: remove
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This class is intended to be used as:
|
||||||
|
* Get an SkSurfaceCharacterization from the ultimate intended gpu-backed destination SkSurface
|
||||||
|
* Create one of these (an SkDDLMaker) on the stack
|
||||||
|
* Get the canvas and render into it
|
||||||
|
* Snap off and hold on to an SkDeferredDisplayList
|
||||||
|
* Once your app actually needs the pixels, call SkSurface::draw(SkDeferredDisplayList*)
|
||||||
|
*
|
||||||
|
* This class never accesses the GPU but performs all the cpu work it can. It
|
||||||
|
* is thread-safe (i.e., one can break a scene into tiles and perform their cpu-side
|
||||||
|
* work in parallel ahead of time).
|
||||||
|
*/
|
||||||
|
class SkDeferredDisplayListRecorder {
|
||||||
|
public:
|
||||||
|
SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&);
|
||||||
|
|
||||||
|
const SkSurfaceCharacterization& characterization() const {
|
||||||
|
return fCharacterization;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The backing canvas will become invalid (and this entry point will return
|
||||||
|
// null) once 'detach' is called.
|
||||||
|
// Note: ownership of the SkCanvas is not transfered via this call.
|
||||||
|
SkCanvas* getCanvas();
|
||||||
|
|
||||||
|
std::unique_ptr<SkDeferredDisplayList> detach();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkSurfaceCharacterization fCharacterization;
|
||||||
|
|
||||||
|
sk_sp<SkSurface> fSurface; // temporary until we have a real implementation
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -15,7 +15,9 @@
|
|||||||
#include "GrTypes.h"
|
#include "GrTypes.h"
|
||||||
|
|
||||||
class SkCanvas;
|
class SkCanvas;
|
||||||
|
class SkDeferredDisplayList;
|
||||||
class SkPaint;
|
class SkPaint;
|
||||||
|
class SkSurfaceCharacterization;
|
||||||
class GrBackendRenderTarget;
|
class GrBackendRenderTarget;
|
||||||
class GrBackendSemaphore;
|
class GrBackendSemaphore;
|
||||||
class GrContext;
|
class GrContext;
|
||||||
@ -335,6 +337,21 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
|
bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This creates a characterization of this SkSurface's properties that can
|
||||||
|
* be used to perform gpu-backend preprocessing in a separate thread (via
|
||||||
|
* the SkDeferredDisplayListRecorder).
|
||||||
|
* It will return false on failure (e.g., if the SkSurface is cpu-backed).
|
||||||
|
*/
|
||||||
|
bool characterize(SkSurfaceCharacterization* characterization) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a deferred display list (created via SkDeferredDisplayListRecorder).
|
||||||
|
* The draw will be skipped if the characterization stored in the display list
|
||||||
|
* isn't compatible with this surface.
|
||||||
|
*/
|
||||||
|
void draw(SkDeferredDisplayList* deferredDisplayList);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SkSurface(int width, int height, const SkSurfaceProps*);
|
SkSurface(int width, int height, const SkSurfaceProps*);
|
||||||
SkSurface(const SkImageInfo&, const SkSurfaceProps*);
|
SkSurface(const SkImageInfo&, const SkSurfaceProps*);
|
||||||
|
43
include/private/SkDeferredDisplayList.h
Normal file
43
include/private/SkDeferredDisplayList.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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 SkDeferredDisplayList_DEFINED
|
||||||
|
#define SkDeferredDisplayList_DEFINED
|
||||||
|
|
||||||
|
#include "SkSurfaceCharacterization.h"
|
||||||
|
|
||||||
|
class SkImage; // TODO: rm this
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This class contains pre-processed gpu operations that can be replayed into
|
||||||
|
* an SkSurface via draw(SkDeferredDisplayList*).
|
||||||
|
*
|
||||||
|
* TODO: we probably need to expose this class so users can query it for memory usage.
|
||||||
|
*/
|
||||||
|
class SkDeferredDisplayList {
|
||||||
|
public:
|
||||||
|
SkDeferredDisplayList(const SkSurfaceCharacterization& characterization,
|
||||||
|
sk_sp<SkImage> image) // TODO rm this parameter
|
||||||
|
: fCharacterization(characterization)
|
||||||
|
, fImage(std::move(image)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const SkSurfaceCharacterization& characterization() const {
|
||||||
|
return fCharacterization;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove this. It is just scaffolding to get something up & running
|
||||||
|
void draw(SkSurface*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkSurfaceCharacterization fCharacterization;
|
||||||
|
|
||||||
|
// TODO: actually store the GPU opLists
|
||||||
|
sk_sp<SkImage> fImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
54
include/private/SkSurfaceCharacterization.h
Normal file
54
include/private/SkSurfaceCharacterization.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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 SkSurfaceCharacterization_DEFINED
|
||||||
|
#define SkSurfaceCharacterization_DEFINED
|
||||||
|
|
||||||
|
#include "GrTypes.h"
|
||||||
|
|
||||||
|
class SkSurface;
|
||||||
|
|
||||||
|
// This class captures all the pertinent data about an SkSurface required
|
||||||
|
// to perform cpu-preprocessing for gpu-rendering.
|
||||||
|
class SkSurfaceCharacterization {
|
||||||
|
public:
|
||||||
|
SkSurfaceCharacterization()
|
||||||
|
: fOrigin(kBottomLeft_GrSurfaceOrigin)
|
||||||
|
, fWidth(0)
|
||||||
|
, fHeight(0)
|
||||||
|
, fConfig(kRGBA_8888_GrPixelConfig)
|
||||||
|
, fSampleCnt(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(GrSurfaceOrigin origin,
|
||||||
|
int width, int height,
|
||||||
|
GrPixelConfig config,
|
||||||
|
int sampleCnt) {
|
||||||
|
fOrigin = origin;
|
||||||
|
fWidth = width;
|
||||||
|
fHeight = height;
|
||||||
|
fConfig = config;
|
||||||
|
fSampleCnt = sampleCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
GrSurfaceOrigin origin() const { return fOrigin; }
|
||||||
|
int width() const { return fWidth; }
|
||||||
|
int height() const { return fHeight; }
|
||||||
|
GrPixelConfig config() const { return fConfig; }
|
||||||
|
int sampleCount() const { return fSampleCnt; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
GrSurfaceOrigin fOrigin;
|
||||||
|
int fWidth;
|
||||||
|
int fHeight;
|
||||||
|
GrPixelConfig fConfig;
|
||||||
|
int fSampleCnt;
|
||||||
|
// TODO: need to include caps!
|
||||||
|
// Maybe use GrContextThreadSafeProxy (it has the caps & the unique Context ID already)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
46
src/core/SkDeferredDisplayListRecorder.cpp
Normal file
46
src/core/SkDeferredDisplayListRecorder.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SkDeferredDisplayListRecorder.h"
|
||||||
|
|
||||||
|
#include "SkCanvas.h" // TODO: remove
|
||||||
|
#include "SkDeferredDisplayList.h"
|
||||||
|
#include "SkSurface.h" // TODO: remove
|
||||||
|
|
||||||
|
SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(
|
||||||
|
const SkSurfaceCharacterization& characterization)
|
||||||
|
: fCharacterization(characterization) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SkCanvas* SkDeferredDisplayListRecorder::getCanvas() {
|
||||||
|
if (!fSurface) {
|
||||||
|
SkImageInfo ii = SkImageInfo::MakeN32(fCharacterization.width(),
|
||||||
|
fCharacterization.height(),
|
||||||
|
kOpaque_SkAlphaType);
|
||||||
|
|
||||||
|
// Use raster right now to allow threading
|
||||||
|
fSurface = SkSurface::MakeRaster(ii, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fSurface->getCanvas();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
|
||||||
|
sk_sp<SkImage> img = fSurface->makeImageSnapshot();
|
||||||
|
fSurface.reset();
|
||||||
|
|
||||||
|
// TODO: need to wrap the opLists associated with the deferred draws
|
||||||
|
// in the SkDeferredDisplayList.
|
||||||
|
return std::unique_ptr<SkDeferredDisplayList>(
|
||||||
|
new SkDeferredDisplayList(fCharacterization, std::move(img)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Placeholder. Ultimately, the SkSurface_Gpu will pass the wrapped opLists to its
|
||||||
|
// renderTargetContext.
|
||||||
|
void SkDeferredDisplayList::draw(SkSurface* surface) {
|
||||||
|
surface->getCanvas()->drawImage(fImage.get(), 0, 0);
|
||||||
|
}
|
@ -209,6 +209,14 @@ bool SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores
|
|||||||
return asSB(this)->onWait(numSemaphores, waitSemaphores);
|
return asSB(this)->onWait(numSemaphores, waitSemaphores);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkSurface::characterize(SkSurfaceCharacterization* characterization) const {
|
||||||
|
return asSB(const_cast<SkSurface*>(this))->onCharacterize(characterization);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkSurface::draw(SkDeferredDisplayList* ddl) {
|
||||||
|
return asSB(this)->onDraw(ddl);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
#include "SkNoDrawCanvas.h"
|
#include "SkNoDrawCanvas.h"
|
||||||
|
|
||||||
|
@ -94,6 +94,9 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool onCharacterize(SkSurfaceCharacterization*) const { return false; }
|
||||||
|
virtual void onDraw(SkDeferredDisplayList*) { }
|
||||||
|
|
||||||
inline SkCanvas* getCachedCanvas();
|
inline SkCanvas* getCachedCanvas();
|
||||||
inline sk_sp<SkImage> refCachedImage();
|
inline sk_sp<SkImage> refCachedImage();
|
||||||
|
|
||||||
|
@ -15,11 +15,13 @@
|
|||||||
|
|
||||||
#include "SkCanvas.h"
|
#include "SkCanvas.h"
|
||||||
#include "SkColorSpace_Base.h"
|
#include "SkColorSpace_Base.h"
|
||||||
|
#include "SkDeferredDisplayList.h"
|
||||||
#include "SkGpuDevice.h"
|
#include "SkGpuDevice.h"
|
||||||
#include "SkImage_Base.h"
|
#include "SkImage_Base.h"
|
||||||
#include "SkImage_Gpu.h"
|
#include "SkImage_Gpu.h"
|
||||||
#include "SkImagePriv.h"
|
#include "SkImagePriv.h"
|
||||||
#include "SkSurface_Base.h"
|
#include "SkSurface_Base.h"
|
||||||
|
#include "SkSurfaceCharacterization.h"
|
||||||
|
|
||||||
#if SK_SUPPORT_GPU
|
#if SK_SUPPORT_GPU
|
||||||
|
|
||||||
@ -158,6 +160,35 @@ bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSema
|
|||||||
return fDevice->wait(numSemaphores, waitSemaphores);
|
return fDevice->wait(numSemaphores, waitSemaphores);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* data) const {
|
||||||
|
GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
|
||||||
|
|
||||||
|
data->set(rtc->origin(), rtc->width(), rtc->height(),
|
||||||
|
rtc->config(), rtc->numColorSamples());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkSurface_Gpu::isCompatible(const SkSurfaceCharacterization& data) const {
|
||||||
|
GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
|
||||||
|
|
||||||
|
return data.origin() == rtc->origin() &&
|
||||||
|
data.width() == rtc->width() &&
|
||||||
|
data.height() == rtc->height() &&
|
||||||
|
data.config() == rtc->config() &&
|
||||||
|
data.sampleCount() == rtc->numColorSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkSurface_Gpu::onDraw(SkDeferredDisplayList* dl) {
|
||||||
|
if (!this->isCompatible(dl->characterization())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ultimately need to pass opLists from the DeferredDisplayList on to the
|
||||||
|
// SkGpuDevice's renderTargetContext.
|
||||||
|
dl->draw(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
|
bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
|
||||||
|
@ -29,6 +29,9 @@ public:
|
|||||||
GrSemaphoresSubmitted onFlush(int numSemaphores,
|
GrSemaphoresSubmitted onFlush(int numSemaphores,
|
||||||
GrBackendSemaphore signalSemaphores[]) override;
|
GrBackendSemaphore signalSemaphores[]) override;
|
||||||
bool onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) override;
|
bool onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) override;
|
||||||
|
bool onCharacterize(SkSurfaceCharacterization*) const override;
|
||||||
|
bool isCompatible(const SkSurfaceCharacterization&) const;
|
||||||
|
void onDraw(SkDeferredDisplayList*) override;
|
||||||
|
|
||||||
SkGpuDevice* getDevice() { return fDevice.get(); }
|
SkGpuDevice* getDevice() { return fDevice.get(); }
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ DECLARE_bool(preAbandonGpuContext);
|
|||||||
DECLARE_bool(abandonGpuContext);
|
DECLARE_bool(abandonGpuContext);
|
||||||
DECLARE_bool(releaseAndAbandonGpuContext);
|
DECLARE_bool(releaseAndAbandonGpuContext);
|
||||||
DECLARE_string(skps);
|
DECLARE_string(skps);
|
||||||
|
DECLARE_bool(ddl);
|
||||||
DECLARE_string(svgs);
|
DECLARE_string(svgs);
|
||||||
DECLARE_int32(threads);
|
DECLARE_int32(threads);
|
||||||
DECLARE_string(resourcePath);
|
DECLARE_string(resourcePath);
|
||||||
|
Loading…
Reference in New Issue
Block a user