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 "SkCanvas.h"
9#include "SkData.h"
10#include "SkImageEncoder.h"
11#include "SkRRect.h"
12#include "SkSurface.h"
13#include "SkUtils.h"
14#include "Test.h"
15
16#if SK_SUPPORT_GPU
17#include "GrContextFactory.h"
18#else
19class GrContextFactory;
20class GrContext;
21#endif
22
23enum SurfaceType {
24    kRaster_SurfaceType,
25    kRasterDirect_SurfaceType,
26    kGpu_SurfaceType,
27    kGpuScratch_SurfaceType,
28};
29
30static void release_storage(void* pixels, void* context) {
31    SkASSERT(pixels == context);
32    sk_free(pixels);
33}
34
35static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context,
36                                SkImageInfo* requestedInfo = NULL) {
37    static const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
38
39    if (requestedInfo) {
40        *requestedInfo = info;
41    }
42
43    switch (surfaceType) {
44        case kRaster_SurfaceType:
45            return SkSurface::NewRaster(info);
46        case kRasterDirect_SurfaceType: {
47            const size_t rowBytes = info.minRowBytes();
48            void* storage = sk_malloc_throw(info.getSafeSize(rowBytes));
49            return SkSurface::NewRasterDirectReleaseProc(info, storage, rowBytes,
50                                                         release_storage, storage);
51        }
52        case kGpu_SurfaceType:
53            return SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0, NULL);
54        case kGpuScratch_SurfaceType:
55            return SkSurface::NewRenderTarget(context, SkSurface::kYes_Budgeted, info, 0, NULL);
56    }
57    return NULL;
58}
59
60enum ImageType {
61    kRasterCopy_ImageType,
62    kRasterData_ImageType,
63    kGpu_ImageType,
64    kCodec_ImageType,
65};
66
67#include "SkImageGenerator.h"
68
69class EmptyGenerator : public SkImageGenerator {
70public:
71    EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {}
72};
73
74static void test_empty_image(skiatest::Reporter* reporter) {
75    const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
76
77    REPORTER_ASSERT(reporter, NULL == SkImage::NewRasterCopy(info, NULL, 0));
78    REPORTER_ASSERT(reporter, NULL == SkImage::NewRasterData(info, NULL, 0));
79    REPORTER_ASSERT(reporter, NULL == SkImage::NewFromGenerator(SkNEW(EmptyGenerator)));
80}
81
82static void test_empty_surface(skiatest::Reporter* reporter, GrContext* ctx) {
83    const SkImageInfo info = SkImageInfo::Make(0, 0, kN32_SkColorType, kPremul_SkAlphaType);
84
85    REPORTER_ASSERT(reporter, NULL == SkSurface::NewRaster(info));
86    REPORTER_ASSERT(reporter, NULL == SkSurface::NewRasterDirect(info, NULL, 0));
87    if (ctx) {
88        REPORTER_ASSERT(reporter, NULL ==
89                        SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info, 0, NULL));
90    }
91}
92
93#if SK_SUPPORT_GPU
94static void test_wrapped_texture_surface(skiatest::Reporter* reporter, GrContext* ctx) {
95    if (NULL == ctx) {
96        return;
97    }
98    // Test the wrapped factory for SkSurface by creating a texture using ctx and then treat it as
99    // an external texture and wrap it in a SkSurface.
100
101    GrSurfaceDesc texDesc;
102    texDesc.fConfig = kRGBA_8888_GrPixelConfig;
103    texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
104    texDesc.fWidth = texDesc.fHeight = 100;
105    texDesc.fSampleCnt = 0;
106    texDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
107    SkAutoTUnref<GrSurface> dummySurface(ctx->textureProvider()->createTexture(texDesc, false));
108
109    REPORTER_ASSERT(reporter, dummySurface && dummySurface->asTexture() &&
110                              dummySurface->asRenderTarget());
111    if (!dummySurface || !dummySurface->asTexture() || !dummySurface->asRenderTarget()) {
112        return;
113    }
114
115    GrBackendObject textureHandle = dummySurface->asTexture()->getTextureHandle();
116
117    GrBackendTextureDesc wrappedDesc;
118    wrappedDesc.fConfig = dummySurface->config();
119    wrappedDesc.fWidth = dummySurface->width();
120    wrappedDesc.fHeight = dummySurface->height();
121    wrappedDesc.fOrigin = dummySurface->origin();
122    wrappedDesc.fSampleCnt = dummySurface->asRenderTarget()->numSamples();
123    wrappedDesc.fFlags = kRenderTarget_GrBackendTextureFlag;
124    wrappedDesc.fTextureHandle = textureHandle;
125
126    SkAutoTUnref<SkSurface> surface(SkSurface::NewWrappedRenderTarget(ctx, wrappedDesc, NULL));
127    REPORTER_ASSERT(reporter, surface);
128}
129#endif
130
131
132static void test_image(skiatest::Reporter* reporter) {
133    SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
134    size_t rowBytes = info.minRowBytes();
135    size_t size = info.getSafeSize(rowBytes);
136    SkData* data = SkData::NewUninitialized(size);
137
138    REPORTER_ASSERT(reporter, data->unique());
139    SkImage* image = SkImage::NewRasterData(info, data, rowBytes);
140    REPORTER_ASSERT(reporter, !data->unique());
141    image->unref();
142    REPORTER_ASSERT(reporter, data->unique());
143    data->unref();
144}
145
146static SkImage* createImage(ImageType imageType, GrContext* context, SkColor color) {
147    const SkPMColor pmcolor = SkPreMultiplyColor(color);
148    const SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
149    const size_t rowBytes = info.minRowBytes();
150    const size_t size = rowBytes * info.height();
151
152    SkAutoTUnref<SkData> data(SkData::NewUninitialized(size));
153    void* addr = data->writable_data();
154    sk_memset32((SkPMColor*)addr, pmcolor, SkToInt(size >> 2));
155
156    switch (imageType) {
157        case kRasterCopy_ImageType:
158            return SkImage::NewRasterCopy(info, addr, rowBytes);
159        case kRasterData_ImageType:
160            return SkImage::NewRasterData(info, data, rowBytes);
161        case kGpu_ImageType: {
162            SkAutoTUnref<SkSurface> surf(
163                SkSurface::NewRenderTarget(context, SkSurface::kNo_Budgeted, info, 0));
164            surf->getCanvas()->clear(color);
165            return surf->newImageSnapshot();
166        }
167        case kCodec_ImageType: {
168            SkBitmap bitmap;
169            bitmap.installPixels(info, addr, rowBytes);
170            SkAutoTUnref<SkData> src(
171                 SkImageEncoder::EncodeData(bitmap, SkImageEncoder::kPNG_Type, 100));
172            return SkImage::NewFromData(src);
173        }
174    }
175    SkASSERT(false);
176    return NULL;
177}
178
179static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) {
180    sk_memset32(pixels, color, count);
181}
182static bool has_pixels(const SkPMColor pixels[], int count, SkPMColor expected) {
183    for (int i = 0; i < count; ++i) {
184        if (pixels[i] != expected) {
185            return false;
186        }
187    }
188    return true;
189}
190
191static void test_image_readpixels(skiatest::Reporter* reporter, SkImage* image,
192                                  SkPMColor expected) {
193    const SkPMColor notExpected = ~expected;
194
195    const int w = 2, h = 2;
196    const size_t rowBytes = w * sizeof(SkPMColor);
197    SkPMColor pixels[w*h];
198
199    SkImageInfo info;
200
201    info = SkImageInfo::MakeUnknown(w, h);
202    REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, 0));
203
204    // out-of-bounds should fail
205    info = SkImageInfo::MakeN32Premul(w, h);
206    REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, -w, 0));
207    REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, -h));
208    REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, image->width(), 0));
209    REPORTER_ASSERT(reporter, !image->readPixels(info, pixels, rowBytes, 0, image->height()));
210
211    // top-left should succeed
212    set_pixels(pixels, w*h, notExpected);
213    REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, 0, 0));
214    REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
215
216    // bottom-right should succeed
217    set_pixels(pixels, w*h, notExpected);
218    REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
219                                                image->width() - w, image->height() - h));
220    REPORTER_ASSERT(reporter, has_pixels(pixels, w*h, expected));
221
222    // partial top-left should succeed
223    set_pixels(pixels, w*h, notExpected);
224    REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes, -1, -1));
225    REPORTER_ASSERT(reporter, pixels[3] == expected);
226    REPORTER_ASSERT(reporter, has_pixels(pixels, w*h - 1, notExpected));
227
228    // partial bottom-right should succeed
229    set_pixels(pixels, w*h, notExpected);
230    REPORTER_ASSERT(reporter, image->readPixels(info, pixels, rowBytes,
231                                                image->width() - 1, image->height() - 1));
232    REPORTER_ASSERT(reporter, pixels[0] == expected);
233    REPORTER_ASSERT(reporter, has_pixels(&pixels[1], w*h - 1, notExpected));
234}
235
236static void test_imagepeek(skiatest::Reporter* reporter, GrContextFactory* factory) {
237    static const struct {
238        ImageType   fType;
239        bool        fPeekShouldSucceed;
240        const char* fName;
241    } gRec[] = {
242        { kRasterCopy_ImageType,    true,       "RasterCopy"    },
243        { kRasterData_ImageType,    true,       "RasterData"    },
244        { kGpu_ImageType,           false,      "Gpu"           },
245        { kCodec_ImageType,         false,      "Codec"         },
246    };
247
248    const SkColor color = SK_ColorRED;
249    const SkPMColor pmcolor = SkPreMultiplyColor(color);
250
251    GrContext* ctx = NULL;
252#if SK_SUPPORT_GPU
253    ctx = factory->get(GrContextFactory::kNative_GLContextType);
254    if (NULL == ctx) {
255        return;
256    }
257#endif
258
259    for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
260        SkImageInfo info;
261        size_t rowBytes;
262
263        SkAutoTUnref<SkImage> image(createImage(gRec[i].fType, ctx, color));
264        if (!image.get()) {
265            SkDebugf("failed to createImage[%d] %s\n", i, gRec[i].fName);
266            continue;   // gpu may not be enabled
267        }
268        const void* addr = image->peekPixels(&info, &rowBytes);
269        bool success = SkToBool(addr);
270        REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
271        if (success) {
272            REPORTER_ASSERT(reporter, 10 == info.width());
273            REPORTER_ASSERT(reporter, 10 == info.height());
274            REPORTER_ASSERT(reporter, kN32_SkColorType == info.colorType());
275            REPORTER_ASSERT(reporter, kPremul_SkAlphaType == info.alphaType() ||
276                            kOpaque_SkAlphaType == info.alphaType());
277            REPORTER_ASSERT(reporter, info.minRowBytes() <= rowBytes);
278            REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
279        }
280
281        test_image_readpixels(reporter, image, pmcolor);
282    }
283}
284
285static void test_canvaspeek(skiatest::Reporter* reporter,
286                            GrContextFactory* factory) {
287    static const struct {
288        SurfaceType fType;
289        bool        fPeekShouldSucceed;
290    } gRec[] = {
291        { kRaster_SurfaceType,          true    },
292        { kRasterDirect_SurfaceType,    true    },
293#if SK_SUPPORT_GPU
294        { kGpu_SurfaceType,             false   },
295        { kGpuScratch_SurfaceType,      false   },
296#endif
297    };
298
299    const SkColor color = SK_ColorRED;
300    const SkPMColor pmcolor = SkPreMultiplyColor(color);
301
302    int cnt;
303#if SK_SUPPORT_GPU
304    cnt = GrContextFactory::kGLContextTypeCnt;
305#else
306    cnt = 1;
307#endif
308
309    for (int i= 0; i < cnt; ++i) {
310        GrContext* context = NULL;
311#if SK_SUPPORT_GPU
312        GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
313        if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
314            continue;
315        }
316        context = factory->get(glCtxType);
317
318        if (NULL == context) {
319            continue;
320        }
321#endif
322        for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
323            SkImageInfo info, requestInfo;
324            size_t rowBytes;
325
326            SkAutoTUnref<SkSurface> surface(createSurface(gRec[i].fType, context,
327                                                          &requestInfo));
328            surface->getCanvas()->clear(color);
329
330            const void* addr = surface->getCanvas()->peekPixels(&info, &rowBytes);
331            bool success = SkToBool(addr);
332            REPORTER_ASSERT(reporter, gRec[i].fPeekShouldSucceed == success);
333
334            SkImageInfo info2;
335            size_t rb2;
336            const void* addr2 = surface->peekPixels(&info2, &rb2);
337
338            if (success) {
339                REPORTER_ASSERT(reporter, requestInfo == info);
340                REPORTER_ASSERT(reporter, requestInfo.minRowBytes() <= rowBytes);
341                REPORTER_ASSERT(reporter, pmcolor == *(const SkPMColor*)addr);
342
343                REPORTER_ASSERT(reporter, addr2 == addr);
344                REPORTER_ASSERT(reporter, info2 == info);
345                REPORTER_ASSERT(reporter, rb2 == rowBytes);
346            } else {
347                REPORTER_ASSERT(reporter, NULL == addr2);
348            }
349        }
350    }
351}
352
353static void TestSurfaceCopyOnWrite(skiatest::Reporter* reporter, SurfaceType surfaceType,
354                                   GrContext* context) {
355    // Verify that the right canvas commands trigger a copy on write
356    SkSurface* surface = createSurface(surfaceType, context);
357    SkAutoTUnref<SkSurface> aur_surface(surface);
358    SkCanvas* canvas = surface->getCanvas();
359
360    const SkRect testRect =
361        SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
362                         SkIntToScalar(4), SkIntToScalar(5));
363    SkPath testPath;
364    testPath.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
365                                      SkIntToScalar(2), SkIntToScalar(1)));
366
367    const SkIRect testIRect = SkIRect::MakeXYWH(0, 0, 2, 1);
368
369    SkRegion testRegion;
370    testRegion.setRect(testIRect);
371
372
373    const SkColor testColor = 0x01020304;
374    const SkPaint testPaint;
375    const SkPoint testPoints[3] = {
376        {SkIntToScalar(0), SkIntToScalar(0)},
377        {SkIntToScalar(2), SkIntToScalar(1)},
378        {SkIntToScalar(0), SkIntToScalar(2)}
379    };
380    const size_t testPointCount = 3;
381
382    SkBitmap testBitmap;
383    testBitmap.allocN32Pixels(10, 10);
384    testBitmap.eraseColor(0);
385
386    SkRRect testRRect;
387    testRRect.setRectXY(testRect, SK_Scalar1, SK_Scalar1);
388
389    SkString testText("Hello World");
390    const SkPoint testPoints2[] = {
391        { SkIntToScalar(0), SkIntToScalar(1) },
392        { SkIntToScalar(1), SkIntToScalar(1) },
393        { SkIntToScalar(2), SkIntToScalar(1) },
394        { SkIntToScalar(3), SkIntToScalar(1) },
395        { SkIntToScalar(4), SkIntToScalar(1) },
396        { SkIntToScalar(5), SkIntToScalar(1) },
397        { SkIntToScalar(6), SkIntToScalar(1) },
398        { SkIntToScalar(7), SkIntToScalar(1) },
399        { SkIntToScalar(8), SkIntToScalar(1) },
400        { SkIntToScalar(9), SkIntToScalar(1) },
401        { SkIntToScalar(10), SkIntToScalar(1) },
402    };
403
404#define EXPECT_COPY_ON_WRITE(command)                               \
405    {                                                               \
406        SkImage* imageBefore = surface->newImageSnapshot();         \
407        SkAutoTUnref<SkImage> aur_before(imageBefore);              \
408        canvas-> command ;                                          \
409        SkImage* imageAfter = surface->newImageSnapshot();          \
410        SkAutoTUnref<SkImage> aur_after(imageAfter);                \
411        REPORTER_ASSERT(reporter, imageBefore != imageAfter);       \
412    }
413
414    EXPECT_COPY_ON_WRITE(clear(testColor))
415    EXPECT_COPY_ON_WRITE(drawPaint(testPaint))
416    EXPECT_COPY_ON_WRITE(drawPoints(SkCanvas::kPoints_PointMode, testPointCount, testPoints, \
417        testPaint))
418    EXPECT_COPY_ON_WRITE(drawOval(testRect, testPaint))
419    EXPECT_COPY_ON_WRITE(drawRect(testRect, testPaint))
420    EXPECT_COPY_ON_WRITE(drawRRect(testRRect, testPaint))
421    EXPECT_COPY_ON_WRITE(drawPath(testPath, testPaint))
422    EXPECT_COPY_ON_WRITE(drawBitmap(testBitmap, 0, 0))
423    EXPECT_COPY_ON_WRITE(drawBitmapRect(testBitmap, NULL, testRect))
424    EXPECT_COPY_ON_WRITE(drawBitmapNine(testBitmap, testIRect, testRect, NULL))
425    EXPECT_COPY_ON_WRITE(drawSprite(testBitmap, 0, 0, NULL))
426    EXPECT_COPY_ON_WRITE(drawText(testText.c_str(), testText.size(), 0, 1, testPaint))
427    EXPECT_COPY_ON_WRITE(drawPosText(testText.c_str(), testText.size(), testPoints2, \
428        testPaint))
429    EXPECT_COPY_ON_WRITE(drawTextOnPath(testText.c_str(), testText.size(), testPath, NULL, \
430        testPaint))
431}
432
433static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter,
434                                                    SurfaceType surfaceType,
435                                                    GrContext* context) {
436    // This test succeeds by not triggering an assertion.
437    // The test verifies that the surface remains writable (usable) after
438    // acquiring and releasing a snapshot without triggering a copy on write.
439    SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
440    SkCanvas* canvas = surface->getCanvas();
441    canvas->clear(1);
442    surface->newImageSnapshot()->unref();  // Create and destroy SkImage
443    canvas->clear(2);  // Must not assert internally
444}
445
446#if SK_SUPPORT_GPU
447static void Test_crbug263329(skiatest::Reporter* reporter,
448                             SurfaceType surfaceType,
449                             GrContext* context) {
450    // This is a regression test for crbug.com/263329
451    // Bug was caused by onCopyOnWrite releasing the old surface texture
452    // back to the scratch texture pool even though the texture is used
453    // by and active SkImage_Gpu.
454    SkAutoTUnref<SkSurface> surface1(createSurface(surfaceType, context));
455    SkAutoTUnref<SkSurface> surface2(createSurface(surfaceType, context));
456    SkCanvas* canvas1 = surface1->getCanvas();
457    SkCanvas* canvas2 = surface2->getCanvas();
458    canvas1->clear(1);
459    SkAutoTUnref<SkImage> image1(surface1->newImageSnapshot());
460    // Trigger copy on write, new backing is a scratch texture
461    canvas1->clear(2);
462    SkAutoTUnref<SkImage> image2(surface1->newImageSnapshot());
463    // Trigger copy on write, old backing should not be returned to scratch
464    // pool because it is held by image2
465    canvas1->clear(3);
466
467    canvas2->clear(4);
468    SkAutoTUnref<SkImage> image3(surface2->newImageSnapshot());
469    // Trigger copy on write on surface2. The new backing store should not
470    // be recycling a texture that is held by an existing image.
471    canvas2->clear(5);
472    SkAutoTUnref<SkImage> image4(surface2->newImageSnapshot());
473    REPORTER_ASSERT(reporter, image4->getTexture() != image3->getTexture());
474    // The following assertion checks crbug.com/263329
475    REPORTER_ASSERT(reporter, image4->getTexture() != image2->getTexture());
476    REPORTER_ASSERT(reporter, image4->getTexture() != image1->getTexture());
477    REPORTER_ASSERT(reporter, image3->getTexture() != image2->getTexture());
478    REPORTER_ASSERT(reporter, image3->getTexture() != image1->getTexture());
479    REPORTER_ASSERT(reporter, image2->getTexture() != image1->getTexture());
480}
481
482static void TestGetTexture(skiatest::Reporter* reporter,
483                                 SurfaceType surfaceType,
484                                 GrContext* context) {
485    SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
486    SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
487    GrTexture* texture = image->getTexture();
488    if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) {
489        REPORTER_ASSERT(reporter, texture);
490        REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle());
491    } else {
492        REPORTER_ASSERT(reporter, NULL == texture);
493    }
494    surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
495    REPORTER_ASSERT(reporter, image->getTexture() == texture);
496}
497
498#include "GrGpuResourcePriv.h"
499#include "SkGpuDevice.h"
500#include "SkImage_Gpu.h"
501#include "SkSurface_Gpu.h"
502
503SkSurface::Budgeted is_budgeted(SkSurface* surf) {
504    return ((SkSurface_Gpu*)surf)->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted() ?
505        SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
506}
507
508SkSurface::Budgeted is_budgeted(SkImage* image) {
509    return ((SkImage_Gpu*)image)->getTexture()->resourcePriv().isBudgeted() ?
510        SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
511}
512
513static void test_surface_budget(skiatest::Reporter* reporter, GrContext* context) {
514    SkImageInfo info = SkImageInfo::MakeN32Premul(8,8);
515    for (int i = 0; i < 2; ++i) {
516        SkSurface::Budgeted sbudgeted = i ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
517        for (int j = 0; j < 2; ++j) {
518            SkSurface::Budgeted ibudgeted = j ? SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
519            SkAutoTUnref<SkSurface>
520                surface(SkSurface::NewRenderTarget(context, sbudgeted, info, 0));
521            SkASSERT(surface);
522            REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
523
524            SkAutoTUnref<SkImage> image(surface->newImageSnapshot(ibudgeted));
525
526            // Initially the image shares a texture with the surface, and the surface decides
527            // whether it is budgeted or not.
528            REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
529            REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(image));
530
531            // Now trigger copy-on-write
532            surface->getCanvas()->clear(SK_ColorBLUE);
533
534            // They don't share a texture anymore. They should each have made their own budget
535            // decision.
536            REPORTER_ASSERT(reporter, sbudgeted == is_budgeted(surface));
537            REPORTER_ASSERT(reporter, ibudgeted == is_budgeted(image));
538        }
539    }
540}
541
542#endif
543
544static void TestSurfaceNoCanvas(skiatest::Reporter* reporter,
545                                          SurfaceType surfaceType,
546                                          GrContext* context,
547                                          SkSurface::ContentChangeMode mode) {
548    // Verifies the robustness of SkSurface for handling use cases where calls
549    // are made before a canvas is created.
550    {
551        // Test passes by not asserting
552        SkSurface* surface = createSurface(surfaceType, context);
553        SkAutoTUnref<SkSurface> aur_surface(surface);
554        surface->notifyContentWillChange(mode);
555        SkDEBUGCODE(surface->validate();)
556    }
557    {
558        SkSurface* surface = createSurface(surfaceType, context);
559        SkAutoTUnref<SkSurface> aur_surface(surface);
560        SkImage* image1 = surface->newImageSnapshot();
561        SkAutoTUnref<SkImage> aur_image1(image1);
562        SkDEBUGCODE(image1->validate();)
563        SkDEBUGCODE(surface->validate();)
564        surface->notifyContentWillChange(mode);
565        SkDEBUGCODE(image1->validate();)
566        SkDEBUGCODE(surface->validate();)
567        SkImage* image2 = surface->newImageSnapshot();
568        SkAutoTUnref<SkImage> aur_image2(image2);
569        SkDEBUGCODE(image2->validate();)
570        SkDEBUGCODE(surface->validate();)
571        REPORTER_ASSERT(reporter, image1 != image2);
572    }
573
574}
575
576DEF_GPUTEST(Surface, reporter, factory) {
577    test_image(reporter);
578
579    TestSurfaceCopyOnWrite(reporter, kRaster_SurfaceType, NULL);
580    TestSurfaceWritableAfterSnapshotRelease(reporter, kRaster_SurfaceType, NULL);
581    TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kDiscard_ContentChangeMode);
582    TestSurfaceNoCanvas(reporter, kRaster_SurfaceType, NULL, SkSurface::kRetain_ContentChangeMode);
583
584    test_empty_image(reporter);
585    test_empty_surface(reporter, NULL);
586
587    test_imagepeek(reporter, factory);
588    test_canvaspeek(reporter, factory);
589
590#if SK_SUPPORT_GPU
591    TestGetTexture(reporter, kRaster_SurfaceType, NULL);
592    if (factory) {
593        for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
594            GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
595            if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
596                continue;
597            }
598            GrContext* context = factory->get(glCtxType);
599            if (context) {
600                Test_crbug263329(reporter, kGpu_SurfaceType, context);
601                Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
602                TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
603                TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context);
604                TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context);
605                TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context);
606                TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
607                TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
608                TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
609                TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
610                TestGetTexture(reporter, kGpu_SurfaceType, context);
611                TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
612                test_empty_surface(reporter, context);
613                test_surface_budget(reporter, context);
614                test_wrapped_texture_surface(reporter, context);
615            }
616        }
617    }
618#endif
619}
620
621#if SK_SUPPORT_GPU
622static SkImage* make_desc_image(GrContext* ctx, int w, int h, GrBackendObject texID, bool doCopy) {
623    GrBackendTextureDesc desc;
624    desc.fConfig = kSkia8888_GrPixelConfig;
625    // need to be a rendertarget for now...
626    desc.fFlags = kRenderTarget_GrBackendTextureFlag;
627    desc.fWidth = w;
628    desc.fHeight = h;
629    desc.fSampleCnt = 0;
630    desc.fTextureHandle = texID;
631    return doCopy ? SkImage::NewFromTextureCopy(ctx, desc) : SkImage::NewFromTexture(ctx, desc);
632}
633
634static void test_image_color(skiatest::Reporter* reporter, SkImage* image, SkPMColor expected) {
635    const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
636    SkPMColor pixel;
637    REPORTER_ASSERT(reporter, image->readPixels(info, &pixel, sizeof(pixel), 0, 0));
638    REPORTER_ASSERT(reporter, pixel == expected);
639}
640
641DEF_GPUTEST(SkImage_NewFromTexture, reporter, factory) {
642    GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
643    if (!ctx) {
644        REPORTER_ASSERT(reporter, false);
645        return;
646    }
647    GrTextureProvider* provider = ctx->textureProvider();
648
649    const int w = 10;
650    const int h = 10;
651    SkPMColor storage[w * h];
652    const SkPMColor expected0 = SkPreMultiplyColor(SK_ColorRED);
653    sk_memset32(storage, expected0, w * h);
654
655    GrSurfaceDesc desc;
656    desc.fFlags = kRenderTarget_GrSurfaceFlag;  // needs to be a rendertarget for readpixels();
657    desc.fOrigin = kDefault_GrSurfaceOrigin;
658    desc.fWidth = w;
659    desc.fHeight = h;
660    desc.fConfig = kSkia8888_GrPixelConfig;
661    desc.fSampleCnt = 0;
662
663    SkAutoTUnref<GrTexture> tex(provider->createTexture(desc, false, storage, w * 4));
664    if (!tex) {
665        REPORTER_ASSERT(reporter, false);
666        return;
667    }
668
669    GrBackendObject srcTex = tex->getTextureHandle();
670    SkAutoTUnref<SkImage> refImg(make_desc_image(ctx, w, h, srcTex, false));
671    SkAutoTUnref<SkImage> cpyImg(make_desc_image(ctx, w, h, srcTex, true));
672
673    test_image_color(reporter, refImg, expected0);
674    test_image_color(reporter, cpyImg, expected0);
675
676    // Now lets jam new colors into our "external" texture, and see if the images notice
677    const SkPMColor expected1 = SkPreMultiplyColor(SK_ColorBLUE);
678    sk_memset32(storage, expected1, w * h);
679    tex->writePixels(0, 0, w, h, kSkia8888_GrPixelConfig, storage, GrContext::kFlushWrites_PixelOp);
680
681    // We expect the ref'd image to see the new color, but cpy'd one should still see the old color
682    test_image_color(reporter, refImg, expected1);
683    test_image_color(reporter, cpyImg, expected0);
684}
685#endif
686