xref: /aosp_15_r20/external/skia/tests/SurfaceTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorFilter.h"
14 #include "include/core/SkColorPriv.h"
15 #include "include/core/SkColorSpace.h"
16 #include "include/core/SkColorType.h"
17 #include "include/core/SkFont.h"
18 #include "include/core/SkImage.h"
19 #include "include/core/SkImageInfo.h"
20 #include "include/core/SkOverdrawCanvas.h"
21 #include "include/core/SkPaint.h"
22 #include "include/core/SkPath.h"
23 #include "include/core/SkPixmap.h"
24 #include "include/core/SkPoint.h"
25 #include "include/core/SkRRect.h"
26 #include "include/core/SkRect.h"
27 #include "include/core/SkRefCnt.h"
28 #include "include/core/SkRegion.h"
29 #include "include/core/SkSamplingOptions.h"
30 #include "include/core/SkScalar.h"
31 #include "include/core/SkShader.h"
32 #include "include/core/SkSize.h"
33 #include "include/core/SkString.h"
34 #include "include/core/SkSurface.h"
35 #include "include/core/SkTypes.h"
36 #include "include/effects/SkColorMatrix.h"
37 #include "include/gpu/GpuTypes.h"
38 #include "include/gpu/ganesh/GrBackendSurface.h"
39 #include "include/gpu/ganesh/GrDirectContext.h"
40 #include "include/gpu/ganesh/GrTypes.h"
41 #include "include/gpu/ganesh/SkImageGanesh.h"
42 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
43 #include "include/private/SkColorData.h"
44 #include "include/private/base/SkDebug.h"
45 #include "include/private/base/SkFloatingPoint.h"
46 #include "include/private/base/SkMalloc.h"
47 #include "include/private/base/SkTo.h"
48 #include "include/private/gpu/ganesh/GrTypesPriv.h"
49 #include "src/core/SkAutoPixmapStorage.h"
50 #include "src/core/SkCanvasPriv.h"
51 #include "src/gpu/ganesh/Device.h"
52 #include "src/gpu/ganesh/GrCanvas.h"
53 #include "src/gpu/ganesh/GrCaps.h"
54 #include "src/gpu/ganesh/GrColorInfo.h"
55 #include "src/gpu/ganesh/GrDirectContextPriv.h"
56 #include "src/gpu/ganesh/GrGpu.h"
57 #include "src/gpu/ganesh/GrRenderTarget.h"
58 #include "src/gpu/ganesh/GrRenderTargetProxy.h"
59 #include "src/gpu/ganesh/GrResourceProvider.h"
60 #include "src/gpu/ganesh/GrTextureProxy.h"
61 #include "src/gpu/ganesh/SurfaceContext.h"
62 #include "src/gpu/ganesh/SurfaceFillContext.h"
63 #include "src/gpu/ganesh/image/GrImageUtils.h"
64 #include "src/gpu/ganesh/surface/SkSurface_Ganesh.h"
65 #include "src/image/SkImage_Base.h"
66 #include "tests/CtsEnforcement.h"
67 #include "tests/Test.h"
68 #include "tests/TestHarness.h"
69 #include "tools/RuntimeBlendUtils.h"
70 #include "tools/ToolUtils.h"
71 #include "tools/fonts/FontToolUtils.h"
72 #include "tools/gpu/BackendSurfaceFactory.h"
73 #include "tools/gpu/ManagedBackendTexture.h"
74 #include "tools/gpu/ProxyUtils.h"
75 
76 #include <cstddef>
77 #include <cstdint>
78 #include <initializer_list>
79 #include <limits>
80 #include <memory>
81 #include <utility>
82 
83 class GrRecordingContext;
84 struct GrContextOptions;
85 
release_direct_surface_storage(void * pixels,void * context)86 static void release_direct_surface_storage(void* pixels, void* context) {
87     SkASSERT(pixels == context);
88     sk_free(pixels);
89 }
create_surface(SkAlphaType at=kPremul_SkAlphaType,SkImageInfo * requestedInfo=nullptr)90 static sk_sp<SkSurface> create_surface(SkAlphaType at = kPremul_SkAlphaType,
91                                        SkImageInfo* requestedInfo = nullptr) {
92     const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
93     if (requestedInfo) {
94         *requestedInfo = info;
95     }
96     return SkSurfaces::Raster(info);
97 }
create_direct_surface(SkAlphaType at=kPremul_SkAlphaType,SkImageInfo * requestedInfo=nullptr)98 static sk_sp<SkSurface> create_direct_surface(SkAlphaType at = kPremul_SkAlphaType,
99                                               SkImageInfo* requestedInfo = nullptr) {
100     const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
101     if (requestedInfo) {
102         *requestedInfo = info;
103     }
104     const size_t rowBytes = info.minRowBytes();
105     void* storage = sk_malloc_throw(info.computeByteSize(rowBytes));
106     return SkSurfaces::WrapPixels(info, storage, rowBytes, release_direct_surface_storage, storage);
107 }
create_gpu_surface(GrRecordingContext * rContext,SkAlphaType at=kPremul_SkAlphaType,SkImageInfo * requestedInfo=nullptr)108 static sk_sp<SkSurface> create_gpu_surface(GrRecordingContext* rContext,
109                                            SkAlphaType at = kPremul_SkAlphaType,
110                                            SkImageInfo* requestedInfo = nullptr) {
111     const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
112     if (requestedInfo) {
113         *requestedInfo = info;
114     }
115     return SkSurfaces::RenderTarget(rContext, skgpu::Budgeted::kNo, info);
116 }
create_gpu_scratch_surface(GrRecordingContext * rContext,SkAlphaType at=kPremul_SkAlphaType,SkImageInfo * requestedInfo=nullptr)117 static sk_sp<SkSurface> create_gpu_scratch_surface(GrRecordingContext* rContext,
118                                                    SkAlphaType at = kPremul_SkAlphaType,
119                                                    SkImageInfo* requestedInfo = nullptr) {
120     const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
121     if (requestedInfo) {
122         *requestedInfo = info;
123     }
124     return SkSurfaces::RenderTarget(rContext, skgpu::Budgeted::kYes, info);
125 }
126 
DEF_TEST(SurfaceEmpty,reporter)127 DEF_TEST(SurfaceEmpty, reporter) {
128     const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
129     REPORTER_ASSERT(reporter, nullptr == SkSurfaces::Raster(info));
130     REPORTER_ASSERT(reporter, nullptr == SkSurfaces::WrapPixels(info, nullptr, 0));
131 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceEmpty_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)132 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceEmpty_Gpu,
133                                        reporter,
134                                        ctxInfo,
135                                        CtsEnforcement::kApiLevel_T) {
136     const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
137     REPORTER_ASSERT(reporter,
138                     nullptr == SkSurfaces::RenderTarget(
139                                        ctxInfo.directContext(), skgpu::Budgeted::kNo, info));
140 }
141 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsSurface,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)142 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsSurface,
143                                        reporter,
144                                        ctxInfo,
145                                        CtsEnforcement::kApiLevel_T) {
146     using namespace skgpu;
147 
148     auto context = ctxInfo.directContext();
149 
150     Protected isProtected = Protected(context->priv().caps()->supportsProtectedContent());
151 
152     for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) {
153         static constexpr int kSize = 10;
154 
155         SkColorType colorType = static_cast<SkColorType>(ct);
156         auto info = SkImageInfo::Make(kSize, kSize, colorType, kOpaque_SkAlphaType, nullptr);
157 
158         {
159             bool can = context->colorTypeSupportedAsSurface(colorType);
160             auto surf = SkSurfaces::RenderTarget(context, Budgeted::kYes, info, 1, nullptr);
161             REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
162                             colorType, can, SkToBool(surf));
163 
164             surf = sk_gpu_test::MakeBackendTextureSurface(context,
165                                                           {kSize, kSize},
166                                                           kTopLeft_GrSurfaceOrigin,
167                                                           /*sample cnt*/ 1,
168                                                           colorType,
169                                                           /* colorSpace= */ nullptr,
170                                                           Mipmapped::kNo,
171                                                           isProtected);
172             REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
173                             colorType, can, SkToBool(surf));
174         }
175 
176         // The MSAA test only makes sense if the colorType is renderable to begin with.
177         if (context->colorTypeSupportedAsSurface(colorType)) {
178             static constexpr int kSampleCnt = 2;
179 
180             bool can = context->maxSurfaceSampleCountForColorType(colorType) >= kSampleCnt;
181             auto surf = SkSurfaces::RenderTarget(
182                     context, Budgeted::kYes, info, kSampleCnt, nullptr);
183             REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
184                             colorType, can, SkToBool(surf));
185 
186             surf = sk_gpu_test::MakeBackendTextureSurface(
187                     context, {kSize, kSize}, kTopLeft_GrSurfaceOrigin, kSampleCnt, colorType,
188                     /* colorSpace= */ nullptr, Mipmapped::kNo, isProtected);
189             REPORTER_ASSERT(reporter, can == SkToBool(surf),
190                             "colorTypeSupportedAsSurface:%d, surf:%d, ct:%d", can, SkToBool(surf),
191                             colorType);
192             // Ensure that the sample count stored on the resulting SkSurface is a valid value.
193             if (surf) {
194                 auto rtp = skgpu::ganesh::TopDeviceTargetProxy(surf->getCanvas());
195                 int storedCnt = rtp->numSamples();
196                 const GrBackendFormat& format = rtp->backendFormat();
197                 int allowedCnt =
198                         context->priv().caps()->getRenderTargetSampleCount(storedCnt, format);
199                 REPORTER_ASSERT(reporter, storedCnt == allowedCnt,
200                                 "Should store an allowed sample count (%d vs %d)", allowedCnt,
201                                 storedCnt);
202             }
203         }
204 
205         for (int sampleCnt : {1, 2}) {
206             auto surf = sk_gpu_test::MakeBackendRenderTargetSurface(context,
207                                                                     {16, 16},
208                                                                     kTopLeft_GrSurfaceOrigin,
209                                                                     sampleCnt,
210                                                                     colorType,
211                                                                     /* colorSpace= */ nullptr,
212                                                                     isProtected);
213             bool can = context->colorTypeSupportedAsSurface(colorType) &&
214                        context->maxSurfaceSampleCountForColorType(colorType) >= sampleCnt;
215             if (!surf && can && colorType == kBGRA_8888_SkColorType && sampleCnt > 1 &&
216                 context->backend() == GrBackendApi::kOpenGL) {
217                 // This is an execeptional case. On iOS GLES we support MSAA BGRA for internally-
218                 // created render targets by using a MSAA RGBA8 renderbuffer that resolves to a
219                 // BGRA8 texture. However, the GL_APPLE_texture_format_BGRA8888 extension does not
220                 // allow creation of BGRA8 renderbuffers and we don't support multisampled textures.
221                 // So this is expected to fail. As of 10/5/2020 it actually seems to work to create
222                 // a MSAA BGRA8 renderbuffer (at least in the simulator) but we don't want to rely
223                 // on this undocumented behavior.
224                 continue;
225             }
226             REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, sc: %d, can: %d, surf: %d",
227                             colorType, sampleCnt, can, SkToBool(surf));
228             if (surf) {
229                 auto rtp = skgpu::ganesh::TopDeviceTargetProxy(surf->getCanvas());
230                 int storedCnt = rtp->numSamples();
231                 const GrBackendFormat& backendFormat = rtp->backendFormat();
232                 int allowedCnt = context->priv().caps()->getRenderTargetSampleCount(storedCnt,
233                                                                                     backendFormat);
234                 REPORTER_ASSERT(reporter, storedCnt == allowedCnt,
235                                 "Should store an allowed sample count (%d vs %d)", allowedCnt,
236                                 storedCnt);
237             }
238         }
239     }
240 }
241 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrContext_maxSurfaceSamplesForColorType,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)242 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrContext_maxSurfaceSamplesForColorType,
243                                        reporter,
244                                        ctxInfo,
245                                        CtsEnforcement::kApiLevel_T) {
246     using namespace skgpu;
247 
248     auto context = ctxInfo.directContext();
249 
250     Protected isProtected = Protected(context->priv().caps()->supportsProtectedContent());
251 
252     static constexpr int kSize = 10;
253 
254     for (int ct = 0; ct < kLastEnum_SkColorType; ++ct) {
255 
256         SkColorType colorType = static_cast<SkColorType>(ct);
257         int maxSampleCnt = context->maxSurfaceSampleCountForColorType(colorType);
258         if (!maxSampleCnt) {
259             continue;
260         }
261         if (!context->colorTypeSupportedAsSurface(colorType)) {
262             continue;
263         }
264 
265         auto info = SkImageInfo::Make(kSize, kSize, colorType, kOpaque_SkAlphaType, nullptr);
266         auto surf = sk_gpu_test::MakeBackendTextureSurface(
267                 context, info, kTopLeft_GrSurfaceOrigin, maxSampleCnt, Mipmapped::kNo, isProtected);
268         if (!surf) {
269             ERRORF(reporter, "Could not make surface of color type %d.", colorType);
270             continue;
271         }
272         int sampleCnt = ((SkSurface_Ganesh*)(surf.get()))->getDevice()->targetProxy()->numSamples();
273         REPORTER_ASSERT(reporter, sampleCnt == maxSampleCnt, "Exected: %d, actual: %d",
274                         maxSampleCnt, sampleCnt);
275     }
276 }
277 
test_canvas_peek(skiatest::Reporter * reporter,sk_sp<SkSurface> & surface,const SkImageInfo & requestInfo,bool expectPeekSuccess)278 static void test_canvas_peek(skiatest::Reporter* reporter,
279                              sk_sp<SkSurface>& surface,
280                              const SkImageInfo& requestInfo,
281                              bool expectPeekSuccess) {
282     const SkColor color = SK_ColorRED;
283     const SkPMColor pmcolor = SkPreMultiplyColor(color);
284     surface->getCanvas()->clear(color);
285 
286     SkPixmap pmap;
287     bool success = surface->getCanvas()->peekPixels(&pmap);
288     REPORTER_ASSERT(reporter, expectPeekSuccess == success);
289 
290     SkPixmap pmap2;
291     const void* addr2 = surface->peekPixels(&pmap2) ? pmap2.addr() : nullptr;
292 
293     if (success) {
294         REPORTER_ASSERT(reporter, requestInfo == pmap.info());
295         REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= pmap.rowBytes());
296         REPORTER_ASSERT(reporter, pmcolor == *pmap.addr32());
297 
298         REPORTER_ASSERT(reporter, pmap.addr() == pmap2.addr());
299         REPORTER_ASSERT(reporter, pmap.info() == pmap2.info());
300         REPORTER_ASSERT(reporter, pmap.rowBytes() == pmap2.rowBytes());
301     } else {
302         REPORTER_ASSERT(reporter, nullptr == addr2);
303     }
304 }
DEF_TEST(SurfaceCanvasPeek,reporter)305 DEF_TEST(SurfaceCanvasPeek, reporter) {
306     for (auto& surface_func : { &create_surface, &create_direct_surface }) {
307         SkImageInfo requestInfo;
308         auto surface(surface_func(kPremul_SkAlphaType, &requestInfo));
309         test_canvas_peek(reporter, surface, requestInfo, true);
310     }
311 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceCanvasPeek_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)312 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceCanvasPeek_Gpu,
313                                        reporter,
314                                        ctxInfo,
315                                        CtsEnforcement::kApiLevel_T) {
316     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
317         SkImageInfo requestInfo;
318         auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, &requestInfo));
319         test_canvas_peek(reporter, surface, requestInfo, false);
320     }
321 }
322 
test_snapshot_alphatype(skiatest::Reporter * reporter,const sk_sp<SkSurface> & surface,SkAlphaType expectedAlphaType)323 static void test_snapshot_alphatype(skiatest::Reporter* reporter, const sk_sp<SkSurface>& surface,
324                                     SkAlphaType expectedAlphaType) {
325     REPORTER_ASSERT(reporter, surface);
326     if (surface) {
327         sk_sp<SkImage> image(surface->makeImageSnapshot());
328         REPORTER_ASSERT(reporter, image);
329         if (image) {
330             REPORTER_ASSERT(reporter, image->alphaType() == expectedAlphaType);
331         }
332     }
333 }
DEF_TEST(SurfaceSnapshotAlphaType,reporter)334 DEF_TEST(SurfaceSnapshotAlphaType, reporter) {
335     for (auto& surface_func : { &create_surface, &create_direct_surface }) {
336         for (auto& at: { kOpaque_SkAlphaType, kPremul_SkAlphaType, kUnpremul_SkAlphaType }) {
337             auto surface(surface_func(at, nullptr));
338             test_snapshot_alphatype(reporter, surface, at);
339         }
340     }
341 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceSnapshotAlphaType_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)342 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceSnapshotAlphaType_Gpu,
343                                        reporter,
344                                        ctxInfo,
345                                        CtsEnforcement::kApiLevel_T) {
346     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
347         // GPU doesn't support creating unpremul surfaces, so only test opaque + premul
348         for (auto& at : { kOpaque_SkAlphaType, kPremul_SkAlphaType }) {
349             auto surface(surface_func(ctxInfo.directContext(), at, nullptr));
350             test_snapshot_alphatype(reporter, surface, at);
351         }
352     }
353 }
354 
test_backend_texture_access_copy_on_write(skiatest::Reporter * reporter,SkSurface * surface,SkSurface::BackendHandleAccess access)355 static void test_backend_texture_access_copy_on_write(
356     skiatest::Reporter* reporter, SkSurface* surface, SkSurface::BackendHandleAccess access) {
357     GrBackendTexture tex1 = SkSurfaces::GetBackendTexture(surface, access);
358     sk_sp<SkImage> snap1(surface->makeImageSnapshot());
359 
360     GrBackendTexture tex2 = SkSurfaces::GetBackendTexture(surface, access);
361     sk_sp<SkImage> snap2(surface->makeImageSnapshot());
362 
363     // If the access mode triggers CoW, then the backend objects should reflect it.
364     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(tex1, tex2) == (snap1 == snap2));
365 }
366 
test_backend_rendertarget_access_copy_on_write(skiatest::Reporter * reporter,SkSurface * surface,SkSurface::BackendHandleAccess access)367 static void test_backend_rendertarget_access_copy_on_write(
368     skiatest::Reporter* reporter, SkSurface* surface, SkSurface::BackendHandleAccess access) {
369     GrBackendRenderTarget rt1 = SkSurfaces::GetBackendRenderTarget(surface, access);
370     sk_sp<SkImage> snap1(surface->makeImageSnapshot());
371 
372     GrBackendRenderTarget rt2 = SkSurfaces::GetBackendRenderTarget(surface, access);
373     sk_sp<SkImage> snap2(surface->makeImageSnapshot());
374 
375     // If the access mode triggers CoW, then the backend objects should reflect it.
376     REPORTER_ASSERT(reporter, GrBackendRenderTarget::TestingOnly_Equals(rt1, rt2) ==
377                               (snap1 == snap2));
378 }
379 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceBackendSurfaceAccessCopyOnWrite_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)380 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceBackendSurfaceAccessCopyOnWrite_Gpu,
381                                        reporter,
382                                        ctxInfo,
383                                        CtsEnforcement::kApiLevel_T) {
384     const SkSurfaces::BackendHandleAccess accessModes[] = {
385             SkSurfaces::BackendHandleAccess::kFlushRead,
386             SkSurfaces::BackendHandleAccess::kFlushWrite,
387             SkSurfaces::BackendHandleAccess::kDiscardWrite,
388     };
389 
390     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
391         for (auto& accessMode : accessModes) {
392             {
393                 auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
394                 test_backend_texture_access_copy_on_write(reporter, surface.get(), accessMode);
395             }
396             {
397                 auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
398                 test_backend_rendertarget_access_copy_on_write(reporter, surface.get(), accessMode);
399             }
400         }
401     }
402 }
403 
404 template <typename Type, Type (*func)(SkSurface*, SkSurface::BackendHandleAccess)>
test_backend_unique_id(skiatest::Reporter * reporter,SkSurface * surface)405 static void test_backend_unique_id(skiatest::Reporter* reporter, SkSurface* surface) {
406     sk_sp<SkImage> image0(surface->makeImageSnapshot());
407 
408     Type obj = func(surface, SkSurfaces::BackendHandleAccess::kFlushRead);
409     REPORTER_ASSERT(reporter, obj.isValid());
410     sk_sp<SkImage> image1(surface->makeImageSnapshot());
411     // just read access should not affect the snapshot
412     REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID());
413 
414     obj = func(surface, SkSurfaces::BackendHandleAccess::kFlushWrite);
415     REPORTER_ASSERT(reporter, obj.isValid());
416     sk_sp<SkImage> image2(surface->makeImageSnapshot());
417     // expect a new image, since we claimed we would write
418     REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID());
419 
420     obj = func(surface, SkSurfaces::BackendHandleAccess::kDiscardWrite);
421     REPORTER_ASSERT(reporter, obj.isValid());
422     sk_sp<SkImage> image3(surface->makeImageSnapshot());
423     // expect a new(er) image, since we claimed we would write
424     REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID());
425     REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID());
426 }
427 
428 // No CPU test.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessIDs_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)429 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessIDs_Gpu,
430                                        reporter,
431                                        ctxInfo,
432                                        CtsEnforcement::kApiLevel_T) {
433     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
434         {
435             auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
436             test_backend_unique_id<GrBackendTexture, &SkSurfaces::GetBackendTexture>(reporter,
437                                                                                      surface.get());
438         }
439         {
440             auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
441             test_backend_unique_id<GrBackendRenderTarget, &SkSurfaces::GetBackendRenderTarget>(
442                     reporter, surface.get());
443         }
444     }
445 }
446 
447 // No CPU test.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceAbandonPostFlush_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)448 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceAbandonPostFlush_Gpu,
449                                        reporter,
450                                        ctxInfo,
451                                        CtsEnforcement::kApiLevel_T) {
452     auto direct = ctxInfo.directContext();
453     sk_sp<SkSurface> surface = create_gpu_surface(direct, kPremul_SkAlphaType, nullptr);
454     if (!surface) {
455         return;
456     }
457     // This flush can put command buffer refs on the GrGpuResource for the surface.
458     direct->flush(surface.get());
459     direct->abandonContext();
460     // We pass the test if we don't hit any asserts or crashes when the ref on the surface goes away
461     // after we abanonded the context. One thing specifically this checks is to make sure we're
462     // correctly handling the mix of normal refs and command buffer refs, and correctly deleting
463     // the object at the right time.
464 }
465 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceBackendAccessAbandoned_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)466 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceBackendAccessAbandoned_Gpu,
467                                        reporter,
468                                        ctxInfo,
469                                        CtsEnforcement::kApiLevel_T) {
470     auto dContext = ctxInfo.directContext();
471     sk_sp<SkSurface> surface = create_gpu_surface(dContext, kPremul_SkAlphaType, nullptr);
472     if (!surface) {
473         return;
474     }
475 
476     GrBackendRenderTarget beRT = SkSurfaces::GetBackendRenderTarget(
477             surface.get(), SkSurfaces::BackendHandleAccess::kFlushRead);
478     REPORTER_ASSERT(reporter, beRT.isValid());
479     GrBackendTexture beTex = SkSurfaces::GetBackendTexture(
480             surface.get(), SkSurfaces::BackendHandleAccess::kFlushRead);
481     REPORTER_ASSERT(reporter, beTex.isValid());
482 
483     dContext->flush(surface.get());
484     dContext->abandonContext();
485 
486     // After abandoning the context none of the backend surfaces should be valid.
487     beRT = SkSurfaces::GetBackendRenderTarget(surface.get(),
488                                               SkSurfaces::BackendHandleAccess::kFlushRead);
489     REPORTER_ASSERT(reporter, !beRT.isValid());
490     beTex = SkSurfaces::GetBackendTexture(surface.get(),
491                                           SkSurfaces::BackendHandleAccess::kFlushRead);
492     REPORTER_ASSERT(reporter, !beTex.isValid());
493 }
494 
495 // Verify that the right canvas commands trigger a copy on write.
test_copy_on_write(skiatest::Reporter * reporter,SkSurface * surface)496 static void test_copy_on_write(skiatest::Reporter* reporter, SkSurface* surface) {
497     SkCanvas* canvas = surface->getCanvas();
498 
499     const SkRect testRect =
500         SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
501                          SkIntToScalar(4), SkIntToScalar(5));
502     SkPath testPath;
503     testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
504                                       SkIntToScalar(2), SkIntToScalar(1)));
505 
506     const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
507 
508     SkRegion testRegion;
509     testRegion.setRect(testIRect);
510 
511 
512     const SkColor testColor = 0x01020304;
513     const SkPaint testPaint;
514     const SkPoint testPoints[3] = {
515         {SkIntToScalar(0), SkIntToScalar(0)},
516         {SkIntToScalar(2), SkIntToScalar(1)},
517         {SkIntToScalar(0), SkIntToScalar(2)}
518     };
519     const size_t testPointCount = 3;
520 
521     SkBitmap testBitmap;
522     testBitmap.allocN32Pixels(10, 10);
523     testBitmap.eraseColor(0);
524 
525     SkRRect testRRect;
526     testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1);
527 
528     SkString testText("Hello World");
529 
530 #define EXPECT_COPY_ON_WRITE(command)                               \
531     {                                                               \
532         sk_sp<SkImage> imageBefore = surface->makeImageSnapshot();  \
533         sk_sp<SkImage> aur_before(imageBefore);  /*NOLINT*/         \
534         canvas-> command ;                                          \
535         sk_sp<SkImage> imageAfter = surface->makeImageSnapshot();   \
536         sk_sp<SkImage> aur_after(imageAfter);  /*NOLINT*/           \
537         REPORTER_ASSERT(reporter, imageBefore != imageAfter);       \
538     }
539 
540     EXPECT_COPY_ON_WRITE(clear(testColor))
541     EXPECT_COPY_ON_WRITE(drawPaint(testPaint))
542     EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \
543         testPaint))
544     EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint))
545     EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint))
546     EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint))
547     EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint))
548     EXPECT_COPY_ON_WRITE(drawImage(testBitmap.asImage(), 0, 0))
549     EXPECT_COPY_ON_WRITE(drawImageRect(testBitmap.asImage(), testRect, SkSamplingOptions()))
550     EXPECT_COPY_ON_WRITE(drawString(testText, 0, 1, ToolUtils::DefaultPortableFont(), testPaint))
551 }
DEF_TEST(SurfaceCopyOnWrite,reporter)552 DEF_TEST(SurfaceCopyOnWrite, reporter) {
553     test_copy_on_write(reporter, create_surface().get());
554 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceCopyOnWrite_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)555 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceCopyOnWrite_Gpu,
556                                        reporter,
557                                        ctxInfo,
558                                        CtsEnforcement::kApiLevel_T) {
559     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
560         auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
561         test_copy_on_write(reporter, surface.get());
562     }
563 }
564 
test_writable_after_snapshot_release(skiatest::Reporter * reporter,SkSurface * surface)565 static void test_writable_after_snapshot_release(skiatest::Reporter* reporter,
566                                                  SkSurface* surface) {
567     // This test succeeds by not triggering an assertion.
568     // The test verifies that the surface remains writable (usable) after
569     // acquiring and releasing a snapshot without triggering a copy on write.
570     SkCanvas* canvas = surface->getCanvas();
571     canvas->clear(1);
572     surface->makeImageSnapshot();  // Create and destroy SkImage
573     canvas->clear(2);  // Must not assert internally
574 }
DEF_TEST(SurfaceWriteableAfterSnapshotRelease,reporter)575 DEF_TEST(SurfaceWriteableAfterSnapshotRelease, reporter) {
576     test_writable_after_snapshot_release(reporter, create_surface().get());
577 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceWriteableAfterSnapshotRelease_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)578 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceWriteableAfterSnapshotRelease_Gpu,
579                                        reporter,
580                                        ctxInfo,
581                                        CtsEnforcement::kApiLevel_T) {
582     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
583         auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
584         test_writable_after_snapshot_release(reporter, surface.get());
585     }
586 }
587 
test_crbug263329(skiatest::Reporter * reporter,SkSurface * surface1,SkSurface * surface2)588 static void test_crbug263329(skiatest::Reporter* reporter,
589                              SkSurface* surface1,
590                              SkSurface* surface2) {
591     // This is a regression test for crbug.com/263329
592     // Bug was caused by onCopyOnWrite releasing the old surface texture
593     // back to the scratch texture pool even though the texture is used
594     // by and active SkImage_Ganesh.
595     SkCanvas* canvas1 = surface1->getCanvas();
596     SkCanvas* canvas2 = surface2->getCanvas();
597     canvas1->clear(1);
598     sk_sp<SkImage> image1(surface1->makeImageSnapshot());
599     // Trigger copy on write, new backing is a scratch texture
600     canvas1->clear(2);
601     sk_sp<SkImage> image2(surface1->makeImageSnapshot());
602     // Trigger copy on write, old backing should not be returned to scratch
603     // pool because it is held by image2
604     canvas1->clear(3);
605 
606     canvas2->clear(4);
607     sk_sp<SkImage> image3(surface2->makeImageSnapshot());
608     // Trigger copy on write on surface2. The new backing store should not
609     // be recycling a texture that is held by an existing image.
610     canvas2->clear(5);
611     sk_sp<SkImage> image4(surface2->makeImageSnapshot());
612 
613     auto imageProxy = [ctx = surface1->recordingContext()](SkImage* img) {
614         GrTextureProxy* proxy = sk_gpu_test::GetTextureImageProxy(img, ctx);
615         SkASSERT(proxy);
616         return proxy;
617     };
618 
619     REPORTER_ASSERT(reporter, imageProxy(image4.get()) != imageProxy(image3.get()));
620     // The following assertion checks crbug.com/263329
621     REPORTER_ASSERT(reporter, imageProxy(image4.get()) != imageProxy(image2.get()));
622     REPORTER_ASSERT(reporter, imageProxy(image4.get()) != imageProxy(image1.get()));
623     REPORTER_ASSERT(reporter, imageProxy(image3.get()) != imageProxy(image2.get()));
624     REPORTER_ASSERT(reporter, imageProxy(image3.get()) != imageProxy(image1.get()));
625     REPORTER_ASSERT(reporter, imageProxy(image2.get()) != imageProxy(image1.get()));
626 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceCRBug263329_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)627 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceCRBug263329_Gpu,
628                                        reporter,
629                                        ctxInfo,
630                                        CtsEnforcement::kApiLevel_T) {
631     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
632         auto surface1(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
633         auto surface2(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
634         test_crbug263329(reporter, surface1.get(), surface2.get());
635     }
636 }
637 
DEF_TEST(SurfaceGetTexture,reporter)638 DEF_TEST(SurfaceGetTexture, reporter) {
639     auto surface(create_surface());
640     sk_sp<SkImage> image(surface->makeImageSnapshot());
641     REPORTER_ASSERT(reporter, !as_IB(image)->isTextureBacked());
642     surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
643     REPORTER_ASSERT(reporter, !as_IB(image)->isTextureBacked());
644 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfacepeekTexture_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)645 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfacepeekTexture_Gpu,
646                                        reporter,
647                                        ctxInfo,
648                                        CtsEnforcement::kApiLevel_T) {
649     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
650         auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
651         sk_sp<SkImage> image(surface->makeImageSnapshot());
652 
653         REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked());
654         GrBackendTexture backendTex;
655         bool ok = SkImages::GetBackendTextureFromImage(image, &backendTex, false);
656         REPORTER_ASSERT(reporter, ok);
657         REPORTER_ASSERT(reporter, backendTex.isValid());
658         surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
659         REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked());
660         GrBackendTexture backendTex2;
661         ok = SkImages::GetBackendTextureFromImage(image, &backendTex2, false);
662         REPORTER_ASSERT(reporter, ok);
663         REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(backendTex, backendTex2));
664     }
665 }
666 
is_budgeted(const sk_sp<SkSurface> & surf)667 static skgpu::Budgeted is_budgeted(const sk_sp<SkSurface>& surf) {
668     SkSurface_Ganesh* gsurf = (SkSurface_Ganesh*)surf.get();
669 
670     GrRenderTargetProxy* proxy = gsurf->getDevice()->targetProxy();
671     return proxy->isBudgeted();
672 }
673 
is_budgeted(SkImage * image,GrRecordingContext * rc)674 static skgpu::Budgeted is_budgeted(SkImage* image, GrRecordingContext* rc) {
675     return sk_gpu_test::GetTextureImageProxy(image, rc)->isBudgeted();
676 }
677 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceBudget,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)678 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceBudget,
679                                        reporter,
680                                        ctxInfo,
681                                        CtsEnforcement::kApiLevel_T) {
682     SkImageInfo info = SkImageInfo::MakeN32Premul(8,8);
683     GrDirectContext* dContext = ctxInfo.directContext();
684     for (auto budgeted : {skgpu::Budgeted::kNo, skgpu::Budgeted::kYes}) {
685         auto surface(SkSurfaces::RenderTarget(dContext, budgeted, info));
686         SkASSERT(surface);
687         REPORTER_ASSERT(reporter, budgeted == is_budgeted(surface));
688 
689         sk_sp<SkImage> image(surface->makeImageSnapshot());
690 
691         // Initially the image shares a texture with the surface, and the
692         // the budgets should always match.
693         REPORTER_ASSERT(reporter, budgeted == is_budgeted(surface));
694         REPORTER_ASSERT(reporter, budgeted == is_budgeted(image.get(), dContext));
695 
696         // Now trigger copy-on-write
697         surface->getCanvas()->clear(SK_ColorBLUE);
698 
699         // They don't share a texture anymore but the budgets should still match.
700         REPORTER_ASSERT(reporter, budgeted == is_budgeted(surface));
701         REPORTER_ASSERT(reporter, budgeted == is_budgeted(image.get(), dContext));
702     }
703 }
704 
test_no_canvas1(skiatest::Reporter * reporter,SkSurface * surface,SkSurface::ContentChangeMode mode)705 static void test_no_canvas1(skiatest::Reporter* reporter,
706                             SkSurface* surface,
707                             SkSurface::ContentChangeMode mode) {
708     // Test passes by not asserting
709     surface->notifyContentWillChange(mode);
710 }
test_no_canvas2(skiatest::Reporter * reporter,SkSurface * surface,SkSurface::ContentChangeMode mode)711 static void test_no_canvas2(skiatest::Reporter* reporter,
712                             SkSurface* surface,
713                             SkSurface::ContentChangeMode mode) {
714     // Verifies the robustness of SkSurface for handling use cases where calls
715     // are made before a canvas is created.
716     sk_sp<SkImage> image1 = surface->makeImageSnapshot();
717     sk_sp<SkImage> aur_image1(image1);  // NOLINT(performance-unnecessary-copy-initialization)
718     surface->notifyContentWillChange(mode);
719     sk_sp<SkImage> image2 = surface->makeImageSnapshot();
720     sk_sp<SkImage> aur_image2(image2);  // NOLINT(performance-unnecessary-copy-initialization)
721     REPORTER_ASSERT(reporter, image1 != image2);
722 }
DEF_TEST(SurfaceNoCanvas,reporter)723 DEF_TEST(SurfaceNoCanvas, reporter) {
724     SkSurface::ContentChangeMode modes[] =
725             { SkSurface::kDiscard_ContentChangeMode, SkSurface::kRetain_ContentChangeMode};
726     for (auto& test_func : { &test_no_canvas1, &test_no_canvas2 }) {
727         for (auto& mode : modes) {
728             test_func(reporter, create_surface().get(), mode);
729         }
730     }
731 }
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceNoCanvas_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)732 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceNoCanvas_Gpu,
733                                        reporter,
734                                        ctxInfo,
735                                        CtsEnforcement::kApiLevel_T) {
736     SkSurface::ContentChangeMode modes[] =
737             { SkSurface::kDiscard_ContentChangeMode, SkSurface::kRetain_ContentChangeMode};
738     for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
739         for (auto& test_func : { &test_no_canvas1, &test_no_canvas2 }) {
740             for (auto& mode : modes) {
741                 auto surface(surface_func(ctxInfo.directContext(), kPremul_SkAlphaType, nullptr));
742                 test_func(reporter, surface.get(), mode);
743             }
744         }
745     }
746 }
747 
check_rowbytes_remain_consistent(SkSurface * surface,skiatest::Reporter * reporter)748 static void check_rowbytes_remain_consistent(SkSurface* surface, skiatest::Reporter* reporter) {
749     SkPixmap surfacePM;
750     REPORTER_ASSERT(reporter, surface->peekPixels(&surfacePM));
751 
752     sk_sp<SkImage> image(surface->makeImageSnapshot());
753     SkPixmap pm;
754     REPORTER_ASSERT(reporter, image->peekPixels(&pm));
755 
756     REPORTER_ASSERT(reporter, surfacePM.rowBytes() == pm.rowBytes());
757 
758     // trigger a copy-on-write
759     surface->getCanvas()->drawPaint(SkPaint());
760     sk_sp<SkImage> image2(surface->makeImageSnapshot());
761     REPORTER_ASSERT(reporter, image->uniqueID() != image2->uniqueID());
762 
763     SkPixmap pm2;
764     REPORTER_ASSERT(reporter, image2->peekPixels(&pm2));
765     REPORTER_ASSERT(reporter, pm2.rowBytes() == pm.rowBytes());
766 }
767 
DEF_TEST(surface_rowbytes,reporter)768 DEF_TEST(surface_rowbytes, reporter) {
769     const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
770 
771     auto surf0(SkSurfaces::Raster(info));
772     check_rowbytes_remain_consistent(surf0.get(), reporter);
773 
774     // specify a larger rowbytes
775     auto surf1(SkSurfaces::Raster(info, 500, nullptr));
776     check_rowbytes_remain_consistent(surf1.get(), reporter);
777 
778     // Try some illegal rowByte values
779     auto s = SkSurfaces::Raster(info, 396, nullptr);  // needs to be at least 400
780     REPORTER_ASSERT(reporter, nullptr == s);
781     s = SkSurfaces::Raster(info, std::numeric_limits<size_t>::max(), nullptr);
782     REPORTER_ASSERT(reporter, nullptr == s);
783 }
784 
DEF_TEST(surface_raster_zeroinitialized,reporter)785 DEF_TEST(surface_raster_zeroinitialized, reporter) {
786     sk_sp<SkSurface> s(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)));
787     SkPixmap pixmap;
788     REPORTER_ASSERT(reporter, s->peekPixels(&pixmap));
789 
790     for (int i = 0; i < pixmap.info().width(); ++i) {
791         for (int j = 0; j < pixmap.info().height(); ++j) {
792             REPORTER_ASSERT(reporter, *pixmap.addr32(i, j) == 0);
793         }
794     }
795 }
796 
create_gpu_surface_backend_texture(GrDirectContext * dContext,int sampleCnt,const SkColor4f & color)797 static sk_sp<SkSurface> create_gpu_surface_backend_texture(GrDirectContext* dContext,
798                                                            int sampleCnt,
799                                                            const SkColor4f& color) {
800     // On Pixel and Pixel2XL's with Adreno 530 and 540s, setting width and height to 10s reliably
801     // triggers what appears to be a driver race condition where the 10x10 surface from the
802     // OverdrawSurface_gpu test is reused(?) for this surface created by the SurfacePartialDraw_gpu
803     // test.
804     //
805     // Immediately after creation of this surface, readback shows the correct initial solid color.
806     // However, sometime before content is rendered into the upper half of the surface, the driver
807     // presumably cleans up the OverdrawSurface_gpu's memory which corrupts this color buffer. The
808     // top half of the surface is fine after the partially-covering rectangle is drawn, but the
809     // untouched bottom half contains random pixel values that trigger asserts in the
810     // SurfacePartialDraw_gpu test for no longer matching the initial color. Running the
811     // SurfacePartialDraw_gpu test without the OverdrawSurface_gpu test completes successfully.
812     //
813     // Requesting a much larger backend texture size seems to prevent it from reusing the same
814     // memory and avoids the issue.
815     const SkISize kSize = CurrentTestHarnessIsSkQP() ? SkISize{10, 10} : SkISize{100, 100};
816 
817     auto surf = sk_gpu_test::MakeBackendTextureSurface(dContext,
818                                                        kSize,
819                                                        kTopLeft_GrSurfaceOrigin,
820                                                        sampleCnt,
821                                                        kRGBA_8888_SkColorType);
822     if (!surf) {
823         return nullptr;
824     }
825     surf->getCanvas()->clear(color);
826     return surf;
827 }
828 
supports_readpixels(const GrCaps * caps,SkSurface * surface)829 static bool supports_readpixels(const GrCaps* caps, SkSurface* surface) {
830     auto surfaceGpu = static_cast<SkSurface_Ganesh*>(surface);
831     GrRenderTarget* rt = surfaceGpu->getDevice()->targetProxy()->peekRenderTarget();
832     if (!rt) {
833         return false;
834     }
835     return caps->surfaceSupportsReadPixels(rt) == GrCaps::SurfaceReadPixelsSupport::kSupported;
836 }
837 
create_gpu_surface_backend_render_target(GrDirectContext * dContext,int sampleCnt,const SkColor4f & color)838 static sk_sp<SkSurface> create_gpu_surface_backend_render_target(GrDirectContext* dContext,
839                                                                  int sampleCnt,
840                                                                  const SkColor4f& color) {
841     const int kWidth = 10;
842     const int kHeight = 10;
843 
844     auto surf = sk_gpu_test::MakeBackendRenderTargetSurface(dContext,
845                                                             {kWidth, kHeight},
846                                                             kTopLeft_GrSurfaceOrigin,
847                                                             sampleCnt,
848                                                             kRGBA_8888_SkColorType);
849     if (!surf) {
850         return nullptr;
851     }
852     surf->getCanvas()->clear(color);
853     return surf;
854 }
855 
test_surface_context_clear(skiatest::Reporter * reporter,GrDirectContext * dContext,skgpu::ganesh::SurfaceContext * surfaceContext,uint32_t expectedValue)856 static void test_surface_context_clear(skiatest::Reporter* reporter,
857                                        GrDirectContext* dContext,
858                                        skgpu::ganesh::SurfaceContext* surfaceContext,
859                                        uint32_t expectedValue) {
860     int w = surfaceContext->width();
861     int h = surfaceContext->height();
862 
863     SkImageInfo ii = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
864 
865     SkAutoPixmapStorage readback;
866     readback.alloc(ii);
867 
868     readback.erase(~expectedValue);
869     surfaceContext->readPixels(dContext, readback, {0, 0});
870     for (int y = 0; y < h; ++y) {
871         for (int x = 0; x < w; ++x) {
872             uint32_t pixel = readback.addr32()[y * w + x];
873             if (pixel != expectedValue) {
874                 SkString msg;
875                 if (expectedValue) {
876                     msg = "SkSurface should have left render target unmodified";
877                 } else {
878                     msg = "SkSurface should have cleared the render target";
879                 }
880                 ERRORF(reporter,
881                        "%s but read 0x%08X (instead of 0x%08X) at %d,%d", msg.c_str(), pixel,
882                        expectedValue, x, y);
883                 return;
884             }
885         }
886     }
887 }
888 
DEF_GANESH_TEST_FOR_GL_CONTEXT(SurfaceClear_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)889 DEF_GANESH_TEST_FOR_GL_CONTEXT(SurfaceClear_Gpu, reporter, ctxInfo, CtsEnforcement::kApiLevel_T) {
890     auto dContext = ctxInfo.directContext();
891     // Snaps an image from a surface and then makes a SurfaceContext from the image's texture.
892     auto makeImageSurfaceContext = [dContext](SkSurface* surface) {
893         sk_sp<SkImage> i(surface->makeImageSnapshot());
894         auto [view, ct] = skgpu::ganesh::AsView(dContext, i, skgpu::Mipmapped::kNo);
895         GrColorInfo colorInfo(ct, i->alphaType(), i->refColorSpace());
896         return dContext->priv().makeSC(view, std::move(colorInfo));
897     };
898 
899     // Test that non-wrapped RTs are created clear.
900     for (auto& surface_func : {&create_gpu_surface, &create_gpu_scratch_surface}) {
901         auto surface = surface_func(dContext, kPremul_SkAlphaType, nullptr);
902         if (!surface) {
903             ERRORF(reporter, "Could not create GPU SkSurface.");
904             return;
905         }
906         auto sfc = skgpu::ganesh::TopDeviceSurfaceFillContext(surface->getCanvas());
907         if (!sfc) {
908             ERRORF(reporter, "Could access surface context of GPU SkSurface.");
909             return;
910         }
911         test_surface_context_clear(reporter, dContext, sfc, 0x0);
912         auto imageSurfaceCtx = makeImageSurfaceContext(surface.get());
913         test_surface_context_clear(reporter, dContext, imageSurfaceCtx.get(), 0x0);
914     }
915 
916     // Wrapped RTs are *not* supposed to clear (to allow client to partially update a surface).
917     const SkColor4f kOrigColor{.67f, .67f, .67f, 1};
918     for (auto& surfaceFunc :
919          {&create_gpu_surface_backend_texture, &create_gpu_surface_backend_render_target}) {
920         auto surface = surfaceFunc(dContext, 1, kOrigColor);
921         if (!surface) {
922             ERRORF(reporter, "Could not create GPU SkSurface.");
923             return;
924         }
925         auto sfc = skgpu::ganesh::TopDeviceSurfaceFillContext(surface->getCanvas());
926         if (!sfc) {
927             ERRORF(reporter, "Could access surface context of GPU SkSurface.");
928             return;
929         }
930         test_surface_context_clear(reporter, dContext, sfc, kOrigColor.toSkColor());
931         auto imageSurfaceCtx = makeImageSurfaceContext(surface.get());
932         test_surface_context_clear(reporter, dContext, imageSurfaceCtx.get(),
933                                    kOrigColor.toSkColor());
934     }
935 }
936 
test_surface_draw_partially(skiatest::Reporter * reporter,sk_sp<SkSurface> surface,SkColor origColor)937 static void test_surface_draw_partially(
938     skiatest::Reporter* reporter, sk_sp<SkSurface> surface, SkColor origColor) {
939     const int kW = surface->width();
940     const int kH = surface->height();
941     SkPaint paint;
942     const SkColor kRectColor = ~origColor | 0xFF000000;
943     paint.setColor(kRectColor);
944     surface->getCanvas()->drawRect(SkRect::MakeIWH(kW, kH/2), paint);
945 
946     // Read back RGBA to avoid format conversions that may not be supported on all platforms.
947     SkImageInfo readInfo = SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
948 
949     SkAutoPixmapStorage readback;
950     readback.alloc(readInfo);
951 
952     readback.erase(~origColor);
953     REPORTER_ASSERT(reporter, surface->readPixels(readback.info(), readback.writable_addr(),
954                                                   readback.rowBytes(), 0, 0));
955     bool stop = false;
956 
957     SkPMColor origColorPM = SkPackARGB_as_RGBA(SkColorGetA(origColor),
958                                                SkColorGetR(origColor),
959                                                SkColorGetG(origColor),
960                                                SkColorGetB(origColor));
961     SkPMColor rectColorPM = SkPackARGB_as_RGBA(SkColorGetA(kRectColor),
962                                                SkColorGetR(kRectColor),
963                                                SkColorGetG(kRectColor),
964                                                SkColorGetB(kRectColor));
965 
966     for (int y = 0; y < kH/2 && !stop; ++y) {
967        for (int x = 0; x < kW && !stop; ++x) {
968             REPORTER_ASSERT(reporter, rectColorPM == readback.addr32()[x + y * kW]);
969             if (rectColorPM != readback.addr32()[x + y * kW]) {
970                 SkDebugf("--- got [%x] expected [%x], x = %d, y = %d\n",
971                          readback.addr32()[x + y * kW], rectColorPM, x, y);
972                 stop = true;
973             }
974         }
975     }
976     stop = false;
977     for (int y = kH/2; y < kH && !stop; ++y) {
978         for (int x = 0; x < kW && !stop; ++x) {
979             REPORTER_ASSERT(reporter, origColorPM == readback.addr32()[x + y * kW]);
980             if (origColorPM != readback.addr32()[x + y * kW]) {
981                 SkDebugf("--- got [%x] expected [%x], x = %d, y = %d\n",
982                          readback.addr32()[x + y * kW], origColorPM, x, y);
983                 stop = true;
984             }
985         }
986     }
987 }
988 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfacePartialDraw_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)989 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfacePartialDraw_Gpu,
990                                        reporter,
991                                        ctxInfo,
992                                        CtsEnforcement::kApiLevel_T) {
993     auto context = ctxInfo.directContext();
994 
995     static const SkColor4f kOrigColor { 0.667f, 0.733f, 0.8f, 1 };
996 
997     for (auto& surfaceFunc :
998          {&create_gpu_surface_backend_texture, &create_gpu_surface_backend_render_target}) {
999         // Validate that we can draw to the canvas and that the original texture color is
1000         // preserved in pixels that aren't rendered to via the surface.
1001         // This works only for non-multisampled case.
1002         auto surface = surfaceFunc(context, 1, kOrigColor);
1003         if (surface && supports_readpixels(context->priv().caps(), surface.get())) {
1004             test_surface_draw_partially(reporter, surface, kOrigColor.toSkColor());
1005         }
1006     }
1007 }
1008 
1009 struct ReleaseChecker {
ReleaseCheckerReleaseChecker1010     ReleaseChecker() : fReleaseCount(0) {}
1011     int fReleaseCount;
ReleaseReleaseChecker1012     static void Release(void* self) {
1013         static_cast<ReleaseChecker*>(self)->fReleaseCount++;
1014     }
1015 };
1016 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceWrappedWithRelease_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1017 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceWrappedWithRelease_Gpu,
1018                                        reporter,
1019                                        ctxInfo,
1020                                        CtsEnforcement::kApiLevel_T) {
1021     const int kWidth = 10;
1022     const int kHeight = 10;
1023 
1024     auto ctx = ctxInfo.directContext();
1025     GrGpu* gpu = ctx->priv().getGpu();
1026 
1027     for (bool useTexture : {false, true}) {
1028         sk_sp<sk_gpu_test::ManagedBackendTexture> mbet;
1029         GrBackendRenderTarget backendRT;
1030         sk_sp<SkSurface> surface;
1031 
1032         ReleaseChecker releaseChecker;
1033         GrSurfaceOrigin texOrigin = kBottomLeft_GrSurfaceOrigin;
1034 
1035         if (useTexture) {
1036             SkImageInfo ii = SkImageInfo::Make(kWidth, kHeight, SkColorType::kRGBA_8888_SkColorType,
1037                                                kPremul_SkAlphaType);
1038             mbet = sk_gpu_test::ManagedBackendTexture::MakeFromInfo(
1039                     ctx, ii, skgpu::Mipmapped::kNo, GrRenderable::kYes);
1040             if (!mbet) {
1041                 continue;
1042             }
1043 
1044             surface = SkSurfaces::WrapBackendTexture(
1045                     ctx,
1046                     mbet->texture(),
1047                     texOrigin,
1048                     /*sample count*/ 1,
1049                     kRGBA_8888_SkColorType,
1050                     /*color space*/ nullptr,
1051                     /*surface props*/ nullptr,
1052                     sk_gpu_test::ManagedBackendTexture::ReleaseProc,
1053                     mbet->releaseContext(ReleaseChecker::Release, &releaseChecker));
1054         } else {
1055             backendRT = gpu->createTestingOnlyBackendRenderTarget({kWidth, kHeight},
1056                                                                   GrColorType::kRGBA_8888);
1057             if (!backendRT.isValid()) {
1058                 continue;
1059             }
1060             surface = SkSurfaces::WrapBackendRenderTarget(ctx,
1061                                                           backendRT,
1062                                                           texOrigin,
1063                                                           kRGBA_8888_SkColorType,
1064                                                           nullptr,
1065                                                           nullptr,
1066                                                           ReleaseChecker::Release,
1067                                                           &releaseChecker);
1068         }
1069         if (!surface) {
1070             ERRORF(reporter, "Failed to create surface");
1071             continue;
1072         }
1073 
1074         surface->getCanvas()->clear(SK_ColorRED);
1075         ctx->flush(surface.get());
1076         ctx->submit(GrSyncCpu::kYes);
1077 
1078         // Now exercise the release proc
1079         REPORTER_ASSERT(reporter, 0 == releaseChecker.fReleaseCount);
1080         surface.reset(nullptr); // force a release of the surface
1081         REPORTER_ASSERT(reporter, 1 == releaseChecker.fReleaseCount);
1082 
1083         if (!useTexture) {
1084             gpu->deleteTestingOnlyBackendRenderTarget(backendRT);
1085         }
1086     }
1087 }
1088 
DEF_GANESH_TEST_FOR_GL_CONTEXT(SurfaceAttachStencil_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1089 DEF_GANESH_TEST_FOR_GL_CONTEXT(SurfaceAttachStencil_Gpu,
1090                                reporter,
1091                                ctxInfo,
1092                                CtsEnforcement::kApiLevel_T) {
1093     auto context = ctxInfo.directContext();
1094     const GrCaps* caps = context->priv().caps();
1095 
1096     if (caps->avoidStencilBuffers()) {
1097         return;
1098     }
1099 
1100     static const SkColor4f kOrigColor { 0.667f, 0.733f, 0.8f, 1 };
1101 
1102     auto resourceProvider = context->priv().resourceProvider();
1103 
1104     for (auto& surfaceFunc :
1105          {&create_gpu_surface_backend_texture, &create_gpu_surface_backend_render_target}) {
1106         for (int sampleCnt : {1, 4, 8}) {
1107             auto surface = surfaceFunc(context, sampleCnt, kOrigColor);
1108 
1109             if (!surface && sampleCnt > 1) {
1110                 // Certain platforms don't support MSAA, skip these.
1111                 continue;
1112             }
1113 
1114             // Validate that we can attach a stencil buffer to an SkSurface created by either of
1115             // our surface functions.
1116             auto rtp = skgpu::ganesh::TopDeviceTargetProxy(surface->getCanvas());
1117             GrRenderTarget* rt = rtp->peekRenderTarget();
1118             REPORTER_ASSERT(reporter,
1119                             resourceProvider->attachStencilAttachment(rt, rt->numSamples() > 1));
1120         }
1121     }
1122 }
1123 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ReplaceSurfaceBackendTexture,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1124 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ReplaceSurfaceBackendTexture,
1125                                        reporter,
1126                                        ctxInfo,
1127                                        CtsEnforcement::kApiLevel_T) {
1128     auto context = ctxInfo.directContext();
1129 
1130     for (int sampleCnt : {1, 2}) {
1131         auto ii = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
1132         auto mbet1 = sk_gpu_test::ManagedBackendTexture::MakeFromInfo(
1133                 context, ii, skgpu::Mipmapped::kNo, GrRenderable::kYes);
1134         if (!mbet1) {
1135             continue;
1136         }
1137         auto mbet2 = sk_gpu_test::ManagedBackendTexture::MakeFromInfo(
1138                 context, ii, skgpu::Mipmapped::kNo, GrRenderable::kYes);
1139         if (!mbet2) {
1140             ERRORF(reporter, "Expected to be able to make second texture");
1141             continue;
1142         }
1143         auto ii2 = ii.makeWH(8, 8);
1144         auto mbet3 = sk_gpu_test::ManagedBackendTexture::MakeFromInfo(
1145                 context, ii2, skgpu::Mipmapped::kNo, GrRenderable::kYes);
1146         GrBackendTexture backendTexture3;
1147         if (!mbet3) {
1148             ERRORF(reporter, "Couldn't create different sized texture.");
1149             continue;
1150         }
1151 
1152         auto surf = SkSurfaces::WrapBackendTexture(context,
1153                                                    mbet1->texture(),
1154                                                    kTopLeft_GrSurfaceOrigin,
1155                                                    sampleCnt,
1156                                                    kRGBA_8888_SkColorType,
1157                                                    ii.refColorSpace(),
1158                                                    nullptr);
1159         if (!surf) {
1160             continue;
1161         }
1162         surf->getCanvas()->clear(SK_ColorBLUE);
1163         // Change matrix, layer, and clip state before swapping out the backing texture.
1164         surf->getCanvas()->translate(5, 5);
1165         surf->getCanvas()->saveLayer(nullptr, nullptr);
1166         surf->getCanvas()->clipRect(SkRect::MakeXYWH(0, 0, 1, 1));
1167         // switch origin while we're at it.
1168         bool replaced = surf->replaceBackendTexture(mbet2->texture(), kBottomLeft_GrSurfaceOrigin);
1169         REPORTER_ASSERT(reporter, replaced);
1170         SkPaint paint;
1171         paint.setColor(SK_ColorRED);
1172         surf->getCanvas()->drawRect(SkRect::MakeWH(5, 5), paint);
1173         surf->getCanvas()->restore();
1174 
1175         // Check that the replacement texture got the right color values.
1176         SkAutoPixmapStorage pm;
1177         pm.alloc(ii);
1178         bool bad = !surf->readPixels(pm, 0, 0);
1179         REPORTER_ASSERT(reporter, !bad, "Could not read surface.");
1180         for (int y = 0; y < ii.height() && !bad; ++y) {
1181             for (int x = 0; x < ii.width() && !bad; ++x) {
1182                 auto expected = (x == 5 && y == 5) ? 0xFF0000FF : 0xFFFF0000;
1183                 auto found = *pm.addr32(x, y);
1184                 if (found != expected) {
1185                     bad = true;
1186                     ERRORF(reporter, "Expected color 0x%08x, found color 0x%08x at %d, %d.",
1187                            expected, found, x, y);
1188                 }
1189             }
1190         }
1191         // The original texture should still be all blue.
1192         surf = SkSurfaces::WrapBackendTexture(context,
1193                                               mbet1->texture(),
1194                                               kBottomLeft_GrSurfaceOrigin,
1195                                               sampleCnt,
1196                                               kRGBA_8888_SkColorType,
1197                                               ii.refColorSpace(),
1198                                               nullptr);
1199         if (!surf) {
1200             ERRORF(reporter, "Could not create second surface.");
1201             continue;
1202         }
1203         bad = !surf->readPixels(pm, 0, 0);
1204         REPORTER_ASSERT(reporter, !bad, "Could not read second surface.");
1205         for (int y = 0; y < ii.height() && !bad; ++y) {
1206             for (int x = 0; x < ii.width() && !bad; ++x) {
1207                 auto expected = 0xFFFF0000;
1208                 auto found = *pm.addr32(x, y);
1209                 if (found != expected) {
1210                     bad = true;
1211                     ERRORF(reporter, "Expected color 0x%08x, found color 0x%08x at %d, %d.",
1212                            expected, found, x, y);
1213                 }
1214             }
1215         }
1216 
1217         // Can't replace with the same texture
1218         REPORTER_ASSERT(reporter,
1219                         !surf->replaceBackendTexture(mbet1->texture(), kTopLeft_GrSurfaceOrigin));
1220         // Can't replace with invalid texture
1221         REPORTER_ASSERT(reporter, !surf->replaceBackendTexture({}, kTopLeft_GrSurfaceOrigin));
1222         // Can't replace with different size texture.
1223         REPORTER_ASSERT(reporter,
1224                         !surf->replaceBackendTexture(mbet3->texture(), kTopLeft_GrSurfaceOrigin));
1225         // Can't replace texture of non-wrapped SkSurface.
1226         surf = SkSurfaces::RenderTarget(context, skgpu::Budgeted::kYes, ii, sampleCnt, nullptr);
1227         REPORTER_ASSERT(reporter, surf);
1228         if (surf) {
1229             REPORTER_ASSERT(reporter, !surf->replaceBackendTexture(mbet1->texture(),
1230                                                                    kTopLeft_GrSurfaceOrigin));
1231         }
1232     }
1233 }
1234 
test_overdraw_surface(skiatest::Reporter * r,SkSurface * surface)1235 static void test_overdraw_surface(skiatest::Reporter* r, SkSurface* surface) {
1236     SkOverdrawCanvas canvas(surface->getCanvas());
1237     canvas.drawPaint(SkPaint());
1238     sk_sp<SkImage> image = surface->makeImageSnapshot();
1239 
1240     SkBitmap bitmap;
1241     image->asLegacyBitmap(&bitmap);
1242     for (int y = 0; y < 10; y++) {
1243         for (int x = 0; x < 10; x++) {
1244             REPORTER_ASSERT(r, 1 == SkGetPackedA32(*bitmap.getAddr32(x, y)));
1245         }
1246     }
1247 }
1248 
DEF_TEST(OverdrawSurface_Raster,r)1249 DEF_TEST(OverdrawSurface_Raster, r) {
1250     sk_sp<SkSurface> surface = create_surface();
1251     test_overdraw_surface(r, surface.get());
1252 }
1253 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(OverdrawSurface_Gpu,r,ctxInfo,CtsEnforcement::kApiLevel_T)1254 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(OverdrawSurface_Gpu,
1255                                        r,
1256                                        ctxInfo,
1257                                        CtsEnforcement::kApiLevel_T) {
1258     auto context = ctxInfo.directContext();
1259     sk_sp<SkSurface> surface = create_gpu_surface(context);
1260     test_overdraw_surface(r, surface.get());
1261 }
1262 
DEF_TEST(Surface_null,r)1263 DEF_TEST(Surface_null, r) {
1264     REPORTER_ASSERT(r, SkSurfaces::Null(0, 0) == nullptr);
1265 
1266     const int w = 37;
1267     const int h = 1000;
1268     auto surf = SkSurfaces::Null(w, h);
1269     auto canvas = surf->getCanvas();
1270 
1271     canvas->drawPaint(SkPaint());   // should not crash, but don't expect anything to draw
1272     REPORTER_ASSERT(r, surf->makeImageSnapshot() == nullptr);
1273 }
1274 
1275 // assert: if a given imageinfo is valid for a surface, then it must be valid for an image
1276 //         (so the snapshot can succeed)
DEF_TEST(surface_image_unity,reporter)1277 DEF_TEST(surface_image_unity, reporter) {
1278     auto do_test = [reporter](const SkImageInfo& info) {
1279         size_t rowBytes = info.minRowBytes();
1280         auto surf = SkSurfaces::Raster(info, rowBytes, nullptr);
1281         if (surf) {
1282             auto img = surf->makeImageSnapshot();
1283             if ((false)) { // change to true to document the differences
1284                 if (!img) {
1285                     SkDebugf("image failed: [%08X %08X] %14s %s\n",
1286                              (uint32_t)info.width(),
1287                              (uint32_t)info.height(),
1288                              ToolUtils::colortype_name(info.colorType()),
1289                              ToolUtils::alphatype_name(info.alphaType()));
1290                     return;
1291                 }
1292             }
1293             REPORTER_ASSERT(reporter, img != nullptr);
1294 
1295             char tempPixel = 0;    // just need a valid address (not a valid size)
1296             SkPixmap pmap = { info, &tempPixel, rowBytes };
1297             img = SkImages::RasterFromPixmap(pmap, nullptr, nullptr);
1298             REPORTER_ASSERT(reporter, img != nullptr);
1299         }
1300     };
1301 
1302     const int32_t sizes[] = { -1, 0, 1, 1 << 18 };
1303     for (int cti = 0; cti <= kLastEnum_SkColorType; ++cti) {
1304         SkColorType ct = static_cast<SkColorType>(cti);
1305         for (int ati = 0; ati <= kLastEnum_SkAlphaType; ++ati) {
1306             SkAlphaType at = static_cast<SkAlphaType>(ati);
1307             for (int32_t size : sizes) {
1308                 do_test(SkImageInfo::Make(1, size, ct, at));
1309                 do_test(SkImageInfo::Make(size, 1, ct, at));
1310             }
1311         }
1312     }
1313 }
1314