skia2/tests/DrawOpAtlasTest.cpp
Greg Daniel 4065d45d2d Reland "Reland "Have a GrBackendFormat be stored on gpu proxies.""
This is a reland of 2f9a5ea639

Original change's description:
> Reland "Have a GrBackendFormat be stored on gpu proxies."
> 
> This reverts commit 919c9e77c3.
> 
> Reason for revert: Flutter change has landed and fixed memory issue.
> 
> Original change's description:
> > Revert "Have a GrBackendFormat be stored on gpu proxies."
> >
> > This reverts commit 51b1c12bbc.
> >
> > Reason for revert: reverting till flutter gets to 1.1 to fix build issues.
> >
> > Original change's description:
> > > Have a GrBackendFormat be stored on gpu proxies.
> > >
> > > Bug: skia:
> > > Change-Id: Iaf1fb24ab29a61d44e5fa59a5e0867ed02dcda90
> > > Reviewed-on: https://skia-review.googlesource.com/c/168021
> > > Reviewed-by: Brian Osman <brianosman@google.com>
> > > Commit-Queue: Greg Daniel <egdaniel@google.com>
> >
> > TBR=egdaniel@google.com,bsalomon@google.com,brianosman@google.com
> >
> > Change-Id: I574fdc084ef5994596c51fb0d60423b5dc01b885
> > No-Presubmit: true
> > No-Tree-Checks: true
> > No-Try: true
> > Bug: chromium:903701 chromium:903756
> > Reviewed-on: https://skia-review.googlesource.com/c/169835
> > Commit-Queue: Greg Daniel <egdaniel@google.com>
> > Reviewed-by: Greg Daniel <egdaniel@google.com>
> 
> TBR=egdaniel@google.com,bsalomon@google.com,brianosman@google.com
> 
> Change-Id: Ifd9b6b8e194af9fb9258fa626644e76e6ecf090d
> Bug: chromium:903701 chromium:903756
> Reviewed-on: https://skia-review.googlesource.com/c/170104
> Commit-Queue: Greg Daniel <egdaniel@google.com>
> Reviewed-by: Greg Daniel <egdaniel@google.com>
> Reviewed-by: Brian Osman <brianosman@google.com>

Bug: chromium:903701 chromium:903756
Change-Id: Id1360067d8e928b0a4e1848dae8bc1e7f1994403
Reviewed-on: https://skia-review.googlesource.com/c/171660
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
2018-11-19 18:51:07 +00:00

