• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright 2013 Google Inc.
3   *
4   * Use of this source code is governed by a BSD-style license that can be
5   * found in the LICENSE file.
6   */
7  
8  #include "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
19  class GrContextFactory;
20  class GrContext;
21  #endif
22  
23  enum SurfaceType {
24      kRaster_SurfaceType,
25      kRasterDirect_SurfaceType,
26      kGpu_SurfaceType,
27      kGpuScratch_SurfaceType,
28  };
29  
release_storage(void * pixels,void * context)30  static void release_storage(void* pixels, void* context) {
31      SkASSERT(pixels == context);
32      sk_free(pixels);
33  }
34  
createSurface(SurfaceType surfaceType,GrContext * context,SkImageInfo * requestedInfo=NULL)35  static 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  
60  enum ImageType {
61      kRasterCopy_ImageType,
62      kRasterData_ImageType,
63      kGpu_ImageType,
64      kCodec_ImageType,
65  };
66  
67  #include "SkImageGenerator.h"
68  
69  class EmptyGenerator : public SkImageGenerator {
70  public:
EmptyGenerator()71      EmptyGenerator() : SkImageGenerator(SkImageInfo::MakeN32Premul(0, 0)) {}
72  };
73  
test_empty_image(skiatest::Reporter * reporter)74  static 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  
test_empty_surface(skiatest::Reporter * reporter,GrContext * ctx)82  static 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
test_wrapped_texture_surface(skiatest::Reporter * reporter,GrContext * ctx)94  static 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  
test_image(skiatest::Reporter * reporter)132  static 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  
createImage(ImageType imageType,GrContext * context,SkColor color)146  static 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  
set_pixels(SkPMColor pixels[],int count,SkPMColor color)179  static void set_pixels(SkPMColor pixels[], int count, SkPMColor color) {
180      sk_memset32(pixels, color, count);
181  }
has_pixels(const SkPMColor pixels[],int count,SkPMColor expected)182  static 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  
test_image_readpixels(skiatest::Reporter * reporter,SkImage * image,SkPMColor expected)191  static 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  
test_imagepeek(skiatest::Reporter * reporter,GrContextFactory * factory)236  static 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  
test_canvaspeek(skiatest::Reporter * reporter,GrContextFactory * factory)285  static 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  
TestSurfaceCopyOnWrite(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context)353  static 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  
TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context)433  static 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
Test_crbug263329(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context)447  static 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  
TestGetTexture(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context)482  static 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  
is_budgeted(SkSurface * surf)503  SkSurface::Budgeted is_budgeted(SkSurface* surf) {
504      return ((SkSurface_Gpu*)surf)->getDevice()->accessRenderTarget()->resourcePriv().isBudgeted() ?
505          SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
506  }
507  
is_budgeted(SkImage * image)508  SkSurface::Budgeted is_budgeted(SkImage* image) {
509      return ((SkImage_Gpu*)image)->getTexture()->resourcePriv().isBudgeted() ?
510          SkSurface::kYes_Budgeted : SkSurface::kNo_Budgeted;
511  }
512  
test_surface_budget(skiatest::Reporter * reporter,GrContext * context)513  static 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  
TestSurfaceNoCanvas(skiatest::Reporter * reporter,SurfaceType surfaceType,GrContext * context,SkSurface::ContentChangeMode mode)544  static 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  
DEF_GPUTEST(Surface,reporter,factory)576  DEF_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
make_desc_image(GrContext * ctx,int w,int h,GrBackendObject texID,bool doCopy)622  static 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  
test_image_color(skiatest::Reporter * reporter,SkImage * image,SkPMColor expected)634  static 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  
DEF_GPUTEST(SkImage_NewFromTexture,reporter,factory)641  DEF_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