forked from flutter/engine
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update GrTextureStripAtlas for DDLs (take 2)
Change-Id: I4a3f71ffe4a14785e7befddc378929cf4dcf7d8e Reviewed-on: https://skia-review.googlesource.com/145150 Commit-Queue: Robert Phillips <robertphillips@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
- Loading branch information
Showing
11 changed files
with
481 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
/* | ||
* 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 "GrDDLTextureStripAtlas.h" | ||
|
||
#include "GrContextPriv.h" | ||
#include "GrTexture.h" | ||
#include "SkGr.h" | ||
#include "SkTSearch.h" | ||
|
||
GrDDLTextureStripAtlas::GrDDLTextureStripAtlas(const Desc& desc) | ||
: INHERITED(desc) | ||
, fAtlasBitmap(nullptr) | ||
, fMaxNumRows(desc.fHeight / desc.fRowHeight) | ||
, fCurRow(0) | ||
, fRows(new AtlasRow[fMaxNumRows]) { | ||
SkASSERT(fMaxNumRows * fDesc.fRowHeight == fDesc.fHeight); | ||
SkDEBUGCODE(this->validate();) | ||
} | ||
|
||
GrDDLTextureStripAtlas::~GrDDLTextureStripAtlas() { delete[] fRows; } | ||
|
||
// Flush the current state of the atlas. | ||
void GrDDLTextureStripAtlas::finish(GrProxyProvider* proxyProvider) { | ||
SkDEBUGCODE(this->validate();) | ||
|
||
if (!fCurRow) { | ||
SkASSERT(!fCurProxy && !fAtlasBitmap); | ||
return; | ||
} | ||
|
||
int height = fCurRow * fDesc.fRowHeight; | ||
SkASSERT(height <= fDesc.fHeight); | ||
|
||
SkImageInfo ii = SkImageInfo::Make(fDesc.fWidth, height, | ||
fDesc.fColorType, kPremul_SkAlphaType); | ||
fAtlasBitmap->allocPixels(ii); | ||
|
||
for (int i = 0; i < fCurRow; ++i) { | ||
SkASSERT(fRows[i].fBitmap.height() == fDesc.fRowHeight); | ||
|
||
int yPos = i * fDesc.fRowHeight; | ||
fAtlasBitmap->writePixels(fRows[i].fBitmap.pixmap(), 0, yPos); | ||
} | ||
|
||
GrUniqueKey key; | ||
{ | ||
static const GrUniqueKey::Domain kTextureStripAtlasDomain = GrUniqueKey::GenerateDomain(); | ||
GrUniqueKey::Builder builder(&key, kTextureStripAtlasDomain, fCurRow, | ||
"DDL Texture Strip Atlas"); | ||
for (int i = 0; i < fCurRow; ++i) { | ||
builder[i] = fRows[i].fBitmap.getGenerationID(); | ||
} | ||
builder.finish(); | ||
} | ||
|
||
sk_sp<GrTextureProxy> interloper = proxyProvider->findProxyByUniqueKey(key, | ||
fCurProxy->origin()); | ||
if (!interloper) { | ||
// In the unlikely event that there is already a proxy with this key (i.e., it has exactly | ||
// the same strips in exactly the same order) we'll just let it keep the key. | ||
proxyProvider->assignUniqueKeyToProxy(key, fCurProxy.get()); | ||
} | ||
|
||
// reset the state for the next aggregate texture | ||
for (int i = 0; i < fCurRow; ++i) { | ||
fRows[i].fBitmap.reset(); | ||
} | ||
fCurRow = 0; | ||
fCurProxy = nullptr; | ||
fAtlasBitmap = nullptr; | ||
fKeyTable.rewind(); | ||
SkDEBUGCODE(this->validate();) | ||
} | ||
|
||
int GrDDLTextureStripAtlas::addStrip(GrContext* context, const SkBitmap& bitmap) { | ||
SkDEBUGCODE(this->validate();) | ||
|
||
const int key = bitmap.getGenerationID(); | ||
int index = this->searchByKey(key); | ||
|
||
if (fCurRow >= fMaxNumRows && index < 0) { | ||
// The current atlas is full and adding another strip would make it overflow. Calve it off | ||
// and allow the next block to start a new one. | ||
this->finish(context->contextPriv().proxyProvider()); | ||
index = this->searchByKey(key); // 'finish' cleared the table | ||
} | ||
|
||
if (!fCurProxy) { | ||
SkASSERT(!fAtlasBitmap); | ||
|
||
const GrCaps* caps = context->contextPriv().caps(); | ||
GrPixelConfig pixelConfig = SkColorType2GrPixelConfig(fDesc.fColorType); | ||
SkASSERT(kUnknown_GrPixelConfig != pixelConfig); | ||
|
||
SkBitmap* atlasBitmap = new SkBitmap(); | ||
|
||
fCurProxy = GrProxyProvider::MakeFullyLazyProxy( | ||
[atlasBitmap, pixelConfig](GrResourceProvider* provider) -> sk_sp<GrSurface> { | ||
if (!provider) { | ||
delete atlasBitmap; | ||
return sk_sp<GrSurface>(); | ||
} | ||
// When this is called 'atlasBitmap' should've been filled in and be | ||
// non-empty | ||
SkASSERT(atlasBitmap->width() && atlasBitmap->height()); | ||
GrSurfaceDesc desc; | ||
desc.fFlags = kNone_GrSurfaceFlags; | ||
desc.fWidth = atlasBitmap->width(); | ||
desc.fHeight = atlasBitmap->height(); | ||
desc.fConfig = pixelConfig; | ||
|
||
GrMipLevel mipLevel = { atlasBitmap->getPixels(), atlasBitmap->rowBytes() }; | ||
|
||
return provider->createTexture(desc, SkBudgeted::kYes, | ||
SkBackingFit::kExact, mipLevel); | ||
}, | ||
GrProxyProvider::Renderable::kNo, kTopLeft_GrSurfaceOrigin, pixelConfig, *caps); | ||
|
||
fAtlasBitmap = atlasBitmap; | ||
} | ||
|
||
SkASSERT(bitmap.width() == fDesc.fWidth); | ||
SkASSERT(bitmap.height() == fDesc.fRowHeight); | ||
SkASSERT(!context->contextPriv().resourceProvider()); // This atlas class is DDL specific | ||
SkASSERT(fCurRow < fMaxNumRows); | ||
|
||
int rowNumber = -1; | ||
|
||
if (index >= 0) { | ||
// We already have the data in a row, so we can just return that row | ||
AtlasRow* row = fKeyTable[index]; | ||
|
||
// Since all the rows are always stored in a contiguous array, we can save the memory | ||
// required for storing row numbers and just compute it with some pointer arithmetic | ||
rowNumber = static_cast<int>(row - fRows); | ||
} else { | ||
// ~index is the index where we will insert the new key to keep things sorted | ||
index = ~index; | ||
|
||
rowNumber = fCurRow; | ||
fRows[fCurRow].fBitmap = bitmap; | ||
|
||
AtlasRow* row = &fRows[rowNumber]; | ||
fKeyTable.insert(index, 1, &row); | ||
|
||
++fCurRow; | ||
SkASSERT(fCurRow <= fMaxNumRows); | ||
} | ||
|
||
SkASSERT(rowNumber >= 0); | ||
SkDEBUGCODE(this->validate();) | ||
return rowNumber; | ||
} | ||
|
||
int GrDDLTextureStripAtlas::searchByKey(uint32_t generationID) { | ||
static struct AtlasRowLessFunctor { | ||
bool operator()(const AtlasRow* row, const uint32_t& id) const { | ||
return row->fBitmap.getGenerationID() < id; | ||
} | ||
bool operator()(const uint32_t& id, const AtlasRow* row) const { | ||
return id < row->fBitmap.getGenerationID(); | ||
} | ||
} functor; | ||
|
||
return SkTSearch(fKeyTable.begin(), fKeyTable.count(), generationID, sizeof(AtlasRow*), | ||
functor); | ||
} | ||
|
||
#ifdef SK_DEBUG | ||
void GrDDLTextureStripAtlas::validate() { | ||
static const int kBitmapInvalidGenID = 0; | ||
|
||
// Our key table should be sorted | ||
uint32_t prev = fKeyTable.count() >= 1 ? fKeyTable[0]->fBitmap.getGenerationID() : 0; | ||
for (int i = 1; i < fKeyTable.count(); ++i) { | ||
AtlasRow* row = fKeyTable[i]; | ||
SkASSERT(prev < row->fBitmap.getGenerationID()); | ||
SkASSERT(row->fBitmap.getGenerationID() != kBitmapInvalidGenID); | ||
prev = row->fBitmap.getGenerationID(); | ||
} | ||
|
||
for (int i = 0; i < fCurRow; ++i) { | ||
// These should all have a valid bitmap and be in the search table | ||
SkASSERT(fRows[i].fBitmap.getGenerationID() != kBitmapInvalidGenID); | ||
SkASSERT(this->searchByKey(fRows[i].fBitmap.getGenerationID()) >= 0); | ||
} | ||
for (int i = fCurRow; i < fMaxNumRows; ++i) { | ||
// These should all be empty | ||
SkASSERT(fRows[i].fBitmap.getGenerationID() == kBitmapInvalidGenID); | ||
} | ||
} | ||
#endif |
Oops, something went wrong.