2022-02-03 15:44:00 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2022 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "tests/Test.h"
|
|
|
|
|
|
|
|
#include "include/core/SkBitmap.h"
|
|
|
|
#include "include/core/SkCanvas.h"
|
2022-04-05 16:56:01 +00:00
|
|
|
#include "include/core/SkColorSpace.h"
|
2022-02-03 15:44:00 +00:00
|
|
|
#include "include/core/SkSurface.h"
|
2022-04-07 15:20:24 +00:00
|
|
|
#include "src/gpu/ganesh/GrCaps.h"
|
|
|
|
#include "src/gpu/ganesh/GrDirectContextPriv.h"
|
|
|
|
#include "src/gpu/ganesh/GrPixmap.h"
|
2022-02-03 15:44:00 +00:00
|
|
|
#include "tests/TestUtils.h"
|
|
|
|
#include "tools/gpu/ManagedBackendTexture.h"
|
|
|
|
|
|
|
|
using namespace sk_gpu_test;
|
|
|
|
|
|
|
|
bool check_pixels(skiatest::Reporter* reporter,
|
|
|
|
GrDirectContext* dContext,
|
|
|
|
const GrBackendTexture& tex,
|
|
|
|
const SkImageInfo& info,
|
|
|
|
SkColor expectedColor) {
|
|
|
|
// We have to do the readback of the backend texture wrapped in a different Skia surface than
|
|
|
|
// the one used in the main body of the test or else the readPixels call will trigger resolves
|
|
|
|
// itself.
|
|
|
|
sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(dContext,
|
|
|
|
tex,
|
|
|
|
kTopLeft_GrSurfaceOrigin,
|
|
|
|
/*sampleCnt=*/4,
|
|
|
|
kRGBA_8888_SkColorType,
|
|
|
|
nullptr, nullptr);
|
|
|
|
SkBitmap actual;
|
|
|
|
actual.allocPixels(info);
|
|
|
|
if (!surface->readPixels(actual, 0, 0)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkBitmap expected;
|
|
|
|
expected.allocPixels(info);
|
|
|
|
SkCanvas tmp(expected);
|
|
|
|
tmp.clear(expectedColor);
|
|
|
|
expected.setImmutable();
|
|
|
|
|
|
|
|
const float tols[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
|
|
|
|
|
|
auto error = std::function<ComparePixmapsErrorReporter>(
|
|
|
|
[reporter](int x, int y, const float diffs[4]) {
|
|
|
|
SkASSERT(x >= 0 && y >= 0);
|
|
|
|
ERRORF(reporter, "mismatch at %d, %d (%f, %f, %f %f)",
|
|
|
|
x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
|
|
|
|
});
|
|
|
|
|
|
|
|
return ComparePixels(expected.pixmap(), actual.pixmap(), tols, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceResolveTest, reporter, ctxInfo) {
|
|
|
|
auto dContext = ctxInfo.directContext();
|
|
|
|
|
|
|
|
SkImageInfo info = SkImageInfo::Make(8, 8, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
|
|
|
|
|
|
|
|
auto managedTex = ManagedBackendTexture::MakeFromInfo(dContext,
|
|
|
|
info,
|
|
|
|
GrMipmapped::kNo,
|
|
|
|
GrRenderable::kYes);
|
|
|
|
if (!managedTex) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto tex = managedTex->texture();
|
|
|
|
// Wrap the backend surface but tell it rendering with MSAA so that the wrapped texture is the
|
|
|
|
// resolve.
|
|
|
|
sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(dContext,
|
|
|
|
tex,
|
|
|
|
kTopLeft_GrSurfaceOrigin,
|
|
|
|
/*sampleCnt=*/4,
|
|
|
|
kRGBA_8888_SkColorType,
|
|
|
|
nullptr, nullptr);
|
|
|
|
|
|
|
|
if (!surface) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const GrCaps* caps = dContext->priv().caps();
|
|
|
|
// In metal and vulkan if we prefer discardable msaa attachments we will also auto resolve. The
|
|
|
|
// GrBackendTexture and SkSurface are set up in a way that is compatible with discardable msaa
|
|
|
|
// for both backends.
|
|
|
|
bool autoResolves = caps->msaaResolvesAutomatically() ||
|
|
|
|
caps->preferDiscardableMSAAAttachment();
|
|
|
|
|
|
|
|
// First do a simple test where we clear the surface than flush with SkSurface::flush. This
|
|
|
|
// should trigger the resolve and the texture should have the correct data.
|
|
|
|
surface->getCanvas()->clear(SK_ColorRED);
|
|
|
|
surface->flush();
|
|
|
|
dContext->submit();
|
|
|
|
REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorRED));
|
|
|
|
|
|
|
|
// Next try doing a GrDirectContext::flush which will not trigger a resolve on gpus without
|
|
|
|
// automatic msaa resolves.
|
|
|
|
surface->getCanvas()->clear(SK_ColorBLUE);
|
|
|
|
dContext->flush();
|
|
|
|
dContext->submit();
|
|
|
|
if (autoResolves) {
|
|
|
|
REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorBLUE));
|
|
|
|
} else {
|
|
|
|
REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorRED));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now doing a surface flush (even without any queued up normal work) should still resolve the
|
|
|
|
// surface.
|
|
|
|
surface->flush();
|
|
|
|
dContext->submit();
|
|
|
|
REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorBLUE));
|
|
|
|
|
|
|
|
// Test using SkSurface::resolve with a GrDirectContext::flush
|
|
|
|
surface->getCanvas()->clear(SK_ColorRED);
|
|
|
|
surface->resolveMSAA();
|
|
|
|
dContext->flush();
|
|
|
|
dContext->submit();
|
|
|
|
REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorRED));
|
|
|
|
|
|
|
|
// Calling resolve again should cause no issues as it is a no-op (there is an assert in the
|
|
|
|
// resolve op that the surface's msaa is dirty, we shouldn't hit that assert).
|
|
|
|
surface->resolveMSAA();
|
|
|
|
dContext->flush();
|
|
|
|
dContext->submit();
|
|
|
|
REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorRED));
|
|
|
|
|
|
|
|
// Try resolving in the middle of draw calls. Non automatic resolve gpus should only see the
|
|
|
|
// results of the first draw.
|
|
|
|
surface->getCanvas()->clear(SK_ColorGREEN);
|
|
|
|
surface->resolveMSAA();
|
|
|
|
surface->getCanvas()->clear(SK_ColorBLUE);
|
|
|
|
dContext->flush();
|
|
|
|
dContext->submit();
|
|
|
|
if (autoResolves) {
|
|
|
|
REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorBLUE));
|
|
|
|
} else {
|
|
|
|
REPORTER_ASSERT(reporter, check_pixels(reporter, dContext, tex, info, SK_ColorGREEN));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test that a resolve between draws to a different surface doesn't cause the OpsTasks for that
|
|
|
|
// surface to be split. Fails if we hit validation asserts in GrDrawingManager.
|
|
|
|
// First clear out dirty msaa from previous test
|
|
|
|
surface->flush();
|
|
|
|
|
|
|
|
auto otherSurface = SkSurface::MakeRenderTarget(dContext, SkBudgeted::kYes, info);
|
|
|
|
REPORTER_ASSERT(reporter, otherSurface);
|
|
|
|
otherSurface->getCanvas()->clear(SK_ColorRED);
|
|
|
|
surface->resolveMSAA();
|
|
|
|
otherSurface->getCanvas()->clear(SK_ColorBLUE);
|
|
|
|
dContext->flush();
|
|
|
|
dContext->submit();
|
2022-02-04 22:45:35 +00:00
|
|
|
|
|
|
|
// Make sure resolving a non-msaa surface doesn't trigger a resolve call. We'll hit an assert
|
|
|
|
// that the msaa is not dirty if it does.
|
|
|
|
REPORTER_ASSERT(reporter, otherSurface);
|
|
|
|
otherSurface->getCanvas()->clear(SK_ColorRED);
|
|
|
|
otherSurface->resolveMSAA();
|
|
|
|
dContext->flush();
|
|
|
|
dContext->submit();
|
2022-02-03 15:44:00 +00:00
|
|
|
}
|
|
|
|
|