/* * Copyright 2019 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ // This is a Vulkan protected memory specific test. #include "include/core/SkTypes.h" #if defined(SK_VULKAN) #include "include/core/SkAlphaType.h" #include "include/core/SkBitmap.h" #include "include/core/SkBlendMode.h" #include "include/core/SkBlurTypes.h" #include "include/core/SkCanvas.h" #include "include/core/SkColor.h" #include "include/core/SkColorSpace.h" #include "include/core/SkColorType.h" #include "include/core/SkImageInfo.h" #include "include/core/SkMaskFilter.h" #include "include/core/SkPaint.h" #include "include/core/SkPath.h" #include "include/core/SkRect.h" #include "include/core/SkRefCnt.h" #include "include/core/SkSurface.h" #include "include/gpu/GpuTypes.h" #include "include/gpu/ganesh/GrTypes.h" #include "tests/CtsEnforcement.h" #include "tests/Test.h" #include "tools/gpu/vk/VkTestHelper.h" #if defined(SK_GANESH) #include "include/gpu/ganesh/GrBackendSurface.h" #include "include/gpu/ganesh/GrDirectContext.h" #include "include/gpu/ganesh/SkSurfaceGanesh.h" #endif #if defined(SK_GRAPHITE) #include "include/gpu/graphite/BackendTexture.h" #include "include/gpu/graphite/Context.h" #include "include/gpu/graphite/Recorder.h" #include "include/gpu/graphite/TextureInfo.h" #include "include/gpu/graphite/vk/VulkanGraphiteTypes.h" #endif #include #include struct GrContextOptions; static const int kSize = 8; namespace { void create_nonprotected_context(skiatest::Reporter* reporter, skiatest::TestType testType) { std::unique_ptr helper = VkTestHelper::Make(testType, /* isProtected= */ false); REPORTER_ASSERT(reporter, helper); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_CreateNonprotectedContext, reporter, options, CtsEnforcement::kNever) { create_nonprotected_context(reporter, skiatest::TestType::kGanesh); } #if defined(SK_GRAPHITE) DEF_GRAPHITE_TEST(VkProtectedContext_CreateNonprotectedContext_Graphite, reporter, CtsEnforcement::kNextRelease) { create_nonprotected_context(reporter, skiatest::TestType::kGraphite); } #endif DEF_GANESH_TEST(VkProtectedContext_CreateProtectedContext, reporter, options, CtsEnforcement::kNever) { std::unique_ptr helper = VkTestHelper::Make(skiatest::TestType::kGanesh, /* isProtected= */ true); } DEF_GRAPHITE_TEST(VkProtectedContext_CreateProtectedContext_Graphite, reporter, CtsEnforcement::kNextRelease) { std::unique_ptr helper = VkTestHelper::Make(skiatest::TestType::kGraphite, /* isProtected= */ true); } namespace { void create_protected_surface(skiatest::Reporter* reporter, skiatest::TestType testType) { std::unique_ptr helper = VkTestHelper::Make(testType, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp textureable = helper->createSurface({ kSize, kSize }, /* textureable= */ true, /* isProtected= */ true); REPORTER_ASSERT(reporter, textureable); sk_sp untextureable = helper->createSurface({ kSize, kSize }, /* textureable= */ false, /* isProtected= */ true); REPORTER_ASSERT(reporter, untextureable); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_CreateProtectedSkSurface, reporter, options, CtsEnforcement::kNever) { create_protected_surface(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_CreateProtectedSkSurface_Graphite, reporter, CtsEnforcement::kNextRelease) { create_protected_surface(reporter, skiatest::TestType::kGraphite); } namespace { void create_backend_texture_ganesh(skiatest::Reporter* reporter, bool contextIsProtected, bool beTexIsProtected) { std::unique_ptr helper = VkTestHelper::Make(skiatest::TestType::kGanesh, contextIsProtected); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); GrDirectContext* dContext = helper->directContext(); GrBackendTexture backendTex = dContext->createBackendTexture(kSize, kSize, kRGBA_8888_SkColorType, skgpu::Mipmapped::kNo, GrRenderable::kNo, GrProtected(beTexIsProtected)); REPORTER_ASSERT(reporter, backendTex.isValid() == (contextIsProtected == beTexIsProtected)); if (backendTex.isValid()) { REPORTER_ASSERT(reporter, backendTex.isProtected() == beTexIsProtected); } dContext->deleteBackendTexture(backendTex); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_CreateBackendTextures, reporter, options, CtsEnforcement::kNever) { for (bool contextIsProtected : { true, false }) { for (bool beTexIsProtected : { true, false }) { create_backend_texture_ganesh(reporter, contextIsProtected, beTexIsProtected); } } } #if defined(SK_GRAPHITE) namespace { void create_backend_texture_graphite(skiatest::Reporter* reporter, bool contextIsProtected, bool beTexIsProtected) { using namespace skgpu::graphite; std::unique_ptr helper = VkTestHelper::Make(skiatest::TestType::kGraphite, contextIsProtected); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); VulkanTextureInfo vkTextureInfo; vkTextureInfo.fFlags = beTexIsProtected ? VK_IMAGE_CREATE_PROTECTED_BIT : 0; vkTextureInfo.fFormat = VK_FORMAT_R8G8B8A8_UNORM; vkTextureInfo.fImageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; TextureInfo textureInfo = TextureInfos::MakeVulkan(vkTextureInfo); BackendTexture backendTex = helper->recorder()->createBackendTexture({ kSize, kSize }, textureInfo); REPORTER_ASSERT(reporter, backendTex.isValid() == (contextIsProtected == beTexIsProtected)); if (backendTex.isValid()) { REPORTER_ASSERT(reporter, backendTex.info().isProtected() == skgpu::Protected(beTexIsProtected)); } helper->recorder()->deleteBackendTexture(backendTex); } } // anonymous namespace DEF_GRAPHITE_TEST(VkProtectedContext_CreateBackendTextures_Graphite, reporter, CtsEnforcement::kNextRelease) { for (bool contextIsProtected : { true, false }) { for (bool beTexIsProtected : { true, false }) { create_backend_texture_graphite(reporter, contextIsProtected, beTexIsProtected); } } } #endif // SK_GRAPHITE DEF_GANESH_TEST(VkProtectedContext_ReadFromProtectedSurface, reporter, options, CtsEnforcement::kNever) { std::unique_ptr helper = VkTestHelper::Make(skiatest::TestType::kGanesh, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp surface = helper->createSurface({ kSize, kSize }, /* textureable= */ true, /* isProtected= */ true); REPORTER_ASSERT(reporter, surface); REPORTER_ASSERT(reporter, !surface->readPixels(SkImageInfo(), nullptr, 8, 0, 0)); } // Graphite does not perform Copy-on-Write which is why there is no DEF_GRAPHITE_TEST correlate DEF_GANESH_TEST(VkProtectedContext_CopyOnWrite, reporter, options, CtsEnforcement::kNever) { std::unique_ptr helper = VkTestHelper::Make(skiatest::TestType::kGanesh, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); GrDirectContext* dContext = helper->directContext(); SkImageInfo ii = SkImageInfo::Make({ kSize, kSize }, kRGBA_8888_SkColorType, kPremul_SkAlphaType); // We can't use VkTestHelper::createSurface here bc that will wrap a backend // texture which blocks the copy-on-write-behavior sk_sp surface = SkSurfaces::RenderTarget(dContext, skgpu::Budgeted::kNo, ii, /* sampleCount= */ 1, kBottomLeft_GrSurfaceOrigin, /* surfaceProps= */ nullptr, /* shouldCreateWithMips= */ false, /* isProtected= */ true); REPORTER_ASSERT(reporter, surface); SkCanvas* canvas = surface->getCanvas(); REPORTER_ASSERT(reporter, canvas); sk_sp imageBefore = surface->makeImageSnapshot(); REPORTER_ASSERT(reporter, imageBefore); REPORTER_ASSERT(reporter, imageBefore->isProtected()); SkPaint paint; paint.setColor(SK_ColorBLACK); canvas->drawRect(SkRect::MakeWH(4, 4), paint); sk_sp imageAfter = surface->makeImageSnapshot(); REPORTER_ASSERT(reporter, imageAfter); REPORTER_ASSERT(reporter, imageAfter->isProtected()); REPORTER_ASSERT(reporter, imageBefore != imageAfter); SkBitmap readback; readback.allocPixels(imageAfter->imageInfo()); REPORTER_ASSERT(reporter, !imageAfter->readPixels(dContext, readback.pixmap(), 0, 0)); } namespace { struct AsyncContext { bool fCalled = false; std::unique_ptr fResult; }; void async_callback(void* c, std::unique_ptr result) { auto context = static_cast(c); context->fResult = std::move(result); context->fCalled = true; } void async_read_from_protected_surface(skiatest::Reporter* reporter, skiatest::TestType testType) { std::unique_ptr helper = VkTestHelper::Make(testType, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp surface = helper->createSurface({ kSize, kSize }, /* textureable= */ true, /* isProtected= */ true); REPORTER_ASSERT(reporter, surface); AsyncContext cbContext; const SkImageInfo imageInfo = SkImageInfo::Make(6, 6, kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); if (testType == skiatest::TestType::kGanesh) { surface->asyncRescaleAndReadPixelsYUV420(kIdentity_SkYUVColorSpace, SkColorSpace::MakeSRGB(), imageInfo.bounds(), imageInfo.dimensions(), SkSurface::RescaleGamma::kSrc, SkSurface::RescaleMode::kNearest, &async_callback, &cbContext); } #if defined(SK_GRAPHITE) else { // Graphite deprecates SkSurface::asyncRescaleAndReadPixelsYUVA420 in favor of // Context::asyncRescaleAndReadPixelsYUV420. skgpu::graphite::Context* context = helper->context(); context->asyncRescaleAndReadPixelsYUV420(surface.get(), kIdentity_SkYUVColorSpace, SkColorSpace::MakeSRGB(), imageInfo.bounds(), imageInfo.dimensions(), SkSurface::RescaleGamma::kSrc, SkSurface::RescaleMode::kNearest, &async_callback, &cbContext); } #endif helper->submitAndWaitForCompletion(&cbContext.fCalled); REPORTER_ASSERT(reporter, !cbContext.fResult); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_AsyncReadFromProtectedSurface, reporter, options, CtsEnforcement::kNever) { async_read_from_protected_surface(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_AsyncReadFromProtectedSurface_Graphite, reporter, CtsEnforcement::kNextRelease) { async_read_from_protected_surface(reporter, skiatest::TestType::kGraphite); } namespace { void draw_rectangle(skiatest::Reporter* reporter, skiatest::TestType testType) { std::unique_ptr helper = VkTestHelper::Make(testType, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp surface = helper->createSurface({ kSize, kSize }, /* textureable= */ true, /* isProtected= */ true); REPORTER_ASSERT(reporter, surface); SkCanvas* canvas = surface->getCanvas(); REPORTER_ASSERT(reporter, canvas); SkPaint paint; paint.setColor(SK_ColorBLACK); canvas->drawRect(SkRect::MakeWH(4, 4), paint); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_DrawRectangle, reporter, options, CtsEnforcement::kNever) { draw_rectangle(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_DrawRectangle_Graphite, reporter, CtsEnforcement::kNextRelease) { draw_rectangle(reporter, skiatest::TestType::kGraphite); } namespace { void draw_rectangle_with_aa(skiatest::Reporter* reporter, skiatest::TestType testType) { std::unique_ptr helper = VkTestHelper::Make(testType, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp surface = helper->createSurface({ kSize, kSize }, /* textureable= */ true, /* isProtected= */ true); REPORTER_ASSERT(reporter, surface); SkCanvas* canvas = surface->getCanvas(); REPORTER_ASSERT(reporter, canvas); SkPaint paint; paint.setColor(SK_ColorBLACK); paint.setAntiAlias(true); canvas->drawRect(SkRect::MakeWH(4, 4), paint); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_DrawRectangleWithAntiAlias, reporter, options, CtsEnforcement::kNever) { draw_rectangle_with_aa(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_DrawRectangleWithAntiAlias_Graphite, reporter, CtsEnforcement::kNextRelease) { draw_rectangle_with_aa(reporter, skiatest::TestType::kGraphite); } namespace { void draw_rectangle_with_blendmode(skiatest::Reporter* reporter, skiatest::TestType testType) { std::unique_ptr helper = VkTestHelper::Make(testType, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp surface = helper->createSurface({ kSize, kSize }, /* textureable= */ true, /* isProtected= */ true); REPORTER_ASSERT(reporter, surface); SkCanvas* canvas = surface->getCanvas(); REPORTER_ASSERT(reporter, canvas); SkPaint paint; paint.setColor(SK_ColorBLACK); paint.setBlendMode(SkBlendMode::kColorDodge); canvas->drawRect(SkRect::MakeWH(4, 4), paint); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_DrawRectangleWithBlendMode, reporter, options, CtsEnforcement::kNever) { draw_rectangle_with_blendmode(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_DrawRectangleWithBlendMode_Graphite, reporter, CtsEnforcement::kNextRelease) { draw_rectangle_with_blendmode(reporter, skiatest::TestType::kGraphite); } namespace { void draw_rectangle_with_filter(skiatest::Reporter* reporter, skiatest::TestType testType) { std::unique_ptr helper = VkTestHelper::Make(testType, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp surface = helper->createSurface({ kSize, kSize }, /* textureable= */ true, /* isProtected= */ true); REPORTER_ASSERT(reporter, surface); SkCanvas* canvas = surface->getCanvas(); REPORTER_ASSERT(reporter, canvas); SkPaint paint; paint.setColor(SK_ColorBLACK); paint.setStyle(SkPaint::kFill_Style); paint.setMaskFilter(SkMaskFilter::MakeBlur(SkBlurStyle::kOuter_SkBlurStyle, 30.0f)); canvas->drawRect(SkRect::MakeWH(4, 4), paint); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_DrawRectangleWithFilter, reporter, options, CtsEnforcement::kNever) { draw_rectangle_with_filter(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_DrawRectangleWithFilter_Graphite, reporter, CtsEnforcement::kNextRelease) { draw_rectangle_with_filter(reporter, skiatest::TestType::kGraphite); } namespace { void draw_thin_path(skiatest::Reporter* reporter, skiatest::TestType testType) { constexpr bool kIsProtected = true; std::unique_ptr helper = VkTestHelper::Make(testType, kIsProtected); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp surface = helper->createSurface({ kSize, kSize }, /* textureable= */ true, kIsProtected); REPORTER_ASSERT(reporter, surface); SkCanvas* canvas = surface->getCanvas(); REPORTER_ASSERT(reporter, canvas); SkPaint paint; paint.setColor(SK_ColorBLACK); paint.setStyle(SkPaint::kStroke_Style); paint.setAntiAlias(true); paint.setStrokeWidth(.4f); canvas->drawPath(SkPath().moveTo(4, 4).lineTo(6, 6), paint); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_DrawThinPath, reporter, options, CtsEnforcement::kNever) { draw_thin_path(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_DrawThinPath_Graphite, reporter, CtsEnforcement::kNextRelease) { draw_thin_path(reporter, skiatest::TestType::kGraphite); } namespace { void save_layer(skiatest::Reporter* reporter, skiatest::TestType testType) { std::unique_ptr helper = VkTestHelper::Make(testType, /* isProtected= */ true); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); sk_sp surface = helper->createSurface({ kSize, kSize }, /* textureable= */ true, /* isProtected= */ true); REPORTER_ASSERT(reporter, surface); SkCanvas* canvas = surface->getCanvas(); REPORTER_ASSERT(reporter, canvas); canvas->saveLayer(nullptr, nullptr); SkPaint paint; paint.setColor(SK_ColorBLACK); canvas->drawRect(SkRect::MakeWH(4, 4), paint); canvas->restore(); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_SaveLayer, reporter, options, CtsEnforcement::kNever) { save_layer(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_SaveLayer_Graphite, reporter, CtsEnforcement::kNextRelease) { save_layer(reporter, skiatest::TestType::kGraphite); } namespace { void draw_protected_image_on_protected_surface(skiatest::Reporter* reporter, skiatest::TestType testType) { constexpr bool kIsProtected = true; std::unique_ptr helper = VkTestHelper::Make(testType, kIsProtected); if (!helper) { return; } REPORTER_ASSERT(reporter, helper->isValid()); // Create protected image. sk_sp surface1 = helper->createSurface({ kSize, kSize }, /* textureable= */ true, kIsProtected); REPORTER_ASSERT(reporter, surface1); sk_sp image = surface1->makeImageSnapshot(); REPORTER_ASSERT(reporter, image); REPORTER_ASSERT(reporter, image->isProtected() == kIsProtected); // Create protected canvas. sk_sp surface2 = helper->createSurface({ kSize, kSize }, /* textureable= */ true, kIsProtected); REPORTER_ASSERT(reporter, surface2); SkCanvas* canvas = surface2->getCanvas(); REPORTER_ASSERT(reporter, canvas); canvas->drawImage(image, 0, 0); } } // anonymous namespace DEF_GANESH_TEST(VkProtectedContext_DrawProtectedImageOnProtectedSurface, reporter, options, CtsEnforcement::kNever) { draw_protected_image_on_protected_surface(reporter, skiatest::TestType::kGanesh); } DEF_GRAPHITE_TEST(VkProtectedContext_DrawProtectedImageOnProtectedSurface_Graphite, reporter, CtsEnforcement::kNextRelease) { draw_protected_image_on_protected_surface(reporter, skiatest::TestType::kGraphite); } #endif // SK_VULKAN