2018-03-01 15:24:02 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2018 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkBitmap.h"
|
|
|
|
#include "include/core/SkColor.h"
|
|
|
|
#include "include/core/SkColorSpace.h"
|
2019-05-06 21:17:19 +00:00
|
|
|
#include "include/core/SkFont.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkImageInfo.h"
|
|
|
|
#include "include/core/SkMatrix.h"
|
|
|
|
#include "include/core/SkPaint.h"
|
|
|
|
#include "include/core/SkPoint.h"
|
|
|
|
#include "include/core/SkRefCnt.h"
|
2019-05-06 21:17:19 +00:00
|
|
|
#include "include/core/SkSize.h"
|
|
|
|
#include "include/core/SkTypes.h"
|
|
|
|
#include "include/gpu/GrBackendSurface.h"
|
2020-07-06 14:56:46 +00:00
|
|
|
#include "include/gpu/GrDirectContext.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/private/GrTypesPriv.h"
|
|
|
|
#include "src/core/SkIPoint16.h"
|
2019-05-06 21:17:19 +00:00
|
|
|
#include "src/gpu/GrCaps.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/GrDeferredUpload.h"
|
2020-10-14 15:23:11 +00:00
|
|
|
#include "src/gpu/GrDirectContextPriv.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/GrDrawOpAtlas.h"
|
|
|
|
#include "src/gpu/GrDrawingManager.h"
|
|
|
|
#include "src/gpu/GrMemoryPool.h"
|
|
|
|
#include "src/gpu/GrOnFlushResourceProvider.h"
|
|
|
|
#include "src/gpu/GrOpFlushState.h"
|
|
|
|
#include "src/gpu/GrRenderTargetContext.h"
|
2019-06-18 13:58:02 +00:00
|
|
|
#include "src/gpu/GrTextureProxy.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/GrXferProcessor.h"
|
2020-06-10 18:54:22 +00:00
|
|
|
#include "src/gpu/ops/GrAtlasTextOp.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/ops/GrDrawOp.h"
|
2019-05-06 21:17:19 +00:00
|
|
|
#include "src/gpu/ops/GrOp.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/text/GrAtlasManager.h"
|
|
|
|
#include "tests/Test.h"
|
|
|
|
#include "tools/gpu/GrContextFactory.h"
|
2018-05-22 14:48:08 +00:00
|
|
|
|
|
|
|
#include <memory>
|
2019-05-06 21:17:19 +00:00
|
|
|
#include <utility>
|
2018-05-22 14:48:08 +00:00
|
|
|
|
|
|
|
class GrResourceProvider;
|
2018-03-01 15:24:02 +00:00
|
|
|
|
|
|
|
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) {
|
2019-12-10 20:03:10 +00:00
|
|
|
if (fViews[i].proxy()->isInstantiated()) {
|
2018-03-01 15:24:02 +00:00
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2018-03-12 14:17:06 +00:00
|
|
|
void GrAtlasManager::setMaxPages_TestingOnly(uint32_t maxPages) {
|
2018-03-07 16:54:37 +00:00
|
|
|
for (int i = 0; i < kMaskFormatCount; i++) {
|
|
|
|
if (fAtlases[i]) {
|
2018-03-12 14:17:06 +00:00
|
|
|
fAtlases[i]->setMaxPages_TestingOnly(maxPages);
|
2018-03-07 16:54:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GrDrawOpAtlas::setMaxPages_TestingOnly(uint32_t maxPages) {
|
|
|
|
SkASSERT(!fNumActivePages);
|
|
|
|
|
|
|
|
fMaxPages = maxPages;
|
|
|
|
}
|
|
|
|
|
2020-01-22 22:26:56 +00:00
|
|
|
class DummyEvict : public GrDrawOpAtlas::EvictionCallback {
|
|
|
|
public:
|
2020-04-13 15:38:03 +00:00
|
|
|
void evict(GrDrawOpAtlas::PlotLocator) override {
|
2020-01-22 22:26:56 +00:00
|
|
|
SkASSERT(0); // The unit test shouldn't exercise this code path
|
|
|
|
}
|
|
|
|
};
|
2018-03-01 15:24:02 +00:00
|
|
|
|
|
|
|
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() { }
|
|
|
|
|
2018-03-07 16:54:37 +00:00
|
|
|
const GrTokenTracker* tokenTracker() final { return &fTokenTracker; }
|
|
|
|
GrTokenTracker* writeableTokenTracker() { return &fTokenTracker; }
|
2018-03-01 15:24:02 +00:00
|
|
|
|
|
|
|
GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final {
|
|
|
|
SkASSERT(0); // this test shouldn't invoke this code path
|
|
|
|
return fTokenTracker.nextDrawToken();
|
|
|
|
}
|
|
|
|
|
2020-08-14 02:58:04 +00:00
|
|
|
GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&& upload) final {
|
2018-03-01 15:24:02 +00:00
|
|
|
return fTokenTracker.nextTokenToFlush();
|
|
|
|
}
|
|
|
|
|
|
|
|
void issueDrawToken() { fTokenTracker.issueDrawToken(); }
|
|
|
|
void flushToken() { fTokenTracker.flushToken(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
GrTokenTracker fTokenTracker;
|
|
|
|
|
2020-09-03 02:42:33 +00:00
|
|
|
using INHERITED = GrDeferredUploadTarget;
|
2018-03-01 15:24:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool fill_plot(GrDrawOpAtlas* atlas,
|
|
|
|
GrResourceProvider* resourceProvider,
|
|
|
|
GrDeferredUploadTarget* target,
|
2020-04-06 14:29:28 +00:00
|
|
|
GrDrawOpAtlas::AtlasLocator* atlasLocator,
|
2018-03-01 15:24:02 +00:00
|
|
|
int alpha) {
|
|
|
|
SkImageInfo ii = SkImageInfo::MakeA8(kPlotSize, kPlotSize);
|
|
|
|
|
|
|
|
SkBitmap data;
|
|
|
|
data.allocPixels(ii);
|
|
|
|
data.eraseARGB(alpha, 0, 0, 0);
|
|
|
|
|
2018-03-07 16:54:37 +00:00
|
|
|
GrDrawOpAtlas::ErrorCode code;
|
2020-04-06 14:29:28 +00:00
|
|
|
code = atlas->addToAtlas(resourceProvider, target, kPlotSize, kPlotSize,
|
|
|
|
data.getAddr(0, 0), atlasLocator);
|
2018-03-07 16:54:37 +00:00
|
|
|
return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
|
2018-03-01 15:24:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-07 16:54:37 +00:00
|
|
|
// 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) {
|
2020-07-06 14:56:46 +00:00
|
|
|
auto context = ctxInfo.directContext();
|
2019-02-04 18:26:26 +00:00
|
|
|
auto proxyProvider = context->priv().proxyProvider();
|
|
|
|
auto resourceProvider = context->priv().resourceProvider();
|
|
|
|
auto drawingManager = context->priv().drawingManager();
|
2019-07-30 16:49:10 +00:00
|
|
|
const GrCaps* caps = context->priv().caps();
|
2018-03-01 15:24:02 +00:00
|
|
|
|
|
|
|
GrOnFlushResourceProvider onFlushResourceProvider(drawingManager);
|
|
|
|
TestingUploadTarget uploadTarget;
|
|
|
|
|
2019-07-30 16:49:10 +00:00
|
|
|
GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kAlpha_8,
|
|
|
|
GrRenderable::kNo);
|
2018-11-16 20:43:41 +00:00
|
|
|
|
2020-01-22 22:26:56 +00:00
|
|
|
DummyEvict evictor;
|
2020-01-24 20:57:11 +00:00
|
|
|
GrDrawOpAtlas::GenerationCounter counter;
|
2020-01-22 22:26:56 +00:00
|
|
|
|
2018-03-01 15:24:02 +00:00
|
|
|
std::unique_ptr<GrDrawOpAtlas> atlas = GrDrawOpAtlas::Make(
|
|
|
|
proxyProvider,
|
2018-11-16 20:43:41 +00:00
|
|
|
format,
|
2019-05-14 17:29:45 +00:00
|
|
|
GrColorType::kAlpha_8,
|
2018-03-01 15:24:02 +00:00
|
|
|
kAtlasSize, kAtlasSize,
|
2018-12-14 13:22:24 +00:00
|
|
|
kAtlasSize/kNumPlots, kAtlasSize/kNumPlots,
|
2020-01-24 20:57:11 +00:00
|
|
|
&counter,
|
2018-03-01 15:24:02 +00:00
|
|
|
GrDrawOpAtlas::AllowMultitexturing::kYes,
|
2020-01-22 22:26:56 +00:00
|
|
|
&evictor);
|
2018-03-01 15:24:02 +00:00
|
|
|
check(reporter, atlas.get(), 0, 4, 0);
|
|
|
|
|
|
|
|
// Fill up the first level
|
2020-04-06 14:29:28 +00:00
|
|
|
GrDrawOpAtlas::AtlasLocator atlasLocators[kNumPlots * kNumPlots];
|
2018-03-01 15:24:02 +00:00
|
|
|
for (int i = 0; i < kNumPlots * kNumPlots; ++i) {
|
2020-01-24 19:31:16 +00:00
|
|
|
bool result = fill_plot(
|
2020-04-06 14:29:28 +00:00
|
|
|
atlas.get(), resourceProvider, &uploadTarget, &atlasLocators[i], i * 32);
|
2018-03-01 15:24:02 +00:00
|
|
|
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
|
2020-04-06 14:29:28 +00:00
|
|
|
GrDrawOpAtlas::AtlasLocator atlasLocator;
|
|
|
|
bool result = fill_plot(atlas.get(), resourceProvider, &uploadTarget, &atlasLocator, 4 * 32);
|
2018-03-01 15:24:02 +00:00
|
|
|
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) {
|
2020-04-06 14:29:28 +00:00
|
|
|
atlas->setLastUseToken(atlasLocators[0], uploadTarget.tokenTracker()->nextDrawToken());
|
2018-03-01 15:24:02 +00:00
|
|
|
uploadTarget.issueDrawToken();
|
|
|
|
uploadTarget.flushToken();
|
|
|
|
atlas->compact(uploadTarget.tokenTracker()->nextTokenToFlush());
|
|
|
|
}
|
|
|
|
|
|
|
|
check(reporter, atlas.get(), 1, 4, 1);
|
|
|
|
}
|
|
|
|
|
2018-03-07 16:54:37 +00:00
|
|
|
// 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) {
|
|
|
|
|
2020-07-06 14:56:46 +00:00
|
|
|
auto context = ctxInfo.directContext();
|
2018-03-07 16:54:37 +00:00
|
|
|
|
2019-02-04 18:26:26 +00:00
|
|
|
auto gpu = context->priv().getGpu();
|
|
|
|
auto resourceProvider = context->priv().resourceProvider();
|
2018-03-07 16:54:37 +00:00
|
|
|
|
2020-01-08 16:52:34 +00:00
|
|
|
auto rtc = GrRenderTargetContext::Make(
|
|
|
|
context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox, {32, 32});
|
2018-03-07 16:54:37 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setColor(SK_ColorRED);
|
2019-01-02 20:35:29 +00:00
|
|
|
|
|
|
|
SkFont font;
|
|
|
|
font.setEdging(SkFont::Edging::kAlias);
|
2018-03-07 16:54:37 +00:00
|
|
|
|
|
|
|
const char* text = "a";
|
2020-04-15 20:43:00 +00:00
|
|
|
SkSimpleMatrixProvider matrixProvider(SkMatrix::I());
|
2018-03-07 16:54:37 +00:00
|
|
|
|
2020-10-07 20:46:15 +00:00
|
|
|
GrOp::Owner op =
|
2020-06-10 18:54:22 +00:00
|
|
|
GrAtlasTextOp::CreateOpTestingOnly(
|
|
|
|
rtc.get(), paint, font, matrixProvider, text, 16, 16);
|
2020-07-09 20:19:35 +00:00
|
|
|
if (!op) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-10 18:54:22 +00:00
|
|
|
|
2019-06-24 00:07:38 +00:00
|
|
|
bool hasMixedSampledCoverage = false;
|
2020-10-07 20:46:15 +00:00
|
|
|
GrAtlasTextOp* atlasTextOp = (GrAtlasTextOp*)op.get();
|
|
|
|
atlasTextOp->finalize(
|
|
|
|
*context->priv().caps(), nullptr, hasMixedSampledCoverage, GrClampType::kAuto);
|
2018-03-07 16:54:37 +00:00
|
|
|
|
|
|
|
TestingUploadTarget uploadTarget;
|
|
|
|
|
2019-06-18 21:15:04 +00:00
|
|
|
GrOpFlushState flushState(gpu, resourceProvider, uploadTarget.writeableTokenTracker());
|
2019-10-29 15:26:01 +00:00
|
|
|
|
2020-04-01 20:22:00 +00:00
|
|
|
GrSurfaceProxyView surfaceView = rtc->writeSurfaceView();
|
2019-10-08 16:32:56 +00:00
|
|
|
GrOpFlushState::OpArgs opArgs(op.get(),
|
2020-11-19 18:41:26 +00:00
|
|
|
surfaceView,
|
2019-10-08 16:32:56 +00:00
|
|
|
nullptr,
|
2020-09-11 13:33:54 +00:00
|
|
|
GrXferProcessor::DstProxyView(),
|
2020-11-20 15:22:43 +00:00
|
|
|
GrXferBarrierFlags::kNone,
|
|
|
|
GrLoadOp::kLoad);
|
2018-03-07 16:54:37 +00:00
|
|
|
|
2020-07-31 18:16:57 +00:00
|
|
|
// Modify the atlas manager so it can't allocate any pages. This will force a failure
|
2018-03-07 16:54:37 +00:00
|
|
|
// in the preparation of the text op
|
2019-02-04 18:26:26 +00:00
|
|
|
auto atlasManager = context->priv().getAtlasManager();
|
2018-03-07 16:54:37 +00:00
|
|
|
unsigned int numProxies;
|
2019-12-10 20:03:10 +00:00
|
|
|
atlasManager->getViews(kA8_GrMaskFormat, &numProxies);
|
2018-03-07 16:54:37 +00:00
|
|
|
atlasManager->setMaxPages_TestingOnly(0);
|
|
|
|
|
|
|
|
flushState.setOpArgs(&opArgs);
|
|
|
|
op->prepare(&flushState);
|
|
|
|
flushState.setOpArgs(nullptr);
|
|
|
|
}
|
2018-10-18 17:41:32 +00:00
|
|
|
|
2018-12-14 13:22:24 +00:00
|
|
|
void test_atlas_config(skiatest::Reporter* reporter, int maxTextureSize, size_t maxBytes,
|
|
|
|
GrMaskFormat maskFormat, SkISize expectedDimensions,
|
|
|
|
SkISize expectedPlotDimensions) {
|
|
|
|
GrDrawOpAtlasConfig config(maxTextureSize, maxBytes);
|
|
|
|
REPORTER_ASSERT(reporter, config.atlasDimensions(maskFormat) == expectedDimensions);
|
|
|
|
REPORTER_ASSERT(reporter, config.plotDimensions(maskFormat) == expectedPlotDimensions);
|
|
|
|
}
|
|
|
|
|
2018-10-18 17:41:32 +00:00
|
|
|
DEF_GPUTEST(GrDrawOpAtlasConfig_Basic, reporter, options) {
|
2018-12-14 13:22:24 +00:00
|
|
|
// 1/4 MB
|
|
|
|
test_atlas_config(reporter, 65536, 256 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 256, 256 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 256 * 1024, kA8_GrMaskFormat,
|
|
|
|
{ 512, 512 }, { 256, 256 });
|
|
|
|
// 1/2 MB
|
|
|
|
test_atlas_config(reporter, 65536, 512 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 512, 256 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 512 * 1024, kA8_GrMaskFormat,
|
|
|
|
{ 1024, 512 }, { 256, 256 });
|
|
|
|
// 1 MB
|
|
|
|
test_atlas_config(reporter, 65536, 1024 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 512, 512 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 1024 * 1024, kA8_GrMaskFormat,
|
|
|
|
{ 1024, 1024 }, { 256, 256 });
|
|
|
|
// 2 MB
|
|
|
|
test_atlas_config(reporter, 65536, 2 * 1024 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 1024, 512 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 2 * 1024 * 1024, kA8_GrMaskFormat,
|
|
|
|
{ 2048, 1024 }, { 512, 256 });
|
|
|
|
// 4 MB
|
|
|
|
test_atlas_config(reporter, 65536, 4 * 1024 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 1024, 1024 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 4 * 1024 * 1024, kA8_GrMaskFormat,
|
2018-12-20 20:48:55 +00:00
|
|
|
{ 2048, 2048 }, { 512, 512 });
|
2018-12-14 13:22:24 +00:00
|
|
|
// 8 MB
|
|
|
|
test_atlas_config(reporter, 65536, 8 * 1024 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 2048, 1024 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 8 * 1024 * 1024, kA8_GrMaskFormat,
|
2018-12-20 20:48:55 +00:00
|
|
|
{ 2048, 2048 }, { 512, 512 });
|
2018-12-14 13:22:24 +00:00
|
|
|
// 16 MB (should be same as 8 MB)
|
|
|
|
test_atlas_config(reporter, 65536, 16 * 1024 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 2048, 1024 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 16 * 1024 * 1024, kA8_GrMaskFormat,
|
2018-12-20 20:48:55 +00:00
|
|
|
{ 2048, 2048 }, { 512, 512 });
|
2018-12-14 13:22:24 +00:00
|
|
|
|
|
|
|
// 4MB, restricted texture size
|
|
|
|
test_atlas_config(reporter, 1024, 8 * 1024 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 1024, 1024 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 1024, 8 * 1024 * 1024, kA8_GrMaskFormat,
|
|
|
|
{ 1024, 1024 }, { 256, 256 });
|
|
|
|
|
|
|
|
// 3 MB (should be same as 2 MB)
|
|
|
|
test_atlas_config(reporter, 65536, 3 * 1024 * 1024, kARGB_GrMaskFormat,
|
|
|
|
{ 1024, 512 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 3 * 1024 * 1024, kA8_GrMaskFormat,
|
|
|
|
{ 2048, 1024 }, { 512, 256 });
|
|
|
|
|
|
|
|
// minimum size
|
|
|
|
test_atlas_config(reporter, 65536, 0, kARGB_GrMaskFormat,
|
|
|
|
{ 256, 256 }, { 256, 256 });
|
|
|
|
test_atlas_config(reporter, 65536, 0, kA8_GrMaskFormat,
|
|
|
|
{ 512, 512 }, { 256, 256 });
|
2018-10-19 01:51:15 +00:00
|
|
|
}
|