c7ad40f76f
Most of this is (obviously) not necessary to do, but once I started, I figured I'd just get it all. Tools (nanobench, DM, skiaserve), all GMs, benches, and unit tests, plus support code (command line parsing and config stuff). This is almost entirely mechanical. Bug: skia: Change-Id: I209500f8df8c5bd43f8298ff26440d1c4d7425fb Reviewed-on: https://skia-review.googlesource.com/131153 Reviewed-by: Mike Klein <mtklein@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
163 lines
5.2 KiB
C++
163 lines
5.2 KiB
C++
/*
|
|
* Copyright 2018 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "DDLTileHelper.h"
|
|
|
|
#include "DDLPromiseImageHelper.h"
|
|
#include "SkCanvas.h"
|
|
#include "SkDeferredDisplayListRecorder.h"
|
|
#include "SkImage_Gpu.h"
|
|
#include "SkPicture.h"
|
|
#include "SkSurface.h"
|
|
#include "SkSurfaceCharacterization.h"
|
|
#include "SkTaskGroup.h"
|
|
|
|
DDLTileHelper::TileData::TileData(sk_sp<SkSurface> s, const SkIRect& clip)
|
|
: fSurface(std::move(s))
|
|
, fClip(clip) {
|
|
SkAssertResult(fSurface->characterize(&fCharacterization));
|
|
}
|
|
|
|
void DDLTileHelper::TileData::createTileSpecificSKP(SkData* compressedPictureData,
|
|
const DDLPromiseImageHelper& helper) {
|
|
SkASSERT(!fReconstitutedPicture);
|
|
|
|
// This is bending the DDLRecorder contract! The promise images in the SKP should be
|
|
// created by the same recorder used to create the matching DDL.
|
|
SkDeferredDisplayListRecorder recorder(fCharacterization);
|
|
|
|
fReconstitutedPicture = helper.reinflateSKP(&recorder, compressedPictureData, &fPromiseImages);
|
|
}
|
|
|
|
void DDLTileHelper::TileData::createDDL() {
|
|
SkASSERT(fReconstitutedPicture);
|
|
SkASSERT(!fDisplayList);
|
|
|
|
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();
|
|
|
|
// Because we cheated in createTileSpecificSKP and used the wrong DDLRecorder, the GrContext's
|
|
// stored in fReconstitutedPicture's promise images are incorrect. Patch them with the correct
|
|
// one now.
|
|
for (int i = 0; i < fPromiseImages.count(); ++i) {
|
|
GrContext* newContext = subCanvas->getGrContext();
|
|
|
|
if (fPromiseImages[i]->isTextureBacked()) {
|
|
SkImage_Gpu* gpuImage = (SkImage_Gpu*) fPromiseImages[i].get();
|
|
gpuImage->resetContext(sk_ref_sp(newContext));
|
|
}
|
|
}
|
|
|
|
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(fReconstitutedPicture);
|
|
|
|
fDisplayList = recorder.detach();
|
|
}
|
|
|
|
void DDLTileHelper::TileData::draw() {
|
|
SkASSERT(fDisplayList);
|
|
|
|
fSurface->draw(fDisplayList.get());
|
|
}
|
|
|
|
void DDLTileHelper::TileData::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();
|
|
}
|
|
|
|
void DDLTileHelper::TileData::reset() {
|
|
// TODO: when DDLs are re-renderable we don't need to do this
|
|
fDisplayList = nullptr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
DDLTileHelper::DDLTileHelper(SkCanvas* canvas, const SkIRect& viewport, int numDivisions)
|
|
: fNumDivisions(numDivisions) {
|
|
SkASSERT(fNumDivisions > 0);
|
|
fTiles.reserve(fNumDivisions*fNumDivisions);
|
|
|
|
int xTileSize = viewport.width()/fNumDivisions;
|
|
int yTileSize = viewport.height()/fNumDivisions;
|
|
|
|
// Create the destination tiles
|
|
for (int y = 0, yOff = 0; y < fNumDivisions; ++y, yOff += yTileSize) {
|
|
int ySize = (y < fNumDivisions-1) ? yTileSize : viewport.height()-yOff;
|
|
|
|
for (int x = 0, xOff = 0; x < fNumDivisions; ++x, xOff += xTileSize) {
|
|
int xSize = (x < fNumDivisions-1) ? xTileSize : viewport.width()-xOff;
|
|
|
|
SkIRect clip = SkIRect::MakeXYWH(xOff, yOff, xSize, ySize);
|
|
|
|
SkASSERT(viewport.contains(clip));
|
|
|
|
SkImageInfo tileII = SkImageInfo::MakeN32Premul(xSize, ySize);
|
|
|
|
sk_sp<SkSurface> tileSurface = canvas->makeSurface(tileII);
|
|
|
|
// TODO: this is here to deal w/ a resource allocator bug (skbug.com/8007). If all
|
|
// the DDLs are flushed at the same time (w/o the composition draws) the allocator
|
|
// feels free to reuse the backing GrSurfaces!
|
|
tileSurface->flush();
|
|
|
|
fTiles.push_back(TileData(std::move(tileSurface), clip));
|
|
}
|
|
}
|
|
}
|
|
|
|
void DDLTileHelper::createSKPPerTile(SkData* compressedPictureData,
|
|
const DDLPromiseImageHelper& helper) {
|
|
for (int i = 0; i < fTiles.count(); ++i) {
|
|
fTiles[i].createTileSpecificSKP(compressedPictureData, helper);
|
|
}
|
|
}
|
|
|
|
void DDLTileHelper::createDDLsInParallel() {
|
|
#if 1
|
|
SkTaskGroup().batch(fTiles.count(), [&](int i) {
|
|
fTiles[i].createDDL();
|
|
});
|
|
#else
|
|
// Use this code path to debug w/o threads
|
|
for (int i = 0; i < fTiles.count(); ++i) {
|
|
fTiles[i].createDDL();
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
void DDLTileHelper::drawAllTilesAndFlush(GrContext* context, bool flush) {
|
|
for (int i = 0; i < fTiles.count(); ++i) {
|
|
fTiles[i].draw();
|
|
}
|
|
if (flush) {
|
|
context->flush();
|
|
}
|
|
}
|
|
|
|
void DDLTileHelper::composeAllTiles(SkCanvas* dstCanvas) {
|
|
for (int i = 0; i < fTiles.count(); ++i) {
|
|
fTiles[i].compose(dstCanvas);
|
|
}
|
|
}
|
|
|
|
void DDLTileHelper::resetAllTiles() {
|
|
for (int i = 0; i < fTiles.count(); ++i) {
|
|
fTiles[i].reset();
|
|
}
|
|
}
|