skia2/tools/DDLTileHelper.h
Robert Phillips 5dbcca5634 Update DDL test harness to better match OOP-R
OOP-R, on the gpu thread, creates the DDL, pre-compiles its shaders, draws it, flushes and then deletes the DDL. This process triggered a bug (cf. https://skia-review.googlesource.com/c/skia/+/292818 and crbug.com/1056730).

Prior to this CL all the programs were compiled and only at the end was any work flushed - thus it was likely that the bound program would be reset to the correct value when rendering.

With this CL, the addition of the flush right before the DDL deletion, makes it more likely that the wrong program will be bound when rendering begins.

Change-Id: I60479bd429e132d8652bbffde6c8b71094be6225
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/292257
Reviewed-by: Adlai Holler <adlai@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
2020-05-29 15:58:05 +00:00

146 lines
5.5 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.
*/
#ifndef DDLTileHelper_DEFINED
#define DDLTileHelper_DEFINED
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurfaceCharacterization.h"
class DDLPromiseImageHelper;
class PromiseImageCallbackContext;
class SkCanvas;
class SkData;
class SkDeferredDisplayList;
class SkDeferredDisplayListRecorder;
class SkPicture;
class SkSurface;
class SkSurfaceCharacterization;
class DDLTileHelper {
public:
// The TileData class encapsulates the information and behavior of a single tile when
// rendering with DDLs.
class TileData {
public:
TileData() {}
~TileData();
void init(int id,
GrContext* context,
const SkSurfaceCharacterization& dstChar,
const SkIRect& clip);
// Convert the compressedPictureData into an SkPicture replacing each image-index
// with a promise image.
void createTileSpecificSKP(SkData* compressedPictureData,
const DDLPromiseImageHelper& helper);
// Create the DDL for this tile (i.e., fill in 'fDisplayList').
void createDDL();
void dropDDL() { fDisplayList.reset(); }
// Precompile all the programs required to draw this tile's DDL
void precompile(GrContext*);
// Just draw the re-inflated per-tile SKP directly into this tile w/o going through a DDL
// first. This is used for determining the overhead of using DDLs (i.e., it replaces
// a 'createDDL' and 'draw' pair.
void drawSKPDirectly(GrContext*);
// Replay the recorded DDL into the tile surface - filling in 'fBackendTexture'.
void draw(GrContext*);
void reset();
int id() const { return fID; }
SkIRect clipRect() const { return fClip; }
SkDeferredDisplayList* ddl() { return fDisplayList.get(); }
sk_sp<SkImage> makePromiseImage(SkDeferredDisplayListRecorder*);
void dropCallbackContext() { fCallbackContext.reset(); }
static void CreateBackendTexture(GrContext*, TileData*);
static void DeleteBackendTexture(GrContext*, TileData*);
private:
sk_sp<SkSurface> makeWrappedTileDest(GrContext* context);
sk_sp<PromiseImageCallbackContext> refCallbackContext() { return fCallbackContext; }
int fID = -1;
SkIRect fClip; // in the device space of the final SkSurface
SkSurfaceCharacterization fCharacterization; // characterization for the tile's surface
// The callback context holds (via its SkPromiseImageTexture) the backend texture
// that is both wrapped in 'fTileSurface' and backs this tile's promise image
// (i.e., the one returned by 'makePromiseImage').
sk_sp<PromiseImageCallbackContext> fCallbackContext;
// 'fTileSurface' wraps the backend texture in 'fCallbackContext' and must exist until
// after 'fDisplayList' has been flushed (bc it owns the proxy the DDL's destination
// trampoline points at).
// TODO: fix the ref-order so we don't need 'fTileSurface' here
sk_sp<SkSurface> fTileSurface;
sk_sp<SkPicture> fReconstitutedPicture;
SkTArray<sk_sp<SkImage>> fPromiseImages; // All the promise images in the
// reconstituted picture
std::unique_ptr<SkDeferredDisplayList> fDisplayList;
};
DDLTileHelper(GrContext* context,
const SkSurfaceCharacterization& dstChar,
const SkIRect& viewport,
int numDivisions);
void createSKPPerTile(SkData* compressedPictureData, const DDLPromiseImageHelper& helper);
void kickOffThreadedWork(SkTaskGroup* recordingTaskGroup,
SkTaskGroup* gpuTaskGroup,
GrContext* gpuThreadContext);
void createDDLsInParallel();
// Create the DDL that will compose all the tile images into a final result.
void createComposeDDL();
SkDeferredDisplayList* composeDDL() const { return fComposeDDL.get(); }
void precompileAndDrawAllTiles(GrContext*);
// For each tile, create its DDL and then draw it - all on a single thread. This is to allow
// comparison w/ just drawing the SKP directly (i.e., drawAllTilesDirectly). The
// DDL creations and draws are interleaved to prevent starvation of the GPU.
// Note: this is somewhat of a misuse/pessimistic-use of DDLs since they are supposed to
// be created on a separate thread.
void interleaveDDLCreationAndDraw(GrContext*);
// This draws all the per-tile SKPs directly into all of the tiles w/o converting them to
// DDLs first - all on a single thread.
void drawAllTilesDirectly(GrContext*);
void dropCallbackContexts();
void resetAllTiles();
int numTiles() const { return fNumDivisions * fNumDivisions; }
void createBackendTextures(SkTaskGroup*, GrContext*);
void deleteBackendTextures(SkTaskGroup*, GrContext*);
private:
int fNumDivisions; // number of tiles along a side
SkAutoTArray<TileData> fTiles; // 'fNumDivisions' x 'fNumDivisions'
std::unique_ptr<SkDeferredDisplayList> fComposeDDL;
const SkSurfaceCharacterization fDstCharacterization;
};
#endif