Remove old method of drawing DDL SKPs from DM (in favor of ViaDDL method)
Change-Id: I6bb270d9df1c76b9d2e384abde603cdda91c9bb6 Reviewed-on: https://skia-review.googlesource.com/116550 Commit-Queue: Mike Klein <mtklein@google.com> Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
282f9daa82
commit
e47f0a0f16
@ -788,11 +788,7 @@ static bool gather_srcs() {
|
||||
push_src("gm", "", new GMSrc(r->factory()));
|
||||
}
|
||||
|
||||
if (FLAGS_ddl > 0) {
|
||||
gather_file_srcs<DDLSKPSrc>(FLAGS_skps, "skp");
|
||||
} else {
|
||||
gather_file_srcs<SKPSrc>(FLAGS_skps, "skp");
|
||||
}
|
||||
gather_file_srcs<MSKPSrc>(FLAGS_mskps, "mskp");
|
||||
#if !defined(SK_BUILD_FOR_GOOGLE3)
|
||||
gather_file_srcs<SkottieSrc>(FLAGS_jsons, "json");
|
||||
|
325
dm/DMSrcSink.cpp
325
dm/DMSrcSink.cpp
@ -1203,331 +1203,6 @@ SkISize SKPSrc::size() const {
|
||||
|
||||
Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
static const int kDDLViewportSize = 2048;
|
||||
static const SkRect kDDLSKPViewport = { 0, 0, kDDLViewportSize, kDDLViewportSize };
|
||||
|
||||
DDLSKPSrc::DDLSKPSrc(Path path) : fPath(path) { }
|
||||
|
||||
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 !SK_SUPPORT_GPU
|
||||
|
||||
Error DDLSKPSrc::draw(SkCanvas* canvas) const {
|
||||
return SkStringPrintf("DDLs are GPU only\n");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
class PromiseImageInfo {
|
||||
public:
|
||||
int fIndex;
|
||||
sk_sp<SkImage> fImage;
|
||||
SkBitmap fBitmap;
|
||||
GrBackendTexture fBackendTexture;
|
||||
};
|
||||
|
||||
static void promise_image_fulfill_proc(void* textureContext, GrBackendTexture* outTexture) {
|
||||
const PromiseImageInfo* imgInfo = static_cast<const PromiseImageInfo*>(textureContext);
|
||||
|
||||
*outTexture = imgInfo->fBackendTexture;
|
||||
}
|
||||
|
||||
static void promise_image_release_proc(void* textureContext) {
|
||||
// Do nothing. We free all the backend textures at the end.
|
||||
}
|
||||
|
||||
static void promise_image_done_proc(void* textureContext) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
class PromiseImageCallbackContext {
|
||||
public:
|
||||
const SkTArray<PromiseImageInfo>* fImageInfo;
|
||||
SkDeferredDisplayListRecorder* fRecorder;
|
||||
};
|
||||
|
||||
// This generates promise images to replace the indices in the compressed picture. This
|
||||
// reconstitution is performed separately in each thread so we end of with multiple
|
||||
// promise image referring to the same GrBackendTexture.
|
||||
static sk_sp<SkImage> promise_image_creator(const void* rawData, size_t length, void* ctxIn) {
|
||||
PromiseImageCallbackContext* ctx = static_cast<PromiseImageCallbackContext*>(ctxIn);
|
||||
const SkTArray<PromiseImageInfo>* imageInfo = ctx->fImageInfo;
|
||||
SkDeferredDisplayListRecorder* recorder = ctx->fRecorder;
|
||||
|
||||
SkASSERT(length == sizeof(int));
|
||||
|
||||
const int* indexPtr = static_cast<const int*>(rawData);
|
||||
SkASSERT(*indexPtr < imageInfo->count());
|
||||
|
||||
const PromiseImageInfo& curImage = (*imageInfo)[*indexPtr];
|
||||
SkASSERT(curImage.fIndex == *indexPtr);
|
||||
|
||||
GrBackendFormat backendFormat = curImage.fBackendTexture.format();
|
||||
|
||||
// DDL TODO: sort out mipmapping
|
||||
sk_sp<SkImage> image = recorder->makePromiseTexture(backendFormat,
|
||||
curImage.fBitmap.width(),
|
||||
curImage.fBitmap.height(),
|
||||
GrMipMapped::kNo,
|
||||
GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
|
||||
curImage.fBitmap.colorType(),
|
||||
curImage.fBitmap.alphaType(),
|
||||
curImage.fBitmap.refColorSpace(),
|
||||
promise_image_fulfill_proc,
|
||||
promise_image_release_proc,
|
||||
promise_image_done_proc,
|
||||
(void*) &curImage);
|
||||
SkASSERT(image);
|
||||
return image;
|
||||
};
|
||||
|
||||
// DDL TODO: it would be great if we could draw the DDL directly into the destination SkSurface
|
||||
Error DDLSKPSrc::draw(SkCanvas* canvas) const {
|
||||
GrContext* context = canvas->getGrContext();
|
||||
if (!context) {
|
||||
return SkStringPrintf("DDLs are GPU only\n");
|
||||
}
|
||||
|
||||
if (1 == FLAGS_ddl) {
|
||||
// If the number of x & y tiles is one just perform normal (non-DDL) rendering for
|
||||
// comparison purposes
|
||||
sk_sp<SkPicture> picture = read_skp(fPath.c_str());
|
||||
if (!picture) {
|
||||
return SkStringPrintf("Couldn't read %s.", fPath.c_str());
|
||||
}
|
||||
|
||||
canvas->clipRect(kDDLSKPViewport);
|
||||
canvas->drawPicture(std::move(picture));
|
||||
return "";
|
||||
}
|
||||
|
||||
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
|
||||
// In each thread we will reconvert the compressedPictureData into an SkPicture
|
||||
// replacing each image-index with a promise image.
|
||||
void preprocess(SkData* compressedPictureData,
|
||||
const SkTArray<PromiseImageInfo>* imageInfo) {
|
||||
SkDeferredDisplayListRecorder recorder(fCharacterization);
|
||||
|
||||
// DDL TODO: the DDLRecorder's GrContext isn't initialized until getCanvas is called.
|
||||
// Maybe set it up in the ctor?
|
||||
SkCanvas* subCanvas = recorder.getCanvas();
|
||||
|
||||
sk_sp<SkPicture> reconstitutedPicture;
|
||||
|
||||
{
|
||||
PromiseImageCallbackContext callbackCtx = { imageInfo, &recorder };
|
||||
|
||||
SkDeserialProcs procs;
|
||||
procs.fImageCtx = &callbackCtx;
|
||||
procs.fImageProc = promise_image_creator;
|
||||
|
||||
reconstitutedPicture = SkPicture::MakeFromData(compressedPictureData, &procs);
|
||||
if (!reconstitutedPicture) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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(reconstitutedPicture);
|
||||
|
||||
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);
|
||||
|
||||
SkTArray<PromiseImageInfo> imageInfo;
|
||||
sk_sp<SkData> compressedPictureData;
|
||||
|
||||
SkIRect viewport; // this is our ultimate final drawing area/rect
|
||||
|
||||
// DDL TODO: should we also be deduping in the following preprocessing?
|
||||
|
||||
// Massage the input picture into something we can use with DDL
|
||||
{
|
||||
// In the first pass we read in an .skp file into an SkPicture recording all the images
|
||||
// and getting a copy of their pixels in an uploadable form.
|
||||
sk_sp<SkPicture> firstPassPicture;
|
||||
{
|
||||
SkDeserialProcs procs;
|
||||
|
||||
procs.fImageCtx = &imageInfo;
|
||||
procs.fImageProc = [](const void* rawData, size_t length, void* ctx) -> sk_sp<SkImage> {
|
||||
auto imageInfo = static_cast<SkTArray<PromiseImageInfo>*>(ctx);
|
||||
|
||||
sk_sp<SkData> data = SkData::MakeWithCopy(rawData, length);
|
||||
|
||||
PromiseImageInfo newImageInfo;
|
||||
newImageInfo.fIndex = imageInfo->count();
|
||||
newImageInfo.fImage = SkImage::MakeFromEncoded(std::move(data));
|
||||
SkAssertResult(newImageInfo.fImage->asLegacyBitmap(&newImageInfo.fBitmap));
|
||||
|
||||
imageInfo->push_back(newImageInfo);
|
||||
return newImageInfo.fImage;
|
||||
};
|
||||
|
||||
firstPassPicture = read_skp(fPath.c_str(), &procs);
|
||||
if (!firstPassPicture) {
|
||||
return SkStringPrintf("Couldn't read %s.", fPath.c_str());
|
||||
}
|
||||
|
||||
SkRect pictureCullRect = firstPassPicture->cullRect();
|
||||
SkAssertResult(pictureCullRect.intersect(kDDLSKPViewport));
|
||||
viewport = pictureCullRect.roundOut();
|
||||
}
|
||||
|
||||
// In the second pass we convert the SkPicture into SkData replacing all the SkImages
|
||||
// with an index into the imageInfo we collected in the first pass.
|
||||
{
|
||||
SkSerialProcs procs;
|
||||
|
||||
procs.fImageCtx = &imageInfo;
|
||||
procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
|
||||
auto imageInfo = static_cast<const SkTArray<PromiseImageInfo>*>(ctx);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < imageInfo->count(); ++i) {
|
||||
if ((*imageInfo)[i].fImage.get() == image) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SkASSERT(i < imageInfo->count());
|
||||
return SkData::MakeWithCopy(&i, sizeof(i));
|
||||
};
|
||||
|
||||
compressedPictureData = firstPassPicture->serialize(&procs);
|
||||
if (!compressedPictureData) {
|
||||
return SkStringPrintf("Couldn't re-serialize %s.", fPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// In the third pass we go through all the images and upload them to the GPU and
|
||||
// get rid of the SkImage from the first pass
|
||||
{
|
||||
GrGpu* gpu = context->contextPriv().getGpu();
|
||||
if (!gpu) {
|
||||
return SkStringPrintf("Couldn't get GPU from GrContext\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < imageInfo.count(); ++i) {
|
||||
// DDL TODO: how can we tell if we need mipmapping!
|
||||
imageInfo[i].fBackendTexture = gpu->createTestingOnlyBackendTexture(
|
||||
imageInfo[i].fBitmap.getPixels(),
|
||||
imageInfo[i].fBitmap.width(),
|
||||
imageInfo[i].fBitmap.height(),
|
||||
imageInfo[i].fBitmap.colorType(),
|
||||
false, GrMipMapped::kNo);
|
||||
SkAssertResult(imageInfo[i].fBackendTexture.isValid());
|
||||
imageInfo[i].fImage = nullptr; // we don't need this anymore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xTileSize = viewport.width()/FLAGS_ddl;
|
||||
int yTileSize = viewport.height()/FLAGS_ddl;
|
||||
|
||||
// First, create the destination tiles
|
||||
for (int y = 0, yOff = 0; y < FLAGS_ddl; ++y, yOff += yTileSize) {
|
||||
int ySize = (y < FLAGS_ddl-1) ? yTileSize : viewport.height()-yOff;
|
||||
|
||||
for (int x = 0, xOff = 0; x < FLAGS_ddl; ++x, xOff += xTileSize) {
|
||||
int xSize = (x < FLAGS_ddl-1) ? xTileSize : viewport.width()-xOff;
|
||||
|
||||
SkIRect clip = SkIRect::MakeXYWH(xOff, yOff, xSize, ySize);
|
||||
|
||||
SkASSERT(viewport.contains(clip));
|
||||
|
||||
SkImageInfo tileII = SkImageInfo::MakeN32Premul(xSize, ySize);
|
||||
|
||||
tileData.push_back(TileData(canvas->makeSurface(tileII), clip));
|
||||
}
|
||||
}
|
||||
|
||||
// Second, run the cpu pre-processing in threads
|
||||
SkTaskGroup().batch(tileData.count(), [&](int i) {
|
||||
tileData[i].preprocess(compressedPictureData.get(), &imageInfo);
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// All promise images need to be fulfulled before leaving this method since we are about to
|
||||
// delete their backing GrBackendTextures
|
||||
context->flush();
|
||||
|
||||
// Clean up VRAM
|
||||
{
|
||||
GrGpu* gpu = context->contextPriv().getGpu();
|
||||
if (!gpu) {
|
||||
return SkStringPrintf("Couldn't get GPU from GrContext\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < imageInfo.count(); ++i) {
|
||||
gpu->deleteTestingOnlyBackendTexture(imageInfo[i].fBackendTexture);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
||||
|
||||
#if !defined(SK_BUILD_FOR_GOOGLE3)
|
||||
|
@ -251,17 +251,6 @@ private:
|
||||
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_BUILD_FOR_GOOGLE3)
|
||||
class SkottieSrc final : public Src {
|
||||
|
@ -65,9 +65,6 @@ DEFINE_string(jsons, "jsons", "Directory to read (Bodymovin) jsons from.");
|
||||
|
||||
DEFINE_int32(skpViewportSize, 1000, "Width & height of the viewport used to crop skp rendering.");
|
||||
|
||||
DEFINE_int32(ddl, 0, "If > 0, the # of x & y divisions used for DeferredDisplayList-based "
|
||||
"GPU SKP rendering.");
|
||||
|
||||
DEFINE_bool(nativeFonts, true, "If true, use native font manager and rendering. "
|
||||
"If false, fonts will draw as portably as possible.");
|
||||
|
||||
|
@ -25,7 +25,6 @@ DECLARE_bool(abandonGpuContext);
|
||||
DECLARE_bool(releaseAndAbandonGpuContext);
|
||||
DECLARE_string(skps);
|
||||
DECLARE_int32(skpViewportSize);
|
||||
DECLARE_int32(ddl);
|
||||
DECLARE_string(jpgs);
|
||||
DECLARE_string(jsons);
|
||||
DECLARE_string(svgs);
|
||||
|
Loading…
Reference in New Issue
Block a user