|  | /* | 
|  | * Copyright 2021 Google LLC | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "include/core/SkAlphaType.h" | 
|  | #include "include/core/SkCanvas.h" | 
|  | #include "include/core/SkColor.h" | 
|  | #include "include/core/SkColorSpace.h" | 
|  | #include "include/core/SkColorType.h" | 
|  | #include "include/core/SkImage.h" | 
|  | #include "include/core/SkImageInfo.h" | 
|  | #include "include/core/SkRect.h" | 
|  | #include "include/core/SkRefCnt.h" | 
|  | #include "include/core/SkSamplingOptions.h" | 
|  | #include "include/core/SkSurface.h" | 
|  | #include "include/core/SkTypes.h" | 
|  | #include "include/gpu/GpuTypes.h" | 
|  | #include "include/gpu/GrDirectContext.h" | 
|  | #include "include/gpu/GrTypes.h" | 
|  | #include "include/private/SkColorData.h" | 
|  | #include "include/private/chromium/GrDeferredDisplayListRecorder.h" | 
|  | #include "include/private/chromium/GrSurfaceCharacterization.h" | 
|  | #include "include/private/gpu/ganesh/GrTypesPriv.h" | 
|  | #include "src/core/SkAutoPixmapStorage.h" | 
|  | #include "src/gpu/SkBackingFit.h" | 
|  | #include "src/gpu/ganesh/GrCanvas.h" | 
|  | #include "src/gpu/ganesh/GrDirectContextPriv.h" | 
|  | #include "src/gpu/ganesh/GrDrawingManager.h" | 
|  | #include "src/gpu/ganesh/GrImageInfo.h" | 
|  | #include "src/gpu/ganesh/GrRenderTargetProxy.h" | 
|  | #include "src/gpu/ganesh/GrRenderTask.h" | 
|  | #include "src/gpu/ganesh/GrSamplerState.h" | 
|  | #include "src/gpu/ganesh/GrSurfaceProxy.h" | 
|  | #include "src/gpu/ganesh/GrSurfaceProxyView.h" | 
|  | #include "src/gpu/ganesh/GrTextureProxy.h" | 
|  | #include "src/gpu/ganesh/SurfaceContext.h" | 
|  | #include "src/gpu/ganesh/SurfaceFillContext.h" | 
|  | #include "tests/CtsEnforcement.h" | 
|  | #include "tests/Test.h" | 
|  | #include "tests/TestUtils.h" | 
|  | #include "tools/gpu/BackendSurfaceFactory.h" | 
|  | #include "tools/gpu/ProxyUtils.h" | 
|  |  | 
|  | #include <functional> | 
|  | #include <memory> | 
|  |  | 
|  | struct GrContextOptions; | 
|  |  | 
|  | DEF_GANESH_TEST_FOR_ALL_CONTEXTS(WrappedSurfaceCopyOnWrite, | 
|  | reporter, | 
|  | ctxInfo, | 
|  | CtsEnforcement::kApiLevel_T) { | 
|  | GrDirectContext* dContext = ctxInfo.directContext(); | 
|  |  | 
|  | auto makeDirectBackendSurface = [&]() { | 
|  | auto info = SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType); | 
|  | return sk_gpu_test::MakeBackendTextureSurface(dContext, | 
|  | info, | 
|  | kTopLeft_GrSurfaceOrigin, | 
|  | /*sample count*/ 1); | 
|  | }; | 
|  |  | 
|  | auto imageProxyID = [&](const sk_sp<SkImage>& img) { | 
|  | return sk_gpu_test::GetTextureImageProxy(img.get(), dContext)->uniqueID(); | 
|  | }; | 
|  |  | 
|  | auto surfaceProxyID = [&](const sk_sp<SkSurface>& surf) { | 
|  | GrRenderTargetProxy* rtp = skgpu::ganesh::TopDeviceTargetProxy(surf->getCanvas()); | 
|  | return rtp->uniqueID(); | 
|  | }; | 
|  |  | 
|  | sk_sp<SkSurface> surf = makeDirectBackendSurface(); | 
|  | surf->getCanvas()->clear(SkColor4f{1, 0, 0, 1}); | 
|  | sk_sp<SkImage> img = surf->makeImageSnapshot(); | 
|  | // Initially they share | 
|  | REPORTER_ASSERT(reporter, surfaceProxyID(surf) == imageProxyID(img)); | 
|  | // Using the image on the direct context shouldn't affect sharing. | 
|  | sk_sp<SkSurface> surf2 = makeDirectBackendSurface(); | 
|  | surf2->getCanvas()->drawImage(img, 0, 0); | 
|  | REPORTER_ASSERT(reporter, surfaceProxyID(surf) == imageProxyID(img)); | 
|  | // Modifying the original surface should trigger using the copy proxy. | 
|  | surf->getCanvas()->clear({0, 0, 1, 1}); | 
|  | REPORTER_ASSERT(reporter, surfaceProxyID(surf) != imageProxyID(img)); | 
|  | // Image caching on surface should mean another snapshot gives us the same image. | 
|  | GrSurfaceProxy::UniqueID imageID = imageProxyID(img); | 
|  | img = surf->makeImageSnapshot(); | 
|  | REPORTER_ASSERT(reporter, imageProxyID(img) != imageID); | 
|  |  | 
|  | GrSurfaceCharacterization characterization; | 
|  | REPORTER_ASSERT(reporter, surf->characterize(&characterization)); | 
|  | GrDeferredDisplayListRecorder recorder(characterization); | 
|  |  | 
|  | // Using an image from a direct context on a recording context should trigger using the copy. | 
|  | surf = makeDirectBackendSurface(); | 
|  | img = surf->makeImageSnapshot(); | 
|  | REPORTER_ASSERT(reporter, surfaceProxyID(surf) == imageProxyID(img)); | 
|  | recorder.getCanvas()->drawImage(img, 0, 0); | 
|  | REPORTER_ASSERT(reporter, surfaceProxyID(surf) != imageProxyID(img)); | 
|  |  | 
|  | // Same as above but if the surface goes out of scope first we keep using the original | 
|  | surf = makeDirectBackendSurface(); | 
|  | img = surf->makeImageSnapshot(); | 
|  | GrSurfaceProxy::UniqueID surfID = surfaceProxyID(surf); | 
|  | REPORTER_ASSERT(reporter, surfaceProxyID(surf) == imageProxyID(img)); | 
|  | surf.reset(); | 
|  | recorder.getCanvas()->drawImage(img, 0, 0); | 
|  | REPORTER_ASSERT(reporter, surfID == imageProxyID(img)); | 
|  | } | 
|  |  | 
|  | // Make sure GrCopyRenderTasks's skip actually skips the copy. | 
|  | DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkipCopyTaskTest, | 
|  | reporter, | 
|  | ctxInfo, | 
|  | CtsEnforcement::kNever) { | 
|  | GrDirectContext* dContext = ctxInfo.directContext(); | 
|  |  | 
|  | GrImageInfo info(GrColorType::kRGBA_8888, | 
|  | kPremul_SkAlphaType, | 
|  | /*color space*/ nullptr, | 
|  | 10, 10); | 
|  |  | 
|  | auto dstSC = CreateSurfaceContext(dContext, | 
|  | info, | 
|  | SkBackingFit::kExact, | 
|  | kBottomLeft_GrSurfaceOrigin, | 
|  | GrRenderable::kYes); | 
|  | dstSC->asFillContext()->clear(SkPMColor4f{1, 0, 0, 1}); | 
|  |  | 
|  | auto srcSC = CreateSurfaceContext(dContext, | 
|  | info, | 
|  | SkBackingFit::kExact, | 
|  | kBottomLeft_GrSurfaceOrigin, | 
|  | GrRenderable::kYes); | 
|  | srcSC->asFillContext()->clear(SkPMColor4f{0, 0, 1, 1}); | 
|  |  | 
|  | sk_sp<GrRenderTask> task = | 
|  | dContext->priv().drawingManager()->newCopyRenderTask(dstSC->asSurfaceProxyRef(), | 
|  | SkIRect::MakeWH(10, 10), | 
|  | srcSC->asSurfaceProxyRef(), | 
|  | SkIRect::MakeWH(10, 10), | 
|  | GrSamplerState::Filter::kNearest, | 
|  | kTopLeft_GrSurfaceOrigin); | 
|  |  | 
|  | if (!task) { | 
|  | ERRORF(reporter, "Couldn't make a copy task."); | 
|  | return; | 
|  | } | 
|  |  | 
|  | task->makeSkippable(); | 
|  |  | 
|  | SkAutoPixmapStorage pixels; | 
|  | pixels.alloc(SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); | 
|  | dstSC->readPixels(dContext, pixels, {0, 0}); | 
|  | float kTol[4] = {}; | 
|  | std::function<ComparePixmapsErrorReporter> errorReporter( | 
|  | [&](int x, int y, const float diffs[4]) { | 
|  | ERRORF(reporter, "Expected {1, 0, 0, 1}. diff {%f, %f, %f, %f}", | 
|  | diffs[0], diffs[1], diffs[2], diffs[3]); | 
|  | }); | 
|  | CheckSolidPixels(SkColor4f{1, 0, 0, 1}, pixels, kTol, errorReporter); | 
|  | } | 
|  |  | 
|  | #if defined(SK_GANESH) | 
|  |  | 
|  | // Make sure OpsTask are skippable | 
|  | DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkipOpsTaskTest, reporter, ctxInfo, CtsEnforcement::kNever) { | 
|  | GrDirectContext* dContext = ctxInfo.directContext(); | 
|  |  | 
|  | GrImageInfo ii(GrColorType::kRGBA_8888, kPremul_SkAlphaType, /*color space*/ nullptr, 10, 10); | 
|  |  | 
|  | auto dst = dContext->priv().makeSFC(ii, /*label=*/{}, SkBackingFit::kExact); | 
|  | dst->clear(SkPMColor4f{1, 0, 0, 1}); | 
|  | dContext->flush(); | 
|  |  | 
|  | dst->clear(SkPMColor4f{0, 0, 1, 1}); | 
|  | sk_sp<GrRenderTask> task = dst->refRenderTask(); | 
|  |  | 
|  | // GrDrawingManager maintains an "active ops task" and doesn't like having it closed behind | 
|  | // its back. temp exists just to replace dst's ops task as the active one. | 
|  | auto temp = dContext->priv().makeSFC(ii, /*label=*/{}, SkBackingFit::kExact); | 
|  | temp->clear(SkPMColor4f{0, 0, 0, 0}); | 
|  |  | 
|  | GrSurfaceProxyView readView = dst->readSurfaceView(); | 
|  | task->makeSkippable(); | 
|  |  | 
|  | SkAutoPixmapStorage pixels; | 
|  | pixels.alloc(SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); | 
|  | dst->readPixels(dContext, pixels, {0, 0}); | 
|  | float kTol[4] = {}; | 
|  | std::function<ComparePixmapsErrorReporter> errorReporter( | 
|  | [&](int x, int y, const float diffs[4]) { | 
|  | ERRORF(reporter, "Expected {1, 0, 0, 1}. diff {%f, %f, %f, %f}", | 
|  | diffs[0], diffs[1], diffs[2], diffs[3]); | 
|  | }); | 
|  | CheckSolidPixels(SkColor4f{1, 0, 0, 1}, pixels, kTol, errorReporter); | 
|  | } | 
|  | #endif // defined(SK_GANESH) |