2021-03-05 19:00:07 +00:00
|
|
|
/*
|
|
|
|
* 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/SkDeferredDisplayListRecorder.h"
|
|
|
|
#include "include/core/SkImageInfo.h"
|
|
|
|
#include "include/gpu/GrDirectContext.h"
|
|
|
|
#include "include/gpu/GrTypes.h"
|
|
|
|
#include "src/core/SkAutoPixmapStorage.h"
|
|
|
|
#include "src/core/SkCanvasPriv.h"
|
2022-04-07 15:20:24 +00:00
|
|
|
#include "src/gpu/ganesh/GrDirectContextPriv.h"
|
|
|
|
#include "src/gpu/ganesh/GrProxyProvider.h"
|
|
|
|
#include "src/gpu/ganesh/GrSurfaceProxy.h"
|
|
|
|
#include "src/gpu/ganesh/SurfaceFillContext.h"
|
2021-03-05 19:00:07 +00:00
|
|
|
#include "tests/Test.h"
|
|
|
|
#include "tests/TestUtils.h"
|
|
|
|
#include "tools/gpu/BackendSurfaceFactory.h"
|
|
|
|
#include "tools/gpu/ProxyUtils.h"
|
|
|
|
|
|
|
|
DEF_GPUTEST_FOR_ALL_CONTEXTS(WrappedSurfaceCopyOnWrite, reporter, ctxInfo) {
|
|
|
|
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) {
|
2021-06-03 15:58:43 +00:00
|
|
|
GrRenderTargetProxy* rtp = SkCanvasPriv::TopDeviceTargetProxy(surf->getCanvas());
|
|
|
|
return rtp->uniqueID();
|
2021-03-05 19:00:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
SkSurfaceCharacterization characterization;
|
|
|
|
REPORTER_ASSERT(reporter, surf->characterize(&characterization));
|
|
|
|
SkDeferredDisplayListRecorder 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_GPUTEST_FOR_RENDERING_CONTEXTS(SkipCopyTaskTest, reporter, ctxInfo) {
|
|
|
|
GrDirectContext* dContext = ctxInfo.directContext();
|
|
|
|
|
2021-07-29 15:23:48 +00:00
|
|
|
GrImageInfo info(GrColorType::kRGBA_8888,
|
|
|
|
kPremul_SkAlphaType,
|
|
|
|
/*color space*/ nullptr,
|
|
|
|
10, 10);
|
2021-03-05 19:00:07 +00:00
|
|
|
|
2021-08-16 15:41:27 +00:00
|
|
|
auto dstSC = CreateSurfaceContext(dContext,
|
|
|
|
info,
|
|
|
|
SkBackingFit::kExact,
|
|
|
|
kBottomLeft_GrSurfaceOrigin,
|
|
|
|
GrRenderable::kYes);
|
2021-07-29 15:23:48 +00:00
|
|
|
dstSC->asFillContext()->clear(SkPMColor4f{1, 0, 0, 1});
|
|
|
|
|
2021-08-16 15:41:27 +00:00
|
|
|
auto srcSC = CreateSurfaceContext(dContext,
|
|
|
|
info,
|
|
|
|
SkBackingFit::kExact,
|
|
|
|
kBottomLeft_GrSurfaceOrigin,
|
|
|
|
GrRenderable::kYes);
|
2021-07-29 15:23:48 +00:00
|
|
|
srcSC->asFillContext()->clear(SkPMColor4f{0, 0, 1, 1});
|
2021-03-05 19:00:07 +00:00
|
|
|
|
|
|
|
sk_sp<GrRenderTask> task =
|
2021-07-29 15:23:48 +00:00
|
|
|
dContext->priv().drawingManager()->newCopyRenderTask(srcSC->asSurfaceProxyRef(),
|
2021-03-05 19:00:07 +00:00
|
|
|
SkIRect::MakeWH(10, 10),
|
2021-07-29 15:23:48 +00:00
|
|
|
dstSC->asSurfaceProxyRef(),
|
2021-03-05 19:00:07 +00:00
|
|
|
{0, 0},
|
|
|
|
kTopLeft_GrSurfaceOrigin);
|
|
|
|
|
|
|
|
if (!task) {
|
|
|
|
ERRORF(reporter, "Couldn't make a copy task.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-27 18:31:56 +00:00
|
|
|
task->makeSkippable();
|
2021-03-05 19:00:07 +00:00
|
|
|
|
|
|
|
SkAutoPixmapStorage pixels;
|
|
|
|
pixels.alloc(SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType));
|
2021-07-29 15:23:48 +00:00
|
|
|
dstSC->readPixels(dContext, pixels, {0, 0});
|
2021-03-05 19:00:07 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-07-29 15:23:48 +00:00
|
|
|
#if SK_GPU_V1
|
|
|
|
|
2021-08-25 17:22:24 +00:00
|
|
|
// Make sure OpsTask are skippable
|
2021-03-05 19:00:07 +00:00
|
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkipOpsTaskTest, reporter, ctxInfo) {
|
|
|
|
GrDirectContext* dContext = ctxInfo.directContext();
|
|
|
|
|
2021-08-11 13:31:00 +00:00
|
|
|
GrImageInfo ii(GrColorType::kRGBA_8888, kPremul_SkAlphaType, /*color space*/ nullptr, 10, 10);
|
|
|
|
|
|
|
|
auto dst = dContext->priv().makeSFC(ii, SkBackingFit::kExact);
|
2021-03-05 19:00:07 +00:00
|
|
|
dst->clear(SkPMColor4f{1, 0, 0, 1});
|
|
|
|
dContext->flush();
|
|
|
|
|
|
|
|
dst->clear(SkPMColor4f{0, 0, 1, 1});
|
2021-08-11 13:31:00 +00:00
|
|
|
sk_sp<GrRenderTask> task = dst->refRenderTask();
|
2021-03-05 19:00:07 +00:00
|
|
|
|
|
|
|
// 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.
|
2021-08-11 13:31:00 +00:00
|
|
|
auto temp = dContext->priv().makeSFC(ii, SkBackingFit::kExact);
|
2021-03-05 19:00:07 +00:00
|
|
|
temp->clear(SkPMColor4f{0, 0, 0, 0});
|
|
|
|
|
|
|
|
GrSurfaceProxyView readView = dst->readSurfaceView();
|
2021-04-27 18:31:56 +00:00
|
|
|
task->makeSkippable();
|
2021-03-05 19:00:07 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2021-07-29 15:23:48 +00:00
|
|
|
#endif // SK_GPU_V1
|