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