blob: da82bffe6df52ae153af4ef1549d5e5bc624b7d8 [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tests/Test.h"
#if defined(SK_GANESH)
#include "include/core/SkBitmap.h"
#include "include/core/SkSurface.h"
#include "include/gpu/ganesh/SkImageGanesh.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
#include "src/gpu/ganesh/GrDirectContextPriv.h"
#include "tests/CtsEnforcement.h"
#include "tools/gpu/BackendSurfaceFactory.h"
#include "tools/gpu/BackendTextureImageFactory.h"
#ifdef SK_GL
#include "src/gpu/ganesh/gl/GrGLCaps.h"
#endif
#ifdef SK_VULKAN
#include "src/gpu/ganesh/vk/GrVkCaps.h"
#endif
namespace {
bool context_supports_protected(GrDirectContext* dContext) {
[[maybe_unused]] const GrCaps* caps = dContext->priv().caps();
#ifdef SK_GL
if (dContext->backend() == GrBackendApi::kOpenGL) {
const GrGLCaps* glCaps = static_cast<const GrGLCaps*>(caps);
return glCaps->supportsProtected();
}
#endif
#ifdef SK_VULKAN
if (dContext->backend() == GrBackendApi::kVulkan) {
const GrVkCaps* vkCaps = static_cast<const GrVkCaps*>(caps);
return vkCaps->supportsProtectedMemory();
}
#endif
if (dContext->backend() == GrBackendApi::kMock) {
return true;
}
// Metal, Dawn and D3D don't support protected textures
return false;
}
sk_sp<SkSurface> create_protected_sksurface(GrDirectContext* dContext,
skiatest::Reporter* reporter,
bool textureable,
bool isProtected) {
const int kW = 8;
const int kH = 8;
SkSurfaceProps surfaceProps = SkSurfaceProps(0, kRGB_H_SkPixelGeometry);
sk_sp<SkSurface> surface;
if (textureable) {
surface = sk_gpu_test::MakeBackendTextureSurface(dContext,
{kW, kH},
kTopLeft_GrSurfaceOrigin,
1,
kRGBA_8888_SkColorType,
/* colorSpace= */ nullptr,
GrMipmapped::kNo,
skgpu::Protected(isProtected),
&surfaceProps);
} else {
surface = sk_gpu_test::MakeBackendRenderTargetSurface(dContext,
{kW, kH},
kTopLeft_GrSurfaceOrigin,
1,
kRGBA_8888_SkColorType,
/* colorSpace= */ nullptr,
skgpu::Protected(isProtected),
&surfaceProps);
}
if (!surface) {
ERRORF(reporter, "Could not create %s surface.", isProtected ? "protected" : "unprotected");
return nullptr;
}
SkCanvas* canvas = surface->getCanvas();
canvas->clear(SkColors::kBlue);
if (textureable) {
GrBackendTexture backendTex = SkSurfaces::GetBackendTexture(
surface.get(), SkSurfaces::BackendHandleAccess::kFlushRead);
REPORTER_ASSERT(reporter, backendTex.isValid());
REPORTER_ASSERT(reporter, backendTex.isProtected() == isProtected);
} else {
GrBackendRenderTarget backendRT = SkSurfaces::GetBackendRenderTarget(
surface.get(), SkSurfaces::BackendHandleAccess::kFlushRead);
REPORTER_ASSERT(reporter, backendRT.isValid());
REPORTER_ASSERT(reporter, backendRT.isProtected() == isProtected);
}
return surface;
}
void check_image_be_protection(SkImage* image,
skiatest::Reporter* reporter,
bool expectingProtected) {
GrBackendTexture beTex;
GrSurfaceOrigin origin;
bool result = SkImages::GetBackendTextureFromImage(image,
&beTex,
true,
&origin);
if (!result) {
ERRORF(reporter, "GetBackendTextureFromImage failed");
return;
}
REPORTER_ASSERT(reporter, beTex.isValid());
REPORTER_ASSERT(reporter, beTex.isProtected() == expectingProtected);
}
sk_sp<SkImage> create_protected_skimage(GrDirectContext* dContext,
skiatest::Reporter* reporter,
SkColor4f color,
bool isProtected) {
const int kW = 8;
const int kH = 8;
SkImageInfo ii = SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
sk_sp<SkImage> image = sk_gpu_test::MakeBackendTextureImage(dContext,
ii,
color,
GrMipmapped::kNo,
GrRenderable::kNo,
kTopLeft_GrSurfaceOrigin,
skgpu::Protected(isProtected));
if (!image) {
ERRORF(reporter, "Could not create %s image.", isProtected ? "protected" : "unprotected");
return nullptr;
}
check_image_be_protection(image.get(), reporter, isProtected);
return image;
}
} // anonymous namespace
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_SmokeTest, reporter, ctxInfo, CtsEnforcement::kNever) {
auto dContext = ctxInfo.directContext();
if (!context_supports_protected(dContext)) {
// Protected content not supported
return;
}
for (bool textureable : { true, false }) {
for (bool isProtected : { true, false }) {
sk_sp<SkSurface> surface = create_protected_sksurface(dContext, reporter, textureable,
isProtected);
if (!surface) {
continue;
}
sk_sp<SkImage> image = surface->makeImageSnapshot();
if (!image) {
ERRORF(reporter, "Could not makeImageSnapshot from a %s surface.",
isProtected ? "protected" : "unprotected");
continue;
}
dContext->submit(/* syncCpu= */ true);
check_image_be_protection(image.get(), reporter, isProtected);
}
}
for (bool isProtected : { true, false }) {
create_protected_skimage(dContext, reporter, SkColors::kBlue, isProtected);
}
for (bool renderable : { true, false }) {
for (bool isProtected : { true, false }) {
GrBackendTexture beTex = dContext->createBackendTexture(16,
16,
kRGBA_8888_SkColorType,
SkColors::kTransparent,
GrMipmapped::kNo,
GrRenderable(renderable),
GrProtected(isProtected));
REPORTER_ASSERT(reporter, beTex.isValid());
REPORTER_ASSERT(reporter, beTex.isProtected() == isProtected);
}
}
}
// Verify that readPixels fails on protected surfaces
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_readPixelsFromSurfaces, reporter, ctxInfo,
CtsEnforcement::kNever) {
auto dContext = ctxInfo.directContext();
if (!context_supports_protected(dContext)) {
// Protected content not supported
return;
}
for (bool isProtected : { true, false }) {
sk_sp<SkSurface> surface = create_protected_sksurface(dContext, reporter,
/* textureable= */ true,
isProtected);
if (!surface) {
continue;
}
SkBitmap readback;
readback.allocPixels(surface->imageInfo());
REPORTER_ASSERT(reporter, isProtected != surface->readPixels(readback, 0, 0));
}
}
namespace {
struct AsyncContext {
bool fCalled = false;
std::unique_ptr<const SkSurface::AsyncReadResult> fResult;
};
static void async_callback(void* c, std::unique_ptr<const SkSurface::AsyncReadResult> result) {
auto context = static_cast<AsyncContext*>(c);
context->fResult = std::move(result);
context->fCalled = true;
}
} // anonymous namespace
// Verify that asyncRescaleAndReadPixels fails on protected surfaces
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(Protected_asyncRescaleAndReadPixelsFromSurfaces, reporter, ctxInfo,
CtsEnforcement::kNever) {
auto dContext = ctxInfo.directContext();
if (!context_supports_protected(dContext)) {
// Protected content not supported
return;
}
for (bool isProtected : { true, false }) {
sk_sp<SkSurface> surface = create_protected_sksurface(dContext, reporter,
/* textureable= */ true,
isProtected);
if (!surface) {
continue;
}
AsyncContext cbContext;
surface->asyncRescaleAndReadPixels(surface->imageInfo(),
SkIRect::MakeWH(surface->width(), surface->height()),
SkSurface::RescaleGamma::kSrc,
SkSurface::RescaleMode::kNearest,
async_callback, &cbContext);
dContext->submit();
while (!cbContext.fCalled) {
dContext->checkAsyncWorkCompletion();
}
REPORTER_ASSERT(reporter, isProtected != SkToBool(cbContext.fResult));
}
}
#endif // defined(SK_GANESH)