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:
Robert Phillips 2018-03-27 17:01:16 -04:00 committed by Skia Commit-Bot
parent 282f9daa82
commit e47f0a0f16
5 changed files with 1 additions and 345 deletions

View File

@ -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");

View File

@ -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)

View File

@ -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 {

View File

@ -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.");

View File

@ -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);