blob: a92ecbe50b105befb7ac5e0d53e8ab6185fd5ef7 [file] [log] [blame]
junov@chromium.org995beb62013-03-28 13:49:22 +00001/*
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 */
tfarina@chromium.org4ee16bf2014-01-10 22:08:27 +00007
bsalomone63ffef2016-02-05 07:17:34 -08008#include <functional>
junov@chromium.org995beb62013-03-28 13:49:22 +00009#include "SkCanvas.h"
reed@google.com4f7c6152014-02-06 14:11:56 +000010#include "SkData.h"
reed41e010c2015-06-09 12:16:53 -070011#include "SkDevice.h"
bsalomon55812362015-06-10 08:49:28 -070012#include "SkImage_Base.h"
bungemand3ebb482015-08-05 13:57:49 -070013#include "SkPath.h"
junov@chromium.org995beb62013-03-28 13:49:22 +000014#include "SkRRect.h"
15#include "SkSurface.h"
reed@google.com4f7c6152014-02-06 14:11:56 +000016#include "SkUtils.h"
junov@chromium.org995beb62013-03-28 13:49:22 +000017#include "Test.h"
18
19#if SK_SUPPORT_GPU
kkinnunen179a8f52015-11-20 13:32:24 -080020#include "GrContext.h"
robertphillips175dd9b2016-04-28 14:32:04 -070021#include "GrDrawContext.h"
kkinnunen179a8f52015-11-20 13:32:24 -080022#include "GrGpu.h"
ericrkc4025182016-05-04 12:01:58 -070023#include "GrResourceProvider.h"
junov@chromium.org995beb62013-03-28 13:49:22 +000024#endif
25
kkinnunen179a8f52015-11-20 13:32:24 -080026#include <initializer_list>
bsalomon74f681d2015-06-23 14:38:48 -070027
kkinnunen179a8f52015-11-20 13:32:24 -080028static void release_direct_surface_storage(void* pixels, void* context) {
reed982542d2014-06-27 06:48:14 -070029 SkASSERT(pixels == context);
30 sk_free(pixels);
31}
reede8f30622016-03-23 18:59:25 -070032static sk_sp<SkSurface> create_surface(SkAlphaType at = kPremul_SkAlphaType,
33 SkImageInfo* requestedInfo = nullptr) {
bsalomon74f681d2015-06-23 14:38:48 -070034 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000035 if (requestedInfo) {
36 *requestedInfo = info;
37 }
reede8f30622016-03-23 18:59:25 -070038 return SkSurface::MakeRaster(info);
junov@chromium.org995beb62013-03-28 13:49:22 +000039}
reede8f30622016-03-23 18:59:25 -070040static sk_sp<SkSurface> create_direct_surface(SkAlphaType at = kPremul_SkAlphaType,
41 SkImageInfo* requestedInfo = nullptr) {
kkinnunen179a8f52015-11-20 13:32:24 -080042 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
43 if (requestedInfo) {
44 *requestedInfo = info;
45 }
46 const size_t rowBytes = info.minRowBytes();
47 void* storage = sk_malloc_throw(info.getSafeSize(rowBytes));
reede8f30622016-03-23 18:59:25 -070048 return SkSurface::MakeRasterDirectReleaseProc(info, storage, rowBytes,
49 release_direct_surface_storage,
50 storage);
kkinnunen179a8f52015-11-20 13:32:24 -080051}
52#if SK_SUPPORT_GPU
reede8f30622016-03-23 18:59:25 -070053static sk_sp<SkSurface> create_gpu_surface(GrContext* context, SkAlphaType at = kPremul_SkAlphaType,
54 SkImageInfo* requestedInfo = nullptr) {
kkinnunen179a8f52015-11-20 13:32:24 -080055 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
56 if (requestedInfo) {
57 *requestedInfo = info;
58 }
reede8f30622016-03-23 18:59:25 -070059 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, 0, nullptr);
kkinnunen179a8f52015-11-20 13:32:24 -080060}
reede8f30622016-03-23 18:59:25 -070061static sk_sp<SkSurface> create_gpu_scratch_surface(GrContext* context,
62 SkAlphaType at = kPremul_SkAlphaType,
63 SkImageInfo* requestedInfo = nullptr) {
kkinnunen179a8f52015-11-20 13:32:24 -080064 const SkImageInfo info = SkImageInfo::MakeN32(10, 10, at);
65 if (requestedInfo) {
66 *requestedInfo = info;
67 }
reede8f30622016-03-23 18:59:25 -070068 return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0, nullptr);
kkinnunen179a8f52015-11-20 13:32:24 -080069}
70#endif
junov@chromium.org995beb62013-03-28 13:49:22 +000071
kkinnunen179a8f52015-11-20 13:32:24 -080072DEF_TEST(SurfaceEmpty, reporter) {
reedb2497c22014-12-31 12:31:43 -080073 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
reede8f30622016-03-23 18:59:25 -070074 REPORTER_ASSERT(reporter, nullptr == SkSurface::MakeRaster(info));
75 REPORTER_ASSERT(reporter, nullptr == SkSurface::MakeRasterDirect(info, nullptr, 0));
kkinnunen179a8f52015-11-20 13:32:24 -080076
reedb2497c22014-12-31 12:31:43 -080077}
kkinnunen179a8f52015-11-20 13:32:24 -080078#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -070079DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceEmpty_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -080080 const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
81 REPORTER_ASSERT(reporter, nullptr ==
bsalomon8b7451a2016-05-11 06:33:06 -070082 SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kNo, info, 0,
bsalomonf2f1c172016-04-05 12:59:06 -070083 nullptr));
kkinnunen179a8f52015-11-20 13:32:24 -080084}
85#endif
reedb2497c22014-12-31 12:31:43 -080086
kkinnunen179a8f52015-11-20 13:32:24 -080087static void test_canvas_peek(skiatest::Reporter* reporter,
reede8f30622016-03-23 18:59:25 -070088 sk_sp<SkSurface>& surface,
kkinnunen179a8f52015-11-20 13:32:24 -080089 const SkImageInfo& requestInfo,
90 bool expectPeekSuccess) {
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000091 const SkColor color = SK_ColorRED;
92 const SkPMColor pmcolor = SkPreMultiplyColor(color);
kkinnunen179a8f52015-11-20 13:32:24 -080093 surface->getCanvas()->clear(color);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000094
reed6ceeebd2016-03-09 14:26:26 -080095 SkPixmap pmap;
96 bool success = surface->getCanvas()->peekPixels(&pmap);
kkinnunen179a8f52015-11-20 13:32:24 -080097 REPORTER_ASSERT(reporter, expectPeekSuccess == success);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +000098
reed6ceeebd2016-03-09 14:26:26 -080099 SkPixmap pmap2;
100 const void* addr2 = surface->peekPixels(&pmap2) ? pmap2.addr() : nullptr;
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000101
kkinnunen179a8f52015-11-20 13:32:24 -0800102 if (success) {
reed6ceeebd2016-03-09 14:26:26 -0800103 REPORTER_ASSERT(reporter, requestInfo == pmap.info());
104 REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= pmap.rowBytes());
105 REPORTER_ASSERT(reporter, pmcolor == *pmap.addr32());
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000106
reed6ceeebd2016-03-09 14:26:26 -0800107 REPORTER_ASSERT(reporter, pmap.addr() == pmap2.addr());
108 REPORTER_ASSERT(reporter, pmap.info() == pmap2.info());
109 REPORTER_ASSERT(reporter, pmap.rowBytes() == pmap2.rowBytes());
kkinnunen179a8f52015-11-20 13:32:24 -0800110 } else {
111 REPORTER_ASSERT(reporter, nullptr == addr2);
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000112 }
113}
kkinnunen179a8f52015-11-20 13:32:24 -0800114DEF_TEST(SurfaceCanvasPeek, reporter) {
115 for (auto& surface_func : { &create_surface, &create_direct_surface }) {
116 SkImageInfo requestInfo;
reede8f30622016-03-23 18:59:25 -0700117 auto surface(surface_func(kPremul_SkAlphaType, &requestInfo));
kkinnunen179a8f52015-11-20 13:32:24 -0800118 test_canvas_peek(reporter, surface, requestInfo, true);
119 }
120}
121#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700122DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCanvasPeek_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800123 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
124 SkImageInfo requestInfo;
bsalomon8b7451a2016-05-11 06:33:06 -0700125 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, &requestInfo));
kkinnunen179a8f52015-11-20 13:32:24 -0800126 test_canvas_peek(reporter, surface, requestInfo, false);
127 }
128}
129#endif
commit-bot@chromium.orgc3bd8af2014-02-13 17:14:46 +0000130
reed41e010c2015-06-09 12:16:53 -0700131// For compatibility with clients that still call accessBitmap(), we need to ensure that we bump
132// the bitmap's genID when we draw to it, else they won't know it has new values. When they are
133// exclusively using surface/image, and we can hide accessBitmap from device, we can remove this
134// test.
reede8f30622016-03-23 18:59:25 -0700135void test_access_pixels(skiatest::Reporter* reporter, const sk_sp<SkSurface>& surface) {
kkinnunen179a8f52015-11-20 13:32:24 -0800136 SkCanvas* canvas = surface->getCanvas();
137 canvas->clear(0);
reed41e010c2015-06-09 12:16:53 -0700138
kkinnunen179a8f52015-11-20 13:32:24 -0800139 SkBaseDevice* device = canvas->getDevice_just_for_deprecated_compatibility_testing();
140 SkBitmap bm = device->accessBitmap(false);
141 uint32_t genID0 = bm.getGenerationID();
142 // Now we draw something, which needs to "dirty" the genID (sorta like copy-on-write)
143 canvas->drawColor(SK_ColorBLUE);
144 // Now check that we get a different genID
145 uint32_t genID1 = bm.getGenerationID();
146 REPORTER_ASSERT(reporter, genID0 != genID1);
147}
148DEF_TEST(SurfaceAccessPixels, reporter) {
149 for (auto& surface_func : { &create_surface, &create_direct_surface }) {
reede8f30622016-03-23 18:59:25 -0700150 auto surface(surface_func(kPremul_SkAlphaType, nullptr));
kkinnunen179a8f52015-11-20 13:32:24 -0800151 test_access_pixels(reporter, surface);
152 }
153}
154#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700155DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceAccessPixels_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800156 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
bsalomon8b7451a2016-05-11 06:33:06 -0700157 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
kkinnunen179a8f52015-11-20 13:32:24 -0800158 test_access_pixels(reporter, surface);
159 }
160}
161#endif
162
reede8f30622016-03-23 18:59:25 -0700163static void test_snapshot_alphatype(skiatest::Reporter* reporter, const sk_sp<SkSurface>& surface,
kkinnunen179a8f52015-11-20 13:32:24 -0800164 bool expectOpaque) {
165 REPORTER_ASSERT(reporter, surface);
166 if (surface) {
reed9ce9d672016-03-17 10:51:11 -0700167 sk_sp<SkImage> image(surface->makeImageSnapshot());
kkinnunen179a8f52015-11-20 13:32:24 -0800168 REPORTER_ASSERT(reporter, image);
169 if (image) {
170 REPORTER_ASSERT(reporter, image->isOpaque() == SkToBool(expectOpaque));
reed41e010c2015-06-09 12:16:53 -0700171 }
172 }
173}
kkinnunen179a8f52015-11-20 13:32:24 -0800174DEF_TEST(SurfaceSnapshotAlphaType, reporter) {
175 for (auto& surface_func : { &create_surface, &create_direct_surface }) {
176 for (auto& isOpaque : { true, false }) {
177 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
reede8f30622016-03-23 18:59:25 -0700178 auto surface(surface_func(alphaType, nullptr));
kkinnunen179a8f52015-11-20 13:32:24 -0800179 test_snapshot_alphatype(reporter, surface, isOpaque);
bsalomon74f681d2015-06-23 14:38:48 -0700180 }
181 }
182}
kkinnunen179a8f52015-11-20 13:32:24 -0800183#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700184DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceSnapshotAlphaType_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800185 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
186 for (auto& isOpaque : { true, false }) {
187 SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
bsalomon8b7451a2016-05-11 06:33:06 -0700188 auto surface(surface_func(ctxInfo.grContext(), alphaType, nullptr));
kkinnunen179a8f52015-11-20 13:32:24 -0800189 test_snapshot_alphatype(reporter, surface, isOpaque);
190 }
191 }
192}
193#endif
bsalomon74f681d2015-06-23 14:38:48 -0700194
kkinnunen179a8f52015-11-20 13:32:24 -0800195static GrBackendObject get_surface_backend_texture_handle(
196 SkSurface* s, SkSurface::BackendHandleAccess a) {
197 return s->getTextureHandle(a);
198}
199static GrBackendObject get_surface_backend_render_target_handle(
200 SkSurface* s, SkSurface::BackendHandleAccess a) {
201 GrBackendObject result;
202 if (!s->getRenderTargetHandle(&result, a)) {
203 return 0;
204 }
205 return result;
206}
207
208static void test_backend_handle_access_copy_on_write(
209 skiatest::Reporter* reporter, SkSurface* surface, SkSurface::BackendHandleAccess mode,
210 GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) {
fmalitae2639082015-08-06 07:04:51 -0700211 GrBackendObject obj1 = func(surface, mode);
reed9ce9d672016-03-17 10:51:11 -0700212 sk_sp<SkImage> snap1(surface->makeImageSnapshot());
fmalitae2639082015-08-06 07:04:51 -0700213
214 GrBackendObject obj2 = func(surface, mode);
reed9ce9d672016-03-17 10:51:11 -0700215 sk_sp<SkImage> snap2(surface->makeImageSnapshot());
fmalitae2639082015-08-06 07:04:51 -0700216
217 // If the access mode triggers CoW, then the backend objects should reflect it.
218 REPORTER_ASSERT(reporter, (obj1 == obj2) == (snap1 == snap2));
219}
kkinnunen179a8f52015-11-20 13:32:24 -0800220DEF_TEST(SurfaceBackendHandleAccessCopyOnWrite, reporter) {
221 const SkSurface::BackendHandleAccess accessModes[] = {
222 SkSurface::kFlushRead_BackendHandleAccess,
223 SkSurface::kFlushWrite_BackendHandleAccess,
224 SkSurface::kDiscardWrite_BackendHandleAccess,
225 };
226 for (auto& handle_access_func :
227 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle }) {
228 for (auto& accessMode : accessModes) {
reede8f30622016-03-23 18:59:25 -0700229 auto surface(create_surface());
230 test_backend_handle_access_copy_on_write(reporter, surface.get(), accessMode,
kkinnunen179a8f52015-11-20 13:32:24 -0800231 handle_access_func);
232 }
233 }
234}
235#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700236DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessCopyOnWrite_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800237 const SkSurface::BackendHandleAccess accessModes[] = {
238 SkSurface::kFlushRead_BackendHandleAccess,
239 SkSurface::kFlushWrite_BackendHandleAccess,
240 SkSurface::kDiscardWrite_BackendHandleAccess,
241 };
242 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
243 for (auto& handle_access_func :
244 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle }) {
245 for (auto& accessMode : accessModes) {
bsalomon8b7451a2016-05-11 06:33:06 -0700246 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
reede8f30622016-03-23 18:59:25 -0700247 test_backend_handle_access_copy_on_write(reporter, surface.get(), accessMode,
kkinnunen179a8f52015-11-20 13:32:24 -0800248 handle_access_func);
249 }
250 }
251 }
252}
253#endif
fmalitae2639082015-08-06 07:04:51 -0700254
bsalomonf47b9a32016-02-22 11:02:58 -0800255static bool same_image(SkImage* a, SkImage* b,
256 std::function<intptr_t(SkImage*)> getImageBackingStore) {
257 return getImageBackingStore(a) == getImageBackingStore(b);
258}
259
260static bool same_image_surf(SkImage* a, SkSurface* b,
261 std::function<intptr_t(SkImage*)> getImageBackingStore,
262 std::function<intptr_t(SkSurface*)> getSurfaceBackingStore) {
263 return getImageBackingStore(a) == getSurfaceBackingStore(b);
264}
265
266static void test_unique_image_snap(skiatest::Reporter* reporter, SkSurface* surface,
267 bool surfaceIsDirect,
268 std::function<intptr_t(SkImage*)> imageBackingStore,
269 std::function<intptr_t(SkSurface*)> surfaceBackingStore) {
270 std::function<intptr_t(SkImage*)> ibs = imageBackingStore;
271 std::function<intptr_t(SkSurface*)> sbs = surfaceBackingStore;
bsalomon5ec26ae2016-02-25 08:33:02 -0800272 static const SkBudgeted kB = SkBudgeted::kNo;
bsalomonf47b9a32016-02-22 11:02:58 -0800273 {
reed9ce9d672016-03-17 10:51:11 -0700274 sk_sp<SkImage> image(surface->makeImageSnapshot(kB, SkSurface::kYes_ForceUnique));
275 REPORTER_ASSERT(reporter, !same_image_surf(image.get(), surface, ibs, sbs));
bsalomonf47b9a32016-02-22 11:02:58 -0800276 REPORTER_ASSERT(reporter, image->unique());
277 }
278 {
reed9ce9d672016-03-17 10:51:11 -0700279 sk_sp<SkImage> image1(surface->makeImageSnapshot(kB, SkSurface::kYes_ForceUnique));
280 REPORTER_ASSERT(reporter, !same_image_surf(image1.get(), surface, ibs, sbs));
bsalomonf47b9a32016-02-22 11:02:58 -0800281 REPORTER_ASSERT(reporter, image1->unique());
reed9ce9d672016-03-17 10:51:11 -0700282 sk_sp<SkImage> image2(surface->makeImageSnapshot(kB, SkSurface::kYes_ForceUnique));
283 REPORTER_ASSERT(reporter, !same_image_surf(image2.get(), surface, ibs, sbs));
284 REPORTER_ASSERT(reporter, !same_image(image1.get(), image2.get(), ibs));
bsalomonf47b9a32016-02-22 11:02:58 -0800285 REPORTER_ASSERT(reporter, image2->unique());
286 }
287 {
reed9ce9d672016-03-17 10:51:11 -0700288 sk_sp<SkImage> image1(surface->makeImageSnapshot(kB, SkSurface::kNo_ForceUnique));
289 sk_sp<SkImage> image2(surface->makeImageSnapshot(kB, SkSurface::kYes_ForceUnique));
290 sk_sp<SkImage> image3(surface->makeImageSnapshot(kB, SkSurface::kNo_ForceUnique));
291 sk_sp<SkImage> image4(surface->makeImageSnapshot(kB, SkSurface::kYes_ForceUnique));
bsalomonf47b9a32016-02-22 11:02:58 -0800292 // Image 1 and 3 ought to be the same (or we're missing an optimization).
reed9ce9d672016-03-17 10:51:11 -0700293 REPORTER_ASSERT(reporter, same_image(image1.get(), image3.get(), ibs));
bsalomonf47b9a32016-02-22 11:02:58 -0800294 // If the surface is not direct then images 1 and 3 should alias the surface's
295 // store.
reed9ce9d672016-03-17 10:51:11 -0700296 REPORTER_ASSERT(reporter, !surfaceIsDirect == same_image_surf(image1.get(), surface, ibs, sbs));
bsalomonf47b9a32016-02-22 11:02:58 -0800297 // Image 2 should not be shared with any other image.
reed9ce9d672016-03-17 10:51:11 -0700298 REPORTER_ASSERT(reporter, !same_image(image1.get(), image2.get(), ibs) &&
299 !same_image(image3.get(), image2.get(), ibs) &&
300 !same_image(image4.get(), image2.get(), ibs));
bsalomonf47b9a32016-02-22 11:02:58 -0800301 REPORTER_ASSERT(reporter, image2->unique());
reed9ce9d672016-03-17 10:51:11 -0700302 REPORTER_ASSERT(reporter, !same_image_surf(image2.get(), surface, ibs, sbs));
bsalomonf47b9a32016-02-22 11:02:58 -0800303 // Image 4 should not be shared with any other image.
reed9ce9d672016-03-17 10:51:11 -0700304 REPORTER_ASSERT(reporter, !same_image(image1.get(), image4.get(), ibs) &&
305 !same_image(image3.get(), image4.get(), ibs));
306 REPORTER_ASSERT(reporter, !same_image_surf(image4.get(), surface, ibs, sbs));
bsalomonf47b9a32016-02-22 11:02:58 -0800307 REPORTER_ASSERT(reporter, image4->unique());
308 }
309}
310
311DEF_TEST(UniqueImageSnapshot, reporter) {
312 auto getImageBackingStore = [reporter](SkImage* image) {
313 SkPixmap pm;
314 bool success = image->peekPixels(&pm);
315 REPORTER_ASSERT(reporter, success);
316 return reinterpret_cast<intptr_t>(pm.addr());
317 };
318 auto getSufaceBackingStore = [reporter](SkSurface* surface) {
reed6ceeebd2016-03-09 14:26:26 -0800319 SkPixmap pmap;
320 const void* pixels = surface->getCanvas()->peekPixels(&pmap) ? pmap.addr() : nullptr;
bsalomonf47b9a32016-02-22 11:02:58 -0800321 REPORTER_ASSERT(reporter, pixels);
322 return reinterpret_cast<intptr_t>(pixels);
323 };
324
reede8f30622016-03-23 18:59:25 -0700325 auto surface(create_surface());
326 test_unique_image_snap(reporter, surface.get(), false, getImageBackingStore,
327 getSufaceBackingStore);
328 surface = create_direct_surface();
329 test_unique_image_snap(reporter, surface.get(), true, getImageBackingStore,
330 getSufaceBackingStore);
bsalomonf47b9a32016-02-22 11:02:58 -0800331}
332
333#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700334DEF_GPUTEST_FOR_RENDERING_CONTEXTS(UniqueImageSnapshot_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700335 GrContext* context = ctxInfo.grContext();
bsalomonf47b9a32016-02-22 11:02:58 -0800336 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
reede8f30622016-03-23 18:59:25 -0700337 auto surface(surface_func(context, kOpaque_SkAlphaType, nullptr));
bsalomonf47b9a32016-02-22 11:02:58 -0800338
339 auto imageBackingStore = [reporter](SkImage* image) {
340 GrTexture* texture = as_IB(image)->peekTexture();
341 if (!texture) {
342 ERRORF(reporter, "Not texture backed.");
343 return static_cast<intptr_t>(0);
344 }
345 return static_cast<intptr_t>(texture->getUniqueID());
346 };
347
348 auto surfaceBackingStore = [reporter](SkSurface* surface) {
robertphillips175dd9b2016-04-28 14:32:04 -0700349 GrDrawContext* dc = surface->getCanvas()->internal_private_accessTopLayerDrawContext();
350 GrRenderTarget* rt = dc->accessRenderTarget();
bsalomonf47b9a32016-02-22 11:02:58 -0800351 if (!rt) {
352 ERRORF(reporter, "Not render target backed.");
353 return static_cast<intptr_t>(0);
354 }
355 return static_cast<intptr_t>(rt->getUniqueID());
356 };
357
reede8f30622016-03-23 18:59:25 -0700358 test_unique_image_snap(reporter, surface.get(), false, imageBackingStore,
359 surfaceBackingStore);
bsalomonf47b9a32016-02-22 11:02:58 -0800360
361 // Test again with a "direct" render target;
362 GrBackendObject textureObject = context->getGpu()->createTestingOnlyBackendTexture(nullptr,
egdaniel0a3a7f72016-06-24 09:22:31 -0700363 10, 10, kRGBA_8888_GrPixelConfig, true);
bsalomonf47b9a32016-02-22 11:02:58 -0800364 GrBackendTextureDesc desc;
365 desc.fConfig = kRGBA_8888_GrPixelConfig;
366 desc.fWidth = 10;
367 desc.fHeight = 10;
368 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
369 desc.fTextureHandle = textureObject;
370 GrTexture* texture = context->textureProvider()->wrapBackendTexture(desc);
371 {
reede8f30622016-03-23 18:59:25 -0700372 auto surface(SkSurface::MakeRenderTargetDirect(texture->asRenderTarget()));
373 test_unique_image_snap(reporter, surface.get(), true, imageBackingStore,
bsalomonf47b9a32016-02-22 11:02:58 -0800374 surfaceBackingStore);
375 }
376 texture->unref();
377 context->getGpu()->deleteTestingOnlyBackendTexture(textureObject);
378 }
379}
380#endif
381
kkinnunen179a8f52015-11-20 13:32:24 -0800382#if SK_SUPPORT_GPU
383// May we (soon) eliminate the need to keep testing this, by hiding the bloody device!
384static uint32_t get_legacy_gen_id(SkSurface* surface) {
385 SkBaseDevice* device =
386 surface->getCanvas()->getDevice_just_for_deprecated_compatibility_testing();
387 return device->accessBitmap(false).getGenerationID();
388}
389/*
390 * Test legacy behavor of bumping the surface's device's bitmap's genID when we access its
391 * texture handle for writing.
392 *
reed9ce9d672016-03-17 10:51:11 -0700393 * Note: this needs to be tested separately from checking makeImageSnapshot, as calling that
kkinnunen179a8f52015-11-20 13:32:24 -0800394 * can also incidentally bump the genID (when a new backing surface is created).
395 */
396static void test_backend_handle_gen_id(
397 skiatest::Reporter* reporter, SkSurface* surface,
398 GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) {
399 const uint32_t gen0 = get_legacy_gen_id(surface);
400 func(surface, SkSurface::kFlushRead_BackendHandleAccess);
401 const uint32_t gen1 = get_legacy_gen_id(surface);
402 REPORTER_ASSERT(reporter, gen0 == gen1);
403
404 func(surface, SkSurface::kFlushWrite_BackendHandleAccess);
405 const uint32_t gen2 = get_legacy_gen_id(surface);
406 REPORTER_ASSERT(reporter, gen0 != gen2);
407
408 func(surface, SkSurface::kDiscardWrite_BackendHandleAccess);
409 const uint32_t gen3 = get_legacy_gen_id(surface);
410 REPORTER_ASSERT(reporter, gen0 != gen3);
411 REPORTER_ASSERT(reporter, gen2 != gen3);
412}
413static void test_backend_handle_unique_id(
414 skiatest::Reporter* reporter, SkSurface* surface,
415 GrBackendObject (*func)(SkSurface*, SkSurface::BackendHandleAccess)) {
reed9ce9d672016-03-17 10:51:11 -0700416 sk_sp<SkImage> image0(surface->makeImageSnapshot());
kkinnunen179a8f52015-11-20 13:32:24 -0800417 GrBackendObject obj = func(surface, SkSurface::kFlushRead_BackendHandleAccess);
418 REPORTER_ASSERT(reporter, obj != 0);
reed9ce9d672016-03-17 10:51:11 -0700419 sk_sp<SkImage> image1(surface->makeImageSnapshot());
kkinnunen179a8f52015-11-20 13:32:24 -0800420 // just read access should not affect the snapshot
421 REPORTER_ASSERT(reporter, image0->uniqueID() == image1->uniqueID());
422
423 obj = func(surface, SkSurface::kFlushWrite_BackendHandleAccess);
424 REPORTER_ASSERT(reporter, obj != 0);
reed9ce9d672016-03-17 10:51:11 -0700425 sk_sp<SkImage> image2(surface->makeImageSnapshot());
kkinnunen179a8f52015-11-20 13:32:24 -0800426 // expect a new image, since we claimed we would write
427 REPORTER_ASSERT(reporter, image0->uniqueID() != image2->uniqueID());
428
429 obj = func(surface, SkSurface::kDiscardWrite_BackendHandleAccess);
430 REPORTER_ASSERT(reporter, obj != 0);
reed9ce9d672016-03-17 10:51:11 -0700431 sk_sp<SkImage> image3(surface->makeImageSnapshot());
kkinnunen179a8f52015-11-20 13:32:24 -0800432 // expect a new(er) image, since we claimed we would write
433 REPORTER_ASSERT(reporter, image0->uniqueID() != image3->uniqueID());
434 REPORTER_ASSERT(reporter, image2->uniqueID() != image3->uniqueID());
435}
436// No CPU test.
bsalomon68d91342016-04-12 09:59:58 -0700437DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBackendHandleAccessIDs_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800438 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
439 for (auto& test_func : { &test_backend_handle_unique_id, &test_backend_handle_gen_id }) {
440 for (auto& handle_access_func :
441 { &get_surface_backend_texture_handle, &get_surface_backend_render_target_handle}) {
bsalomon8b7451a2016-05-11 06:33:06 -0700442 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
reede8f30622016-03-23 18:59:25 -0700443 test_func(reporter, surface.get(), handle_access_func);
kkinnunen179a8f52015-11-20 13:32:24 -0800444 }
445 }
446 }
447}
448#endif
449
450// Verify that the right canvas commands trigger a copy on write.
451static void test_copy_on_write(skiatest::Reporter* reporter, SkSurface* surface) {
junov@chromium.org995beb62013-03-28 13:49:22 +0000452 SkCanvas* canvas = surface->getCanvas();
453
454 const SkRect testRect =
455 SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
456 SkIntToScalar(4), SkIntToScalar(5));
junov@chromium.org995beb62013-03-28 13:49:22 +0000457 SkPath testPath;
458 testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
459 SkIntToScalar(2), SkIntToScalar(1)));
460
461 const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
462
463 SkRegion testRegion;
464 testRegion.setRect(testIRect);
465
466
467 const SkColor testColor = 0x01020304;
468 const SkPaint testPaint;
469 const SkPoint testPoints[3] = {
470 {SkIntToScalar(0), SkIntToScalar(0)},
471 {SkIntToScalar(2), SkIntToScalar(1)},
472 {SkIntToScalar(0), SkIntToScalar(2)}
473 };
474 const size_t testPointCount = 3;
475
476 SkBitmap testBitmap;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000477 testBitmap.allocN32Pixels(10, 10);
robertphillips@google.comd1ce77d2013-10-09 12:51:09 +0000478 testBitmap.eraseColor(0);
junov@chromium.org995beb62013-03-28 13:49:22 +0000479
480 SkRRect testRRect;
481 testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1);
482
483 SkString testText("Hello World");
484 const SkPoint testPoints2[] = {
485 { SkIntToScalar(0), SkIntToScalar(1) },
486 { SkIntToScalar(1), SkIntToScalar(1) },
487 { SkIntToScalar(2), SkIntToScalar(1) },
488 { SkIntToScalar(3), SkIntToScalar(1) },
489 { SkIntToScalar(4), SkIntToScalar(1) },
490 { SkIntToScalar(5), SkIntToScalar(1) },
491 { SkIntToScalar(6), SkIntToScalar(1) },
492 { SkIntToScalar(7), SkIntToScalar(1) },
493 { SkIntToScalar(8), SkIntToScalar(1) },
494 { SkIntToScalar(9), SkIntToScalar(1) },
495 { SkIntToScalar(10), SkIntToScalar(1) },
496 };
497
498#define EXPECT_COPY_ON_WRITE(command) \
499 { \
reed9ce9d672016-03-17 10:51:11 -0700500 sk_sp<SkImage> imageBefore = surface->makeImageSnapshot(); \
501 sk_sp<SkImage> aur_before(imageBefore); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000502 canvas-> command ; \
reed9ce9d672016-03-17 10:51:11 -0700503 sk_sp<SkImage> imageAfter = surface->makeImageSnapshot(); \
504 sk_sp<SkImage> aur_after(imageAfter); \
junov@chromium.org995beb62013-03-28 13:49:22 +0000505 REPORTER_ASSERT(reporter, imageBefore != imageAfter); \
506 }
507
508 EXPECT_COPY_ON_WRITE(clear(testColor))
509 EXPECT_COPY_ON_WRITE(drawPaint(testPaint))
510 EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \
511 testPaint))
512 EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint))
513 EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint))
514 EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint))
515 EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint))
516 EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0))
reede47829b2015-08-06 10:02:53 -0700517 EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, testRect, nullptr))
halcanary96fcdcc2015-08-27 07:41:13 -0700518 EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, nullptr))
junov@chromium.org995beb62013-03-28 13:49:22 +0000519 EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint))
520 EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \
521 testPaint))
halcanary96fcdcc2015-08-27 07:41:13 -0700522 EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, nullptr, \
junov@chromium.org995beb62013-03-28 13:49:22 +0000523 testPaint))
kkinnunen179a8f52015-11-20 13:32:24 -0800524}
525DEF_TEST(SurfaceCopyOnWrite, reporter) {
reede8f30622016-03-23 18:59:25 -0700526 test_copy_on_write(reporter, create_surface().get());
kkinnunen179a8f52015-11-20 13:32:24 -0800527}
528#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700529DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCopyOnWrite_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800530 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
bsalomon8b7451a2016-05-11 06:33:06 -0700531 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
reede8f30622016-03-23 18:59:25 -0700532 test_copy_on_write(reporter, surface.get());
fmalitae2639082015-08-06 07:04:51 -0700533 }
junov@chromium.org995beb62013-03-28 13:49:22 +0000534}
kkinnunen179a8f52015-11-20 13:32:24 -0800535#endif
junov@chromium.org995beb62013-03-28 13:49:22 +0000536
kkinnunen179a8f52015-11-20 13:32:24 -0800537static void test_writable_after_snapshot_release(skiatest::Reporter* reporter,
538 SkSurface* surface) {
junov@chromium.orgaf058352013-04-03 15:03:26 +0000539 // This test succeeds by not triggering an assertion.
540 // The test verifies that the surface remains writable (usable) after
541 // acquiring and releasing a snapshot without triggering a copy on write.
junov@chromium.orgaf058352013-04-03 15:03:26 +0000542 SkCanvas* canvas = surface->getCanvas();
543 canvas->clear(1);
reed9ce9d672016-03-17 10:51:11 -0700544 surface->makeImageSnapshot(); // Create and destroy SkImage
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000545 canvas->clear(2); // Must not assert internally
junov@chromium.org995beb62013-03-28 13:49:22 +0000546}
kkinnunen179a8f52015-11-20 13:32:24 -0800547DEF_TEST(SurfaceWriteableAfterSnapshotRelease, reporter) {
reede8f30622016-03-23 18:59:25 -0700548 test_writable_after_snapshot_release(reporter, create_surface().get());
kkinnunen179a8f52015-11-20 13:32:24 -0800549}
550#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700551DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceWriteableAfterSnapshotRelease_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800552 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
bsalomon8b7451a2016-05-11 06:33:06 -0700553 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
reede8f30622016-03-23 18:59:25 -0700554 test_writable_after_snapshot_release(reporter, surface.get());
kkinnunen179a8f52015-11-20 13:32:24 -0800555 }
556}
557#endif
junov@chromium.orgda904742013-05-01 22:38:16 +0000558
junov@chromium.orgb516a412013-05-01 22:49:59 +0000559#if SK_SUPPORT_GPU
kkinnunen179a8f52015-11-20 13:32:24 -0800560static void test_crbug263329(skiatest::Reporter* reporter,
561 SkSurface* surface1,
562 SkSurface* surface2) {
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000563 // This is a regression test for crbug.com/263329
564 // Bug was caused by onCopyOnWrite releasing the old surface texture
565 // back to the scratch texture pool even though the texture is used
566 // by and active SkImage_Gpu.
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000567 SkCanvas* canvas1 = surface1->getCanvas();
568 SkCanvas* canvas2 = surface2->getCanvas();
569 canvas1->clear(1);
reed9ce9d672016-03-17 10:51:11 -0700570 sk_sp<SkImage> image1(surface1->makeImageSnapshot());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000571 // Trigger copy on write, new backing is a scratch texture
572 canvas1->clear(2);
reed9ce9d672016-03-17 10:51:11 -0700573 sk_sp<SkImage> image2(surface1->makeImageSnapshot());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000574 // Trigger copy on write, old backing should not be returned to scratch
575 // pool because it is held by image2
576 canvas1->clear(3);
577
578 canvas2->clear(4);
reed9ce9d672016-03-17 10:51:11 -0700579 sk_sp<SkImage> image3(surface2->makeImageSnapshot());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000580 // Trigger copy on write on surface2. The new backing store should not
581 // be recycling a texture that is held by an existing image.
582 canvas2->clear(5);
reed9ce9d672016-03-17 10:51:11 -0700583 sk_sp<SkImage> image4(surface2->makeImageSnapshot());
bsalomon84a4e5a2016-02-29 11:41:52 -0800584 REPORTER_ASSERT(reporter, as_IB(image4)->peekTexture() != as_IB(image3)->peekTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000585 // The following assertion checks crbug.com/263329
bsalomon84a4e5a2016-02-29 11:41:52 -0800586 REPORTER_ASSERT(reporter, as_IB(image4)->peekTexture() != as_IB(image2)->peekTexture());
587 REPORTER_ASSERT(reporter, as_IB(image4)->peekTexture() != as_IB(image1)->peekTexture());
588 REPORTER_ASSERT(reporter, as_IB(image3)->peekTexture() != as_IB(image2)->peekTexture());
589 REPORTER_ASSERT(reporter, as_IB(image3)->peekTexture() != as_IB(image1)->peekTexture());
590 REPORTER_ASSERT(reporter, as_IB(image2)->peekTexture() != as_IB(image1)->peekTexture());
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000591}
egdanielab527a52016-06-28 08:07:26 -0700592DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceCRBug263329_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800593 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
bsalomon8b7451a2016-05-11 06:33:06 -0700594 auto surface1(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
595 auto surface2(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
reede8f30622016-03-23 18:59:25 -0700596 test_crbug263329(reporter, surface1.get(), surface2.get());
kkinnunen179a8f52015-11-20 13:32:24 -0800597 }
598}
599#endif
commit-bot@chromium.org4d24b742013-07-25 23:29:40 +0000600
kkinnunen179a8f52015-11-20 13:32:24 -0800601DEF_TEST(SurfaceGetTexture, reporter) {
reede8f30622016-03-23 18:59:25 -0700602 auto surface(create_surface());
reed9ce9d672016-03-17 10:51:11 -0700603 sk_sp<SkImage> image(surface->makeImageSnapshot());
bsalomon84a4e5a2016-02-29 11:41:52 -0800604 REPORTER_ASSERT(reporter, as_IB(image)->peekTexture() == nullptr);
kkinnunen179a8f52015-11-20 13:32:24 -0800605 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
bsalomon84a4e5a2016-02-29 11:41:52 -0800606 REPORTER_ASSERT(reporter, as_IB(image)->peekTexture() == nullptr);
kkinnunen179a8f52015-11-20 13:32:24 -0800607}
608#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700609DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfacepeekTexture_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800610 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
bsalomon8b7451a2016-05-11 06:33:06 -0700611 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
reed9ce9d672016-03-17 10:51:11 -0700612 sk_sp<SkImage> image(surface->makeImageSnapshot());
bsalomon84a4e5a2016-02-29 11:41:52 -0800613 GrTexture* texture = as_IB(image)->peekTexture();
bsalomon49f085d2014-09-05 13:34:00 -0700614 REPORTER_ASSERT(reporter, texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000615 REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle());
kkinnunen179a8f52015-11-20 13:32:24 -0800616 surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
bsalomon84a4e5a2016-02-29 11:41:52 -0800617 REPORTER_ASSERT(reporter, as_IB(image)->peekTexture() == texture);
junov@chromium.orgda904742013-05-01 22:38:16 +0000618 }
junov@chromium.orgda904742013-05-01 22:38:16 +0000619}
kkinnunen179a8f52015-11-20 13:32:24 -0800620#endif
bsalomoneaaaf0b2015-01-23 08:08:04 -0800621
kkinnunen179a8f52015-11-20 13:32:24 -0800622#if SK_SUPPORT_GPU
bsalomon3582d3e2015-02-13 14:20:05 -0800623#include "GrGpuResourcePriv.h"
bsalomoneaaaf0b2015-01-23 08:08:04 -0800624#include "SkGpuDevice.h"
625#include "SkImage_Gpu.h"
626#include "SkSurface_Gpu.h"
627
reede8f30622016-03-23 18:59:25 -0700628static SkBudgeted is_budgeted(const sk_sp<SkSurface>& surf) {
629 SkSurface_Gpu* gsurf = (SkSurface_Gpu*)surf.get();
630 return gsurf->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted();
bsalomoneaaaf0b2015-01-23 08:08:04 -0800631}
632
bsalomon5ec26ae2016-02-25 08:33:02 -0800633static SkBudgeted is_budgeted(SkImage* image) {
bsalomon84a4e5a2016-02-29 11:41:52 -0800634 return ((SkImage_Gpu*)image)->peekTexture()->resourcePriv().isBudgeted();
bsalomoneaaaf0b2015-01-23 08:08:04 -0800635}
636
reed9ce9d672016-03-17 10:51:11 -0700637static SkBudgeted is_budgeted(const sk_sp<SkImage> image) {
638 return is_budgeted(image.get());
639}
640
egdanielab527a52016-06-28 08:07:26 -0700641DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceBudget, reporter, ctxInfo) {
bsalomoneaaaf0b2015-01-23 08:08:04 -0800642 SkImageInfo info = SkImageInfo::MakeN32Premul(8,8);
bsalomon5ec26ae2016-02-25 08:33:02 -0800643 for (auto sbudgeted : { SkBudgeted::kNo, SkBudgeted::kYes }) {
644 for (auto ibudgeted : { SkBudgeted::kNo, SkBudgeted::kYes }) {
bsalomon8b7451a2016-05-11 06:33:06 -0700645 auto surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(), sbudgeted, info));
bsalomoneaaaf0b2015-01-23 08:08:04 -0800646 SkASSERT(surface);
647 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
648
reed9ce9d672016-03-17 10:51:11 -0700649 sk_sp<SkImage> image(surface->makeImageSnapshot(ibudgeted));
bsalomoneaaaf0b2015-01-23 08:08:04 -0800650
651 // Initially the image shares a texture with the surface, and the surface decides
652 // whether it is budgeted or not.
653 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
654 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(image));
655
656 // Now trigger copy-on-write
657 surface->getCanvas()->clear(SK_ColorBLUE);
658
659 // They don't share a texture anymore. They should each have made their own budget
660 // decision.
661 REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
662 REPORTER_ASSERT(reporter, ibudgeted == is_budgeted(image));
663 }
664 }
665}
junov@chromium.orgb516a412013-05-01 22:49:59 +0000666#endif
junov@chromium.orgda904742013-05-01 22:38:16 +0000667
kkinnunen179a8f52015-11-20 13:32:24 -0800668static void test_no_canvas1(skiatest::Reporter* reporter,
669 SkSurface* surface,
670 SkSurface::ContentChangeMode mode) {
671 // Test passes by not asserting
672 surface->notifyContentWillChange(mode);
673 SkDEBUGCODE(surface->validate();)
674}
675static void test_no_canvas2(skiatest::Reporter* reporter,
676 SkSurface* surface,
677 SkSurface::ContentChangeMode mode) {
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000678 // Verifies the robustness of SkSurface for handling use cases where calls
679 // are made before a canvas is created.
reed9ce9d672016-03-17 10:51:11 -0700680 sk_sp<SkImage> image1 = surface->makeImageSnapshot();
681 sk_sp<SkImage> aur_image1(image1);
kkinnunen179a8f52015-11-20 13:32:24 -0800682 SkDEBUGCODE(image1->validate();)
683 SkDEBUGCODE(surface->validate();)
684 surface->notifyContentWillChange(mode);
685 SkDEBUGCODE(image1->validate();)
686 SkDEBUGCODE(surface->validate();)
reed9ce9d672016-03-17 10:51:11 -0700687 sk_sp<SkImage> image2 = surface->makeImageSnapshot();
688 sk_sp<SkImage> aur_image2(image2);
kkinnunen179a8f52015-11-20 13:32:24 -0800689 SkDEBUGCODE(image2->validate();)
690 SkDEBUGCODE(surface->validate();)
691 REPORTER_ASSERT(reporter, image1 != image2);
junov@chromium.orgacea3ef2013-04-16 19:41:09 +0000692}
kkinnunen179a8f52015-11-20 13:32:24 -0800693DEF_TEST(SurfaceNoCanvas, reporter) {
694 SkSurface::ContentChangeMode modes[] =
695 { SkSurface::kDiscard_ContentChangeMode, SkSurface::kRetain_ContentChangeMode};
696 for (auto& test_func : { &test_no_canvas1, &test_no_canvas2 }) {
697 for (auto& mode : modes) {
reede8f30622016-03-23 18:59:25 -0700698 test_func(reporter, create_surface().get(), mode);
kkinnunen179a8f52015-11-20 13:32:24 -0800699 }
700 }
701}
junov@chromium.orgb516a412013-05-01 22:49:59 +0000702#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -0700703DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceNoCanvas_Gpu, reporter, ctxInfo) {
kkinnunen179a8f52015-11-20 13:32:24 -0800704 SkSurface::ContentChangeMode modes[] =
705 { SkSurface::kDiscard_ContentChangeMode, SkSurface::kRetain_ContentChangeMode};
706 for (auto& surface_func : { &create_gpu_surface, &create_gpu_scratch_surface }) {
707 for (auto& test_func : { &test_no_canvas1, &test_no_canvas2 }) {
708 for (auto& mode : modes) {
bsalomon8b7451a2016-05-11 06:33:06 -0700709 auto surface(surface_func(ctxInfo.grContext(), kPremul_SkAlphaType, nullptr));
reede8f30622016-03-23 18:59:25 -0700710 test_func(reporter, surface.get(), mode);
bsalomone904c092014-07-17 10:50:59 -0700711 }
robertphillips@google.com3bddb382013-11-12 13:51:03 +0000712 }
junov@chromium.orgaf058352013-04-03 15:03:26 +0000713 }
junov@chromium.org995beb62013-03-28 13:49:22 +0000714}
kkinnunen179a8f52015-11-20 13:32:24 -0800715#endif
reed9cd016e2016-01-30 10:01:06 -0800716
717static void check_rowbytes_remain_consistent(SkSurface* surface, skiatest::Reporter* reporter) {
reed6ceeebd2016-03-09 14:26:26 -0800718 SkPixmap surfacePM;
719 REPORTER_ASSERT(reporter, surface->peekPixels(&surfacePM));
reed9cd016e2016-01-30 10:01:06 -0800720
reed9ce9d672016-03-17 10:51:11 -0700721 sk_sp<SkImage> image(surface->makeImageSnapshot());
reed6ceeebd2016-03-09 14:26:26 -0800722 SkPixmap pm;
723 REPORTER_ASSERT(reporter, image->peekPixels(&pm));
reed9cd016e2016-01-30 10:01:06 -0800724
reed6ceeebd2016-03-09 14:26:26 -0800725 REPORTER_ASSERT(reporter, surfacePM.rowBytes() == pm.rowBytes());
reed9cd016e2016-01-30 10:01:06 -0800726
727 // trigger a copy-on-write
728 surface->getCanvas()->drawPaint(SkPaint());
reed9ce9d672016-03-17 10:51:11 -0700729 sk_sp<SkImage> image2(surface->makeImageSnapshot());
reed9cd016e2016-01-30 10:01:06 -0800730 REPORTER_ASSERT(reporter, image->uniqueID() != image2->uniqueID());
731
reed6ceeebd2016-03-09 14:26:26 -0800732 SkPixmap pm2;
733 REPORTER_ASSERT(reporter, image2->peekPixels(&pm2));
734 REPORTER_ASSERT(reporter, pm2.rowBytes() == pm.rowBytes());
reed9cd016e2016-01-30 10:01:06 -0800735}
736
737DEF_TEST(surface_rowbytes, reporter) {
738 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
739
reede8f30622016-03-23 18:59:25 -0700740 auto surf0(SkSurface::MakeRaster(info));
741 check_rowbytes_remain_consistent(surf0.get(), reporter);
reed9cd016e2016-01-30 10:01:06 -0800742
743 // specify a larger rowbytes
reede8f30622016-03-23 18:59:25 -0700744 auto surf1(SkSurface::MakeRaster(info, 500, nullptr));
745 check_rowbytes_remain_consistent(surf1.get(), reporter);
reed9cd016e2016-01-30 10:01:06 -0800746
747 // Try some illegal rowByte values
reede8f30622016-03-23 18:59:25 -0700748 auto s = SkSurface::MakeRaster(info, 396, nullptr); // needs to be at least 400
reed9cd016e2016-01-30 10:01:06 -0800749 REPORTER_ASSERT(reporter, nullptr == s);
reede8f30622016-03-23 18:59:25 -0700750 s = SkSurface::MakeRaster(info, 1 << 30, nullptr); // allocation to large
reed9cd016e2016-01-30 10:01:06 -0800751 REPORTER_ASSERT(reporter, nullptr == s);
752}
bsalomone63ffef2016-02-05 07:17:34 -0800753
754#if SK_SUPPORT_GPU
ericrkc4025182016-05-04 12:01:58 -0700755static sk_sp<SkSurface> create_gpu_surface_backend_texture(
756 GrContext* context, int sampleCnt, uint32_t color, GrBackendObject* outTexture) {
757 const int kWidth = 10;
758 const int kHeight = 10;
759 SkAutoTDeleteArray<uint32_t> pixels(new uint32_t[kWidth * kHeight]);
760 sk_memset32(pixels.get(), color, kWidth * kHeight);
761 GrBackendTextureDesc desc;
762 desc.fConfig = kRGBA_8888_GrPixelConfig;
763 desc.fWidth = kWidth;
764 desc.fHeight = kHeight;
765 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
766 desc.fTextureHandle = context->getGpu()->createTestingOnlyBackendTexture(
egdaniel0a3a7f72016-06-24 09:22:31 -0700767 pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true);
ericrkc4025182016-05-04 12:01:58 -0700768 desc.fSampleCnt = sampleCnt;
769 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(context, desc, nullptr);
770 if (!surface) {
771 context->getGpu()->deleteTestingOnlyBackendTexture(desc.fTextureHandle);
772 return nullptr;
773 }
774 *outTexture = desc.fTextureHandle;
775 return surface;
776}
bsalomone63ffef2016-02-05 07:17:34 -0800777
ericrkc4025182016-05-04 12:01:58 -0700778static sk_sp<SkSurface> create_gpu_surface_backend_texture_as_render_target(
779 GrContext* context, int sampleCnt, uint32_t color, GrBackendObject* outTexture) {
780 const int kWidth = 10;
781 const int kHeight = 10;
782 SkAutoTDeleteArray<uint32_t> pixels(new uint32_t[kWidth * kHeight]);
783 sk_memset32(pixels.get(), color, kWidth * kHeight);
784 GrBackendTextureDesc desc;
785 desc.fConfig = kRGBA_8888_GrPixelConfig;
786 desc.fWidth = kWidth;
787 desc.fHeight = kHeight;
788 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
789 desc.fTextureHandle = context->getGpu()->createTestingOnlyBackendTexture(
egdaniel0a3a7f72016-06-24 09:22:31 -0700790 pixels.get(), kWidth, kHeight, kRGBA_8888_GrPixelConfig, true);
ericrkc4025182016-05-04 12:01:58 -0700791 desc.fSampleCnt = sampleCnt;
792 sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTextureAsRenderTarget(context, desc,
793 nullptr);
794 if (!surface) {
795 context->getGpu()->deleteTestingOnlyBackendTexture(desc.fTextureHandle);
796 return nullptr;
797 }
798 *outTexture = desc.fTextureHandle;
799 return surface;
800}
801
802static void test_surface_clear(skiatest::Reporter* reporter, sk_sp<SkSurface> surface,
803 std::function<GrSurface*(SkSurface*)> grSurfaceGetter,
804 uint32_t expectedValue) {
bsalomone63ffef2016-02-05 07:17:34 -0800805 if (!surface) {
806 ERRORF(reporter, "Could not create GPU SkSurface.");
807 return;
808 }
809 int w = surface->width();
810 int h = surface->height();
811 SkAutoTDeleteArray<uint32_t> pixels(new uint32_t[w * h]);
ericrkc4025182016-05-04 12:01:58 -0700812 sk_memset32(pixels.get(), ~expectedValue, w * h);
bsalomone63ffef2016-02-05 07:17:34 -0800813
reede8f30622016-03-23 18:59:25 -0700814 SkAutoTUnref<GrSurface> grSurface(SkSafeRef(grSurfaceGetter(surface.get())));
bsalomone63ffef2016-02-05 07:17:34 -0800815 if (!grSurface) {
816 ERRORF(reporter, "Could access render target of GPU SkSurface.");
817 return;
818 }
bsalomon2fba8092016-02-05 13:47:06 -0800819 surface.reset();
bsalomone63ffef2016-02-05 07:17:34 -0800820 grSurface->readPixels(0, 0, w, h, kRGBA_8888_GrPixelConfig, pixels.get());
821 for (int y = 0; y < h; ++y) {
822 for (int x = 0; x < w; ++x) {
823 uint32_t pixel = pixels.get()[y * w + x];
824 if (pixel != expectedValue) {
825 SkString msg;
826 if (expectedValue) {
827 msg = "SkSurface should have left render target unmodified";
828 } else {
829 msg = "SkSurface should have cleared the render target";
830 }
831 ERRORF(reporter,
832 "%s but read 0x%08x (instead of 0x%08x) at %x,%d", msg.c_str(), pixel,
833 expectedValue, x, y);
834 return;
835 }
836 }
837 }
838}
839
bsalomon758586c2016-04-06 14:02:39 -0700840DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceClear_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700841 GrContext* context = ctxInfo.grContext();
ericrkc4025182016-05-04 12:01:58 -0700842
bsalomone63ffef2016-02-05 07:17:34 -0800843 std::function<GrSurface*(SkSurface*)> grSurfaceGetters[] = {
egdanielab527a52016-06-28 08:07:26 -0700844 [] (SkSurface* s){
robertphillips175dd9b2016-04-28 14:32:04 -0700845 GrDrawContext* dc = s->getCanvas()->internal_private_accessTopLayerDrawContext();
846 return dc->accessRenderTarget(); },
bsalomone63ffef2016-02-05 07:17:34 -0800847 [] (SkSurface* s){
848 SkBaseDevice* d =
849 s->getCanvas()->getDevice_just_for_deprecated_compatibility_testing();
850 return d->accessRenderTarget(); },
reed9ce9d672016-03-17 10:51:11 -0700851 [] (SkSurface* s){ sk_sp<SkImage> i(s->makeImageSnapshot());
ericrkc4025182016-05-04 12:01:58 -0700852 return as_IB(i)->peekTexture(); }
bsalomone63ffef2016-02-05 07:17:34 -0800853 };
ericrkc4025182016-05-04 12:01:58 -0700854
bsalomone63ffef2016-02-05 07:17:34 -0800855 for (auto grSurfaceGetter : grSurfaceGetters) {
ericrkc4025182016-05-04 12:01:58 -0700856 // Test that non-wrapped RTs are created clear.
bsalomone63ffef2016-02-05 07:17:34 -0800857 for (auto& surface_func : {&create_gpu_surface, &create_gpu_scratch_surface}) {
reede8f30622016-03-23 18:59:25 -0700858 auto surface = surface_func(context, kPremul_SkAlphaType, nullptr);
bsalomone63ffef2016-02-05 07:17:34 -0800859 test_surface_clear(reporter, surface, grSurfaceGetter, 0x0);
860 }
861 // Wrapped RTs are *not* supposed to clear (to allow client to partially update a surface).
ericrkc4025182016-05-04 12:01:58 -0700862 const uint32_t kOrigColor = 0xABABABAB;
863 for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
864 &create_gpu_surface_backend_texture_as_render_target}) {
865 GrBackendObject textureObject;
866 auto surface = surfaceFunc(context, 0, kOrigColor, &textureObject);
867 test_surface_clear(reporter, surface, grSurfaceGetter, kOrigColor);
868 surface.reset();
869 context->getGpu()->deleteTestingOnlyBackendTexture(textureObject);
870 }
871 }
872}
bsalomone63ffef2016-02-05 07:17:34 -0800873
ericrkc4025182016-05-04 12:01:58 -0700874static void test_surface_draw_partially(
875 skiatest::Reporter* reporter, sk_sp<SkSurface> surface, uint32_t origColor) {
876 const int kW = surface->width();
877 const int kH = surface->height();
878 SkPaint paint;
879 const SkColor kRectColor = ~origColor | 0xFF000000;
880 paint.setColor(kRectColor);
881 surface->getCanvas()->drawRect(SkRect::MakeWH(SkIntToScalar(kW), SkIntToScalar(kH)/2),
882 paint);
883 SkAutoTDeleteArray<uint32_t> pixels(new uint32_t[kW * kH]);
884 sk_memset32(pixels.get(), ~origColor, kW * kH);
885 // Read back RGBA to avoid format conversions that may not be supported on all platforms.
886 SkImageInfo readInfo = SkImageInfo::Make(kW, kH, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
887 SkAssertResult(surface->readPixels(readInfo, pixels.get(), kW * sizeof(uint32_t), 0, 0));
888 bool stop = false;
889 SkPMColor origColorPM = SkPackARGB_as_RGBA((origColor >> 24 & 0xFF),
890 (origColor >> 0 & 0xFF),
891 (origColor >> 8 & 0xFF),
892 (origColor >> 16 & 0xFF));
893 SkPMColor rectColorPM = SkPackARGB_as_RGBA((kRectColor >> 24 & 0xFF),
894 (kRectColor >> 16 & 0xFF),
895 (kRectColor >> 8 & 0xFF),
896 (kRectColor >> 0 & 0xFF));
897 for (int y = 0; y < kH/2 && !stop; ++y) {
898 for (int x = 0; x < kW && !stop; ++x) {
899 REPORTER_ASSERT(reporter, rectColorPM == pixels[x + y * kW]);
900 if (rectColorPM != pixels[x + y * kW]) {
901 stop = true;
902 }
903 }
904 }
905 stop = false;
906 for (int y = kH/2; y < kH && !stop; ++y) {
907 for (int x = 0; x < kW && !stop; ++x) {
908 REPORTER_ASSERT(reporter, origColorPM == pixels[x + y * kW]);
909 if (origColorPM != pixels[x + y * kW]) {
910 stop = true;
911 }
912 }
913 }
914}
bsalomone63ffef2016-02-05 07:17:34 -0800915
egdanielab527a52016-06-28 08:07:26 -0700916DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfacePartialDraw_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700917 GrGpu* gpu = ctxInfo.grContext()->getGpu();
ericrkc4025182016-05-04 12:01:58 -0700918 if (!gpu) {
919 return;
920 }
921 static const uint32_t kOrigColor = 0xFFAABBCC;
bsalomone63ffef2016-02-05 07:17:34 -0800922
ericrkc4025182016-05-04 12:01:58 -0700923 for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
924 &create_gpu_surface_backend_texture_as_render_target}) {
925 // Validate that we can draw to the canvas and that the original texture color is
926 // preserved in pixels that aren't rendered to via the surface.
927 // This works only for non-multisampled case.
928 GrBackendObject textureObject;
bsalomon8b7451a2016-05-11 06:33:06 -0700929 auto surface = surfaceFunc(ctxInfo.grContext(), 0, kOrigColor, &textureObject);
ericrkc4025182016-05-04 12:01:58 -0700930 if (surface) {
931 test_surface_draw_partially(reporter, surface, kOrigColor);
932 surface.reset();
933 gpu->deleteTestingOnlyBackendTexture(textureObject);
934 }
935 }
936}
937
938
939DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceAttachStencil_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700940 GrGpu* gpu = ctxInfo.grContext()->getGpu();
ericrkc4025182016-05-04 12:01:58 -0700941 if (!gpu) {
942 return;
943 }
944 static const uint32_t kOrigColor = 0xFFAABBCC;
945
946 for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
947 &create_gpu_surface_backend_texture_as_render_target}) {
948 for (int sampleCnt : {0, 4, 8}) {
949 GrBackendObject textureObject;
bsalomon8b7451a2016-05-11 06:33:06 -0700950 auto surface = surfaceFunc(ctxInfo.grContext(), sampleCnt, kOrigColor, &textureObject);
ericrkc4025182016-05-04 12:01:58 -0700951
952 if (!surface && sampleCnt > 0) {
953 // Certain platforms don't support MSAA, skip these.
954 continue;
955 }
956
957 // Validate that we can attach a stencil buffer to an SkSurface created by either of
958 // our surface functions.
959 GrRenderTarget* rt = surface->getCanvas()->internal_private_accessTopLayerDrawContext()
960 ->accessRenderTarget();
961 REPORTER_ASSERT(reporter,
bsalomon8b7451a2016-05-11 06:33:06 -0700962 ctxInfo.grContext()->resourceProvider()->attachStencilAttachment(rt));
ericrkc4025182016-05-04 12:01:58 -0700963 gpu->deleteTestingOnlyBackendTexture(textureObject);
964 }
bsalomone63ffef2016-02-05 07:17:34 -0800965 }
966}
967#endif