244 lines
8.8 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 "SkTypes.h"
#include "GrContext.h"
#include "GrContextFactory.h"
#include "GrContextPriv.h"
#include "GrDeferredUpload.h"
#include "GrDrawOpAtlas.h"
#include "GrDrawingManager.h"
#include "GrMemoryPool.h"
#include "GrOnFlushResourceProvider.h"
#include "GrOpFlushState.h"
#include "GrRenderTargetContext.h"
#include "GrSurfaceProxyPriv.h"
#include "GrTextureProxy.h"
#include "GrTypesPriv.h"
#include "GrXferProcessor.h"
#include "SkBitmap.h"
#include "SkColor.h"
#include "SkColorSpace.h"
#include "SkIPoint16.h"
#include "SkImageInfo.h"
#include "SkMatrix.h"
#include "SkPaint.h"
#include "SkPoint.h"
#include "SkRefCnt.h"
#include "Test.h"
#include "ops/GrDrawOp.h"
#include "text/GrAtlasManager.h"
#include "text/GrTextContext.h"
#include "text/GrTextTarget.h"
#include <memory>
class GrResourceProvider;
static const int kNumPlots = 2;
static const int kPlotSize = 32;
static const int kAtlasSize = kNumPlots * kPlotSize;
int GrDrawOpAtlas::numAllocated_TestingOnly() const {
int count = 0;
for (uint32_t i = 0; i < this->maxPages(); ++i) {
if (fProxies[i]->isInstantiated()) {
++count;
}
}
return count;
}
void GrAtlasManager::setMaxPages_TestingOnly(uint32_t maxPages) {
for (int i = 0; i < kMaskFormatCount; i++) {
if (fAtlases[i]) {
fAtlases[i]->setMaxPages_TestingOnly(maxPages);
}
}
}
void GrDrawOpAtlas::setMaxPages_TestingOnly(uint32_t maxPages) {
SkASSERT(!fNumActivePages);
fMaxPages = maxPages;
}
void EvictionFunc(GrDrawOpAtlas::AtlasID atlasID, void*) {
SkASSERT(0); // The unit test shouldn't exercise this code path
}
static void check(skiatest::Reporter* r, GrDrawOpAtlas* atlas,
uint32_t expectedActive, uint32_t expectedMax, int expectedAlloced) {
REPORTER_ASSERT(r, expectedActive == atlas->numActivePages());
REPORTER_ASSERT(r, expectedMax == atlas->maxPages());
REPORTER_ASSERT(r, expectedAlloced == atlas->numAllocated_TestingOnly());
}
class TestingUploadTarget : public GrDeferredUploadTarget {
public:
TestingUploadTarget() { }
const GrTokenTracker* tokenTracker() final { return &fTokenTracker; }
GrTokenTracker* writeableTokenTracker() { return &fTokenTracker; }
GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final {
SkASSERT(0); // this test shouldn't invoke this code path
return fTokenTracker.nextDrawToken();
}
virtual GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final {
return fTokenTracker.nextTokenToFlush();
}
void issueDrawToken() { fTokenTracker.issueDrawToken(); }
void flushToken() { fTokenTracker.flushToken(); }
private:
GrTokenTracker fTokenTracker;
typedef GrDeferredUploadTarget INHERITED;
};
static bool fill_plot(GrDrawOpAtlas* atlas,
GrResourceProvider* resourceProvider,
GrDeferredUploadTarget* target,
GrDrawOpAtlas::AtlasID* atlasID,
int alpha) {
SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize);
SkBitmap data;
data.allocPixels(ii);
data.eraseARGB(alpha, 0, 0, 0);
SkIPoint16 loc;
GrDrawOpAtlas::ErrorCode code;
code = atlas->addToAtlas(resourceProvider, atlasID, target, kPlotSize, kPlotSize,
data.getAddr(0, 0), &loc);
return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
}
// This is a basic DrawOpAtlas test. It simply verifies that multitexture atlases correctly
// add and remove pages. Note that this is simulating flush-time behavior.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(BasicDrawOpAtlas, reporter, ctxInfo) {
auto context = ctxInfo.grContext();
auto proxyProvider = context->contextPriv().proxyProvider();
auto resourceProvider = context->contextPriv().resourceProvider();
auto drawingManager = context->contextPriv().drawingManager();
GrOnFlushResourceProvider onFlushResourceProvider(drawingManager);
TestingUploadTarget uploadTarget;
GrBackendFormat format =
context->contextPriv().caps()->getBackendFormatFromColorType(kAlpha_8_SkColorType);
std::unique_ptr<GrDrawOpAtlas> atlas = GrDrawOpAtlas::Make(
proxyProvider,
format,
kAlpha_8_GrPixelConfig,
kAtlasSize, kAtlasSize,
kNumPlots, kNumPlots,
GrDrawOpAtlas::AllowMultitexturing::kYes,
EvictionFunc, nullptr);
check(reporter, atlas.get(), 0, 4, 0);
// Fill up the first level
GrDrawOpAtlas::AtlasID atlasIDs[kNumPlots * kNumPlots];
for (int i = 0; i < kNumPlots * kNumPlots; ++i) {
bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasIDs[i], i*32);
REPORTER_ASSERT(reporter, result);
check(reporter, atlas.get(), 1, 4, 1);
}
atlas->instantiate(&onFlushResourceProvider);
check(reporter, atlas.get(), 1, 4, 1);
// Force allocation of a second level
GrDrawOpAtlas::AtlasID atlasID;
bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasID, 4*32);
REPORTER_ASSERT(reporter, result);
check(reporter, atlas.get(), 2, 4, 2);
// Simulate a lot of draws using only the first plot. The last texture should be compacted.
for (int i = 0; i < 512; ++i) {
atlas->setLastUseToken(atlasIDs[0], uploadTarget.tokenTracker()->nextDrawToken());
uploadTarget.issueDrawToken();
uploadTarget.flushToken();
atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush());
}
check(reporter, atlas.get(), 1, 4, 1);
}
// This test verifies that the GrAtlasTextOp::onPrepare method correctly handles a failure
// when allocating an atlas page.
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrAtlasTextOpPreparation, reporter, ctxInfo) {
auto context = ctxInfo.grContext();
auto gpu = context->contextPriv().getGpu();
auto resourceProvider = context->contextPriv().resourceProvider();
auto drawingManager = context->contextPriv().drawingManager();
auto textContext = drawingManager->getTextContext();
auto opMemoryPool = context->contextPriv().opMemoryPool();
GrBackendFormat format =
context->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
auto rtc = context->contextPriv().makeDeferredRenderTargetContext(format,
SkBackingFit::kApprox,
32, 32,
kRGBA_8888_GrPixelConfig,
nullptr);
SkPaint paint;
paint.setColor(SK_ColorRED);
paint.setLCDRenderText(false);
paint.setAntiAlias(false);
paint.setSubpixelText(false);
const char* text = "a";
std::unique_ptr<GrDrawOp> op = textContext->createOp_TestingOnly(
context, textContext, rtc.get(), paint, SkMatrix::I(), text, 16, 16);
op->finalize(*context->contextPriv().caps(), nullptr);
TestingUploadTarget uploadTarget;
GrOpFlushState flushState(gpu, resourceProvider, uploadTarget.writeableTokenTracker(), nullptr,
nullptr);
GrOpFlushState::OpArgs opArgs = {
op.get(),
rtc->asRenderTargetProxy(),
nullptr,
GrXferProcessor::DstProxy(nullptr, SkIPoint::Make(0, 0))
};
// Cripple the atlas manager so it can't allocate any pages. This will force a failure
// in the preparation of the text op
auto atlasManager = context->contextPriv().getAtlasManager();
unsigned int numProxies;
atlasManager->getProxies(kA8_GrMaskFormat, &numProxies);
atlasManager->setMaxPages_TestingOnly(0);
flushState.setOpArgs(&opArgs);
op->prepare(&flushState);
flushState.setOpArgs(nullptr);
opMemoryPool->release(std::move(op));
}
DEF_GPUTEST(GrDrawOpAtlasConfig_Basic, reporter, options) {
REPORTER_ASSERT(reporter, GrDrawOpAtlasConfig::PlotsPerLongDimensionForARGB( 1) == 1);
REPORTER_ASSERT(reporter, GrDrawOpAtlasConfig::PlotsPerLongDimensionForARGB( 256) == 1);
REPORTER_ASSERT(reporter, GrDrawOpAtlasConfig::PlotsPerLongDimensionForARGB( 512) == 2);
REPORTER_ASSERT(reporter, GrDrawOpAtlasConfig::PlotsPerLongDimensionForARGB(1024) == 4);
REPORTER_ASSERT(reporter, GrDrawOpAtlasConfig::PlotsPerLongDimensionForARGB(2048) == 8);
REPORTER_ASSERT(reporter, GrDrawOpAtlasConfig::PlotsPerLongDimensionForARGB(4096) == 8);
}