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