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