674 lines
28 KiB
C++
674 lines
28 KiB
C++
/*
|
|
* Copyright 2022 Google LLC
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "include/gpu/graphite/BackendTexture.h"
|
|
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/core/SkColorFilter.h"
|
|
#include "include/core/SkColorSpace.h"
|
|
#include "include/core/SkSurface.h"
|
|
#include "include/gpu/graphite/Context.h"
|
|
#include "include/gpu/graphite/Recording.h"
|
|
#include "src/gpu/graphite/Caps.h"
|
|
#include "src/gpu/graphite/ContextPriv.h"
|
|
#include "src/gpu/graphite/RecordingPriv.h"
|
|
#include "tests/Test.h"
|
|
|
|
using namespace skgpu::graphite;
|
|
|
|
namespace {
|
|
|
|
struct PromiseTextureChecker {
|
|
PromiseTextureChecker() = default;
|
|
|
|
explicit PromiseTextureChecker(const BackendTexture& backendTex,
|
|
skiatest::Reporter* reporter)
|
|
: fReporter(reporter) {
|
|
fBackendTextures[0] = backendTex;
|
|
}
|
|
|
|
explicit PromiseTextureChecker(const BackendTexture& backendTex0,
|
|
const BackendTexture& backendTex1,
|
|
skiatest::Reporter* reporter)
|
|
: fReporter(reporter)
|
|
, fHasTwoBackendTextures(true) {
|
|
fBackendTextures[0] = backendTex0;
|
|
fBackendTextures[1] = backendTex1;
|
|
}
|
|
|
|
void checkImageReleased(skiatest::Reporter* reporter, int expectedReleaseCnt) {
|
|
REPORTER_ASSERT(reporter, expectedReleaseCnt == fImageReleaseCount);
|
|
}
|
|
|
|
int totalReleaseCount() const { return fTextureReleaseCounts[0] + fTextureReleaseCounts[1]; }
|
|
|
|
skiatest::Reporter* fReporter = nullptr;
|
|
bool fHasTwoBackendTextures = false;
|
|
BackendTexture fBackendTextures[2];
|
|
int fFulfillCount = 0;
|
|
int fImageReleaseCount = 0;
|
|
int fTextureReleaseCounts[2] = { 0, 0 };
|
|
|
|
static std::tuple<BackendTexture, void*> Fulfill(void* self) {
|
|
auto checker = reinterpret_cast<PromiseTextureChecker*>(self);
|
|
|
|
checker->fFulfillCount++;
|
|
|
|
if (checker->fHasTwoBackendTextures) {
|
|
int whichToUse = checker->fFulfillCount % 2;
|
|
return { checker->fBackendTextures[whichToUse],
|
|
&checker->fTextureReleaseCounts[whichToUse] };
|
|
} else {
|
|
return { checker->fBackendTextures[0], &checker->fTextureReleaseCounts[0] };
|
|
}
|
|
}
|
|
|
|
static void ImageRelease(void* self) {
|
|
auto checker = reinterpret_cast<PromiseTextureChecker*>(self);
|
|
|
|
checker->fImageReleaseCount++;
|
|
}
|
|
|
|
static void TextureRelease(void* context) {
|
|
int* releaseCount = reinterpret_cast<int*>(context);
|
|
|
|
(*releaseCount)++;
|
|
}
|
|
};
|
|
|
|
enum class ReleaseBalanceExpectation {
|
|
kBalanced,
|
|
kOffByOne, // fulfill calls ahead of release calls by 1
|
|
kOffByTwo, // fulfill calls ahead of release calls by 2
|
|
kFulfillsOnly, // 'n' fulfill calls, 0 release calls
|
|
};
|
|
|
|
void check_fulfill_and_release_cnts(skiatest::Reporter* reporter,
|
|
const PromiseTextureChecker& promiseChecker,
|
|
int expectedFulfillCnt,
|
|
ReleaseBalanceExpectation releaseBalanceExpectation) {
|
|
SkASSERT(promiseChecker.fFulfillCount == expectedFulfillCnt);
|
|
REPORTER_ASSERT(reporter, promiseChecker.fFulfillCount == expectedFulfillCnt);
|
|
if (!expectedFulfillCnt) {
|
|
// Release should only ever be called after Fulfill.
|
|
REPORTER_ASSERT(reporter, !promiseChecker.fImageReleaseCount);
|
|
REPORTER_ASSERT(reporter, !promiseChecker.totalReleaseCount());
|
|
return;
|
|
}
|
|
|
|
int releaseDiff = promiseChecker.fFulfillCount - promiseChecker.totalReleaseCount();
|
|
switch (releaseBalanceExpectation) {
|
|
case ReleaseBalanceExpectation::kBalanced:
|
|
SkASSERT(!releaseDiff);
|
|
REPORTER_ASSERT(reporter, !releaseDiff);
|
|
break;
|
|
case ReleaseBalanceExpectation::kOffByOne:
|
|
SkASSERT(releaseDiff == 1);
|
|
REPORTER_ASSERT(reporter, releaseDiff == 1);
|
|
break;
|
|
case ReleaseBalanceExpectation::kOffByTwo:
|
|
SkASSERT(releaseDiff == 2);
|
|
REPORTER_ASSERT(reporter, releaseDiff == 2);
|
|
break;
|
|
case ReleaseBalanceExpectation::kFulfillsOnly:
|
|
REPORTER_ASSERT(reporter, promiseChecker.totalReleaseCount() == 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void check_unfulfilled(const PromiseTextureChecker& promiseChecker,
|
|
skiatest::Reporter* reporter) {
|
|
check_fulfill_and_release_cnts(reporter, promiseChecker, /* expectedFulfillCnt= */ 0,
|
|
ReleaseBalanceExpectation::kBalanced);
|
|
}
|
|
|
|
void check_fulfilled_ahead_by_one(skiatest::Reporter* reporter,
|
|
const PromiseTextureChecker& promiseChecker,
|
|
int expectedFulfillCnt) {
|
|
check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
|
|
ReleaseBalanceExpectation::kOffByOne);
|
|
}
|
|
|
|
void check_fulfilled_ahead_by_two(skiatest::Reporter* reporter,
|
|
const PromiseTextureChecker& promiseChecker,
|
|
int expectedFulfillCnt) {
|
|
check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
|
|
ReleaseBalanceExpectation::kOffByTwo);
|
|
}
|
|
|
|
void check_all_done(skiatest::Reporter* reporter,
|
|
const PromiseTextureChecker& promiseChecker,
|
|
int expectedFulfillCnt) {
|
|
check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
|
|
ReleaseBalanceExpectation::kBalanced);
|
|
}
|
|
|
|
void check_fulfills_only(skiatest::Reporter* reporter,
|
|
const PromiseTextureChecker& promiseChecker,
|
|
int expectedFulfillCnt) {
|
|
check_fulfill_and_release_cnts(reporter, promiseChecker, expectedFulfillCnt,
|
|
ReleaseBalanceExpectation::kFulfillsOnly);
|
|
}
|
|
|
|
struct TestCtx {
|
|
TestCtx() {}
|
|
|
|
~TestCtx() {
|
|
for (int i = 0; i < 2; ++i) {
|
|
if (fBackendTextures[i].isValid()) {
|
|
fContext->deleteBackendTexture(fBackendTextures[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
Context* fContext;
|
|
std::unique_ptr<Recorder> fRecorder;
|
|
BackendTexture fBackendTextures[2];
|
|
PromiseTextureChecker fPromiseChecker;
|
|
sk_sp<SkImage> fImg;
|
|
sk_sp<SkSurface> fSurface;
|
|
};
|
|
|
|
void setup_test_context(Context* context,
|
|
skiatest::Reporter* reporter,
|
|
TestCtx* testCtx,
|
|
SkISize dimensions,
|
|
Volatile isVolatile,
|
|
bool invalidBackendTex) {
|
|
testCtx->fContext = context;
|
|
|
|
const Caps* caps = context->priv().caps();
|
|
testCtx->fRecorder = context->makeRecorder();
|
|
|
|
TextureInfo textureInfo = caps->getDefaultSampledTextureInfo(kRGBA_8888_SkColorType,
|
|
skgpu::Mipmapped::kNo,
|
|
skgpu::Protected::kNo,
|
|
Renderable::kYes);
|
|
|
|
if (invalidBackendTex) {
|
|
// Having invalid backend textures will invalidate all the fulfill calls
|
|
REPORTER_ASSERT(reporter, !testCtx->fBackendTextures[0].isValid());
|
|
REPORTER_ASSERT(reporter, !testCtx->fBackendTextures[1].isValid());
|
|
} else {
|
|
testCtx->fBackendTextures[0] = testCtx->fRecorder->createBackendTexture(dimensions,
|
|
textureInfo);
|
|
REPORTER_ASSERT(reporter, testCtx->fBackendTextures[0].isValid());
|
|
|
|
if (isVolatile == Volatile::kYes) {
|
|
testCtx->fBackendTextures[1] = testCtx->fRecorder->createBackendTexture(dimensions,
|
|
textureInfo);
|
|
REPORTER_ASSERT(reporter, testCtx->fBackendTextures[1].isValid());
|
|
}
|
|
}
|
|
|
|
if (isVolatile == Volatile::kYes) {
|
|
testCtx->fPromiseChecker = PromiseTextureChecker(testCtx->fBackendTextures[0],
|
|
testCtx->fBackendTextures[1],
|
|
reporter);
|
|
} else {
|
|
testCtx->fPromiseChecker = PromiseTextureChecker(testCtx->fBackendTextures[0],
|
|
reporter);
|
|
}
|
|
|
|
SkImageInfo ii = SkImageInfo::Make(dimensions.fWidth,
|
|
dimensions.fHeight,
|
|
kRGBA_8888_SkColorType,
|
|
kPremul_SkAlphaType);
|
|
|
|
testCtx->fImg = SkImage::MakeGraphitePromiseTexture(testCtx->fRecorder.get(),
|
|
dimensions,
|
|
textureInfo,
|
|
ii.colorInfo(),
|
|
isVolatile,
|
|
PromiseTextureChecker::Fulfill,
|
|
PromiseTextureChecker::ImageRelease,
|
|
PromiseTextureChecker::TextureRelease,
|
|
&testCtx->fPromiseChecker);
|
|
|
|
testCtx->fSurface = SkSurface::MakeGraphite(testCtx->fRecorder.get(), ii);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageTest,
|
|
reporter,
|
|
context) {
|
|
constexpr SkISize kDimensions { 16, 16 };
|
|
|
|
TestCtx testContext;
|
|
setup_test_context(context, reporter, &testContext,
|
|
kDimensions, Volatile::kNo, /* invalidBackendTex= */ false);
|
|
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter); // NVPIs not fulfilled at snap
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1); // NVPIs fulfilled at insert
|
|
}
|
|
|
|
context->submit(SyncToCpu::kNo);
|
|
// testContext.fImg still has a ref so we should not have called TextureRelease.
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
|
|
// Test that more draws and insertions don't refulfill the NVPI
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1); // No new fulfill
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
// testContext.fImg should still be fulfilled from the first time we inserted a Recording.
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
}
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
|
|
// Test that dropping the SkImage's ref doesn't change anything
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
testContext.fImg.reset();
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
}
|
|
|
|
// fImg's proxy is reffed by the recording so, despite fImg being reset earlier,
|
|
// the imageRelease callback doesn't occur until the recording is deleted.
|
|
testContext.fPromiseChecker.checkImageReleased(reporter, /* expectedReleaseCnt= */ 1);
|
|
|
|
// testContext.fImg no longer holds a ref but the last recording is still not submitted.
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
|
|
// Now TextureRelease should definitely have been called.
|
|
check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
|
|
}
|
|
|
|
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageFulfillFailureTest,
|
|
reporter,
|
|
context) {
|
|
constexpr SkISize kDimensions { 16, 16 };
|
|
|
|
TestCtx testContext;
|
|
setup_test_context(context, reporter, &testContext,
|
|
kDimensions, Volatile::kNo, /* invalidBackendTex= */ true);
|
|
|
|
// Draw the image a few different ways.
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
|
|
// Test that reinserting gives uninstantiated PromiseImages a second chance
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
|
|
}
|
|
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
SkPaint paint;
|
|
paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
|
|
canvas->drawImage(testContext.fImg, 0, 0, SkSamplingOptions(), &paint);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 3);
|
|
}
|
|
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
sk_sp<SkShader> shader = testContext.fImg->makeShader(SkSamplingOptions());
|
|
REPORTER_ASSERT(reporter, shader);
|
|
|
|
SkPaint paint;
|
|
paint.setShader(std::move(shader));
|
|
canvas->drawRect(SkRect::MakeWH(1, 1), paint);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 3);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
|
|
}
|
|
|
|
testContext.fSurface.reset();
|
|
testContext.fImg.reset();
|
|
|
|
// Despite fulfill failing 4x, the imageRelease callback still fires
|
|
testContext.fPromiseChecker.checkImageReleased(reporter, /* expectedReleaseCnt= */ 1);
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
// fulfill should've been called 4x while release should never have been called
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
|
|
}
|
|
|
|
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(NonVolatileGraphitePromiseImageCreationFailureTest,
|
|
reporter,
|
|
context) {
|
|
// Note: these dimensions are invalid and will cause MakeGraphitePromiseTexture to fail
|
|
constexpr SkISize kDimensions { 0, 0 };
|
|
|
|
TestCtx testContext;
|
|
setup_test_context(context, reporter, &testContext,
|
|
kDimensions, Volatile::kNo, /* invalidBackendTex= */ true);
|
|
|
|
SkASSERT(!testContext.fImg);
|
|
|
|
// Despite MakeGraphitePromiseTexture failing, ImageRelease is called
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fFulfillCount == 0);
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fImageReleaseCount == 1);
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.totalReleaseCount() == 0);
|
|
}
|
|
|
|
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphitePromiseImageTest,
|
|
reporter,
|
|
context) {
|
|
constexpr SkISize kDimensions { 16, 16 };
|
|
|
|
TestCtx testContext;
|
|
setup_test_context(context, reporter, &testContext,
|
|
kDimensions, Volatile::kYes, /* invalidBackendTex= */ false);
|
|
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
// Nothing happens at snap time for VPIs
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1); // VPIs fulfilled on insert
|
|
|
|
// Test that multiple insertions will clobber prior fulfills
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_two(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 2);
|
|
}
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
|
|
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[0] == 1);
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[1] == 1);
|
|
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
// Nothing happens at snap time for volatile images
|
|
check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 3);
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_two(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 4);
|
|
}
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
|
|
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[0] == 2);
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[1] == 2);
|
|
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
testContext.fImg.reset();
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
// Nothing happens at snap time for volatile images
|
|
check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_one(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 5);
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfilled_ahead_by_two(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 6);
|
|
}
|
|
|
|
// testContext.fImg no longer holds a ref but the last recordings are still not submitted.
|
|
check_fulfilled_ahead_by_two(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 6);
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
|
|
// Now all Releases should definitely have been called.
|
|
check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 6);
|
|
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[0] == 3);
|
|
REPORTER_ASSERT(reporter, testContext.fPromiseChecker.fTextureReleaseCounts[1] == 3);
|
|
}
|
|
|
|
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(VolatileGraphitePromiseImageFulfillFailureTest,
|
|
reporter,
|
|
context) {
|
|
constexpr SkISize kDimensions { 16, 16 };
|
|
|
|
TestCtx testContext;
|
|
setup_test_context(context, reporter, &testContext,
|
|
kDimensions, Volatile::kYes, /* invalidBackendTex= */ true);
|
|
|
|
// Draw the image a few different ways.
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
|
|
}
|
|
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
SkPaint paint;
|
|
paint.setColorFilter(SkColorFilters::LinearToSRGBGamma());
|
|
canvas->drawImage(testContext.fImg, 0, 0, SkSamplingOptions(), &paint);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 2);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 3);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
|
|
}
|
|
|
|
{
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
sk_sp<SkShader> shader = testContext.fImg->makeShader(SkSamplingOptions());
|
|
REPORTER_ASSERT(reporter, shader);
|
|
|
|
SkPaint paint;
|
|
paint.setShader(std::move(shader));
|
|
canvas->drawRect(SkRect::MakeWH(1, 1), paint);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 4);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 5);
|
|
|
|
REPORTER_ASSERT(reporter, !context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 6);
|
|
}
|
|
|
|
testContext.fSurface.reset();
|
|
testContext.fImg.reset();
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 6);
|
|
}
|
|
|
|
// Test out dropping the Recorder prior to inserting the Recording
|
|
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphitePromiseImageRecorderLoss,
|
|
reporter,
|
|
context) {
|
|
constexpr SkISize kDimensions{ 16, 16 };
|
|
|
|
for (Volatile isVolatile : { Volatile::kNo, Volatile::kYes }) {
|
|
TestCtx testContext;
|
|
setup_test_context(context, reporter, &testContext,
|
|
kDimensions, isVolatile, /* invalidBackendTex= */ false);
|
|
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
std::unique_ptr<Recording> recording = testContext.fRecorder->snap();
|
|
check_unfulfilled(testContext.fPromiseChecker, reporter);
|
|
|
|
testContext.fRecorder.reset(); // Recorder drop
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recording.get() }));
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
|
|
testContext.fSurface.reset();
|
|
testContext.fImg.reset();
|
|
recording.reset();
|
|
|
|
check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
|
|
}
|
|
}
|
|
|
|
// Test out PromiseImages appearing in multiple Recordings. In particular, test that
|
|
// previous instantiations don't impact the Recording's collection of PromiseImages.
|
|
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(GraphitePromiseImageMultipleImgUses,
|
|
reporter,
|
|
context) {
|
|
constexpr SkISize kDimensions{ 16, 16 };
|
|
|
|
static constexpr int kNumRecordings = 3;
|
|
|
|
for (Volatile isVolatile : { Volatile::kNo, Volatile::kYes }) {
|
|
int expectedVolatile = (isVolatile == Volatile::kYes) ? 1 : 0;
|
|
int expectedNonVolatile = 1 - expectedVolatile;
|
|
|
|
TestCtx testContext;
|
|
setup_test_context(context, reporter, &testContext,
|
|
kDimensions, isVolatile, /* invalidBackendTex= */ false);
|
|
|
|
std::unique_ptr<Recording> recordings[kNumRecordings];
|
|
|
|
SkCanvas* canvas = testContext.fSurface->getCanvas();
|
|
|
|
for (int i = 0; i < kNumRecordings; ++i) {
|
|
canvas->drawImage(testContext.fImg, 0, 0);
|
|
|
|
recordings[i] = testContext.fRecorder->snap();
|
|
|
|
if (isVolatile == Volatile::kYes) {
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ i);
|
|
} else {
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ i > 0 ? 1 : 0);
|
|
}
|
|
|
|
REPORTER_ASSERT(reporter,
|
|
recordings[i]->priv().numVolatilePromiseImages() == expectedVolatile);
|
|
REPORTER_ASSERT(reporter,
|
|
recordings[i]->priv().numNonVolatilePromiseImages() ==
|
|
expectedNonVolatile);
|
|
|
|
REPORTER_ASSERT(reporter, context->insertRecording({ recordings[i].get() }));
|
|
|
|
if (isVolatile == Volatile::kYes) {
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ i+1);
|
|
} else {
|
|
check_fulfills_only(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ 1);
|
|
}
|
|
|
|
// Non-volatiles are cleared out after a successful insertion
|
|
REPORTER_ASSERT(reporter, recordings[i]->priv().numNonVolatilePromiseImages() == 0);
|
|
}
|
|
|
|
context->submit(SyncToCpu::kYes);
|
|
|
|
testContext.fSurface.reset();
|
|
testContext.fImg.reset();
|
|
for (int i = 0; i < kNumRecordings; ++i) {
|
|
recordings[i].reset();
|
|
}
|
|
|
|
if (isVolatile == Volatile::kYes) {
|
|
check_all_done(reporter, testContext.fPromiseChecker,
|
|
/* expectedFulfillCnt= */ kNumRecordings);
|
|
} else {
|
|
check_all_done(reporter, testContext.fPromiseChecker, /* expectedFulfillCnt= */ 1);
|
|
}
|
|
}
|
|
}
|