2013-07-25 21:34:00 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2013 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gm.h"
|
2013-09-06 14:16:12 +00:00
|
|
|
#include "SkBlurMask.h"
|
2013-08-20 16:51:20 +00:00
|
|
|
#include "SkBlurMaskFilter.h"
|
2013-09-06 14:16:12 +00:00
|
|
|
#include "SkCanvas.h"
|
2015-10-23 18:13:01 +00:00
|
|
|
#include "SkGradientShader.h"
|
2015-07-14 17:54:12 +00:00
|
|
|
#include "SkImage.h"
|
2015-11-02 20:33:21 +00:00
|
|
|
#include "SkUtils.h"
|
2013-07-25 21:34:00 +00:00
|
|
|
|
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
#include "GrContext.h"
|
2015-05-27 20:23:23 +00:00
|
|
|
#include "GrContextOptions.h"
|
2015-11-02 20:33:21 +00:00
|
|
|
#include "SkGr.h"
|
2013-07-25 21:34:00 +00:00
|
|
|
#endif
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
/** Holds either a bitmap or image to be rendered and a rect that indicates what part of the bitmap
|
|
|
|
or image should be tested by the GM. The area outside of the rect is present to check
|
|
|
|
for bleed due to filtering/blurring. */
|
|
|
|
struct TestPixels {
|
|
|
|
enum Type {
|
|
|
|
kBitmap,
|
|
|
|
kImage
|
|
|
|
};
|
|
|
|
Type fType;
|
|
|
|
SkBitmap fBitmap;
|
|
|
|
SkAutoTUnref<SkImage> fImage;
|
|
|
|
SkIRect fRect; // The region of the bitmap/image that should be rendered.
|
|
|
|
};
|
2015-11-02 20:33:21 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
/** Creates a bitmap with two one-pixel rings around a checkerboard. The checkerboard is 2x2
|
|
|
|
logically where each check has as many pixels as is necessary to fill the interior. The rect
|
|
|
|
to draw is set to the checkerboard portion. */
|
|
|
|
template<typename PIXEL_TYPE>
|
|
|
|
bool make_ringed_bitmap(GrContext*, TestPixels* result, int width, int height,
|
|
|
|
SkColorType ct, SkAlphaType at,
|
|
|
|
PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor,
|
|
|
|
PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2) {
|
2013-11-08 15:09:22 +00:00
|
|
|
SkASSERT(0 == width % 2 && 0 == height % 2);
|
2015-11-09 18:06:06 +00:00
|
|
|
SkASSERT(width >= 6 && height >= 6);
|
2013-11-09 07:02:23 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
result->fType = TestPixels::kBitmap;
|
|
|
|
SkImageInfo info = SkImageInfo::Make(width, height, ct, at);
|
|
|
|
size_t rowBytes = SkAlign4(info.minRowBytes());
|
|
|
|
result->fBitmap.allocPixels(info, rowBytes);
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
PIXEL_TYPE* scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 0);
|
2013-07-25 21:34:00 +00:00
|
|
|
for (int x = 0; x < width; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = outerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 1);
|
|
|
|
scanline[0] = outerRingColor;
|
2013-11-08 15:09:22 +00:00
|
|
|
for (int x = 1; x < width - 1; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = innerRingColor;
|
2013-11-08 15:09:22 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[width - 1] = outerRingColor;
|
|
|
|
|
|
|
|
for (int y = 2; y < height / 2; ++y) {
|
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
|
|
|
|
scanline[0] = outerRingColor;
|
|
|
|
scanline[1] = innerRingColor;
|
|
|
|
for (int x = 2; x < width / 2; ++x) {
|
|
|
|
scanline[x] = checkColor1;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int x = width / 2; x < width - 2; ++x) {
|
|
|
|
scanline[x] = checkColor2;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[width - 2] = innerRingColor;
|
|
|
|
scanline[width - 1] = outerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int y = height / 2; y < height - 2; ++y) {
|
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
|
|
|
|
scanline[0] = outerRingColor;
|
|
|
|
scanline[1] = innerRingColor;
|
|
|
|
for (int x = 2; x < width / 2; ++x) {
|
|
|
|
scanline[x] = checkColor2;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int x = width / 2; x < width - 2; ++x) {
|
|
|
|
scanline[x] = checkColor1;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[width - 2] = innerRingColor;
|
|
|
|
scanline[width - 1] = outerRingColor;
|
2013-11-08 15:09:22 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 2);
|
|
|
|
scanline[0] = outerRingColor;
|
2013-11-08 15:09:22 +00:00
|
|
|
for (int x = 1; x < width - 1; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = innerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[width - 1] = outerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 1);
|
2013-07-25 21:34:00 +00:00
|
|
|
for (int x = 0; x < width; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = outerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
result->fBitmap.setImmutable();
|
|
|
|
result->fRect.set(2, 2, width - 2, height - 2);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Create a black and white checked texture with 2 1-pixel rings around the outside edge.
|
|
|
|
The inner ring is red and the outer ring is blue. */
|
|
|
|
static bool make_ringed_color_bitmap(GrContext* ctx, TestPixels* result, int width, int height) {
|
|
|
|
static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
|
|
|
|
static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
|
|
|
|
static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
|
|
|
|
static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
|
|
|
|
return make_ringed_bitmap<SkPMColor>(ctx, result, width, height, kBGRA_8888_SkColorType,
|
|
|
|
kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-11-04 12:23:45 +00:00
|
|
|
/** Makes a alpha bitmap with 1 wide rect/ring of 0s, an inset of 1s, and the interior is a 2x2
|
2015-10-23 18:13:01 +00:00
|
|
|
checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
|
|
|
|
the 2x2 checker grid. */
|
2015-11-09 18:06:06 +00:00
|
|
|
static bool make_ringed_alpha_bitmap(GrContext* ctx, TestPixels* result, int width, int height) {
|
|
|
|
static const uint8_t kZero = 0x00;
|
|
|
|
static const uint8_t kHalf = 0x80;
|
|
|
|
static const uint8_t k3Q = 0xC0;
|
|
|
|
static const uint8_t kOne = 0xFF;
|
|
|
|
return make_ringed_bitmap<uint8_t>(ctx, result, width, height, kAlpha_8_SkColorType,
|
|
|
|
kPremul_SkAlphaType, kZero, kOne, k3Q, kHalf);
|
|
|
|
}
|
2015-10-23 18:13:01 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
/** Helper to reuse above functions to produce images rather than bmps */
|
|
|
|
static void bmp_to_image(TestPixels* result) {
|
|
|
|
SkASSERT(TestPixels::kBitmap == result->fType);
|
|
|
|
result->fImage.reset(SkImage::NewFromBitmap(result->fBitmap));
|
|
|
|
SkASSERT(result->fImage);
|
|
|
|
result->fType = TestPixels::kImage;
|
|
|
|
result->fBitmap.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Color image case. */
|
|
|
|
bool make_ringed_color_image(GrContext* ctx, TestPixels* result, int width, int height) {
|
|
|
|
if (make_ringed_color_bitmap(ctx, result, width, height)) {
|
|
|
|
bmp_to_image(result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Alpha image case. */
|
|
|
|
bool make_ringed_alpha_image(GrContext* ctx, TestPixels* result, int width, int height) {
|
|
|
|
if (make_ringed_alpha_bitmap(ctx, result, width, height)) {
|
|
|
|
bmp_to_image(result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Similar to make_ringed_bitmap with these modifications:
|
|
|
|
- The backing store is a texture.
|
|
|
|
- The texture is larger than the bitmap dimensions (it is surrounded by non-content
|
|
|
|
padding on the right/bottom of the contents.)
|
|
|
|
- The right/bottom sides of the rings are omitted so that the rect to draw is adjacent to
|
|
|
|
the texture padding.
|
|
|
|
*/
|
|
|
|
template <typename PIXEL_TYPE>
|
|
|
|
bool make_oversized_texture_bitmap(GrContext* ctx, TestPixels* result, int width, int height,
|
|
|
|
GrPixelConfig config, PIXEL_TYPE outerRingColor,
|
|
|
|
PIXEL_TYPE innerRingColor, PIXEL_TYPE checkColor1,
|
|
|
|
PIXEL_TYPE checkColor2, PIXEL_TYPE padColor) {
|
|
|
|
SkASSERT(0 == width % 2 && 0 == height % 2);
|
|
|
|
SkASSERT(width >= 6 && height >= 6);
|
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
if (!ctx) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/** Put arbitrary pad to the right and below the bitmap content. */
|
|
|
|
static const int kXPad = 10;
|
|
|
|
static const int kYPad = 17;
|
|
|
|
size_t rowBytes = (width + kXPad) * sizeof(PIXEL_TYPE);
|
|
|
|
SkAutoTMalloc<PIXEL_TYPE> pixels(rowBytes*(height + kYPad));
|
2015-10-23 18:13:01 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
PIXEL_TYPE* scanline = pixels.get();
|
2015-10-23 18:13:01 +00:00
|
|
|
for (int x = 0; x < width; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = outerRingColor;
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int x = width; x < width + kXPad; ++x) {
|
|
|
|
scanline[x] = padColor;
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes);
|
|
|
|
scanline[0] = outerRingColor;
|
|
|
|
for (int x = 1; x < width; ++x) {
|
|
|
|
scanline[x] = innerRingColor;
|
|
|
|
}
|
|
|
|
for (int x = width; x < width + kXPad; ++x) {
|
|
|
|
scanline[x] = padColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int y = 2; y < height / 2 + 1; ++y) {
|
|
|
|
scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes);
|
|
|
|
scanline[0] = outerRingColor;
|
|
|
|
scanline[1] = innerRingColor;
|
|
|
|
for (int x = 2; x < width / 2 + 1; ++x) {
|
|
|
|
scanline[x] = checkColor1;
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int x = width / 2 + 1; x < width; ++x) {
|
|
|
|
scanline[x] = checkColor2;
|
|
|
|
}
|
|
|
|
for (int x = width; x < width + kXPad; ++x) {
|
|
|
|
scanline[x] = padColor;
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int y = height / 2 + 1; y < height; ++y) {
|
|
|
|
scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes);
|
|
|
|
scanline[0] = outerRingColor;
|
|
|
|
scanline[1] = innerRingColor;
|
|
|
|
for (int x = 2; x < width / 2 + 1; ++x) {
|
|
|
|
scanline[x] = checkColor2;
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int x = width / 2 + 1; x < width; ++x) {
|
|
|
|
scanline[x] = checkColor1;
|
|
|
|
}
|
|
|
|
for (int x = width; x < width + kXPad; ++x) {
|
|
|
|
scanline[x] = padColor;
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int y = height; y < height + kYPad; ++y) {
|
|
|
|
scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes);
|
|
|
|
for (int x = 0; x < width + kXPad; ++x) {
|
|
|
|
scanline[x] = padColor;
|
|
|
|
}
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
GrSurfaceDesc desc;
|
|
|
|
desc.fConfig = config;
|
|
|
|
desc.fWidth = width + kXPad;
|
|
|
|
desc.fHeight = height + kYPad;
|
2016-02-25 16:33:02 +00:00
|
|
|
SkAutoTUnref<GrTexture> texture(ctx->textureProvider()->createTexture(
|
|
|
|
desc, SkBudgeted::kYes, pixels.get(), rowBytes));
|
2015-11-09 18:06:06 +00:00
|
|
|
|
|
|
|
if (!texture) {
|
|
|
|
return false;
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
|
|
|
|
GrWrapTextureInBitmap(texture, width, height, true, &result->fBitmap);
|
|
|
|
result->fType = TestPixels::kBitmap;
|
|
|
|
result->fBitmap.setImmutable();
|
|
|
|
result->fRect.set(2, 2, width, height);
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Make the color version of the oversized texture-backed bitmap */
|
|
|
|
static bool make_ringed_oversized_color_texture_bitmap(GrContext* ctx, TestPixels* result,
|
|
|
|
int width, int height) {
|
|
|
|
static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
|
|
|
|
static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
|
|
|
|
static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
|
|
|
|
static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
|
|
|
|
static const SkPMColor kGreen = SkPreMultiplyColor(SK_ColorGREEN);
|
|
|
|
return make_oversized_texture_bitmap<SkPMColor>(
|
|
|
|
ctx, result, width, height, kSkia8888_GrPixelConfig, kBlue, kRed, kBlack, kWhite, kGreen);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Make the alpha version of the oversized texture-backed bitmap */
|
|
|
|
static bool make_ringed_oversized_alpha_texture_bitmap(GrContext* ctx, TestPixels* result,
|
|
|
|
int width, int height) {
|
|
|
|
static const uint8_t kZero = 0x00;
|
|
|
|
static const uint8_t kHalf = 0x80;
|
|
|
|
static const uint8_t k3Q = 0xC0;
|
|
|
|
static const uint8_t kOne = 0xFF;
|
|
|
|
static const uint8_t k1Q = 0x40;
|
|
|
|
return make_oversized_texture_bitmap<uint8_t>(
|
|
|
|
ctx, result, width, height, kAlpha_8_GrPixelConfig, kZero, kOne, k3Q, kHalf, k1Q);
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
static sk_sp<SkShader> make_shader() {
|
2015-10-23 18:13:01 +00:00
|
|
|
static const SkPoint pts[] = { {0, 0}, {20, 20} };
|
|
|
|
static const SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
|
2016-03-09 17:50:50 +00:00
|
|
|
return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
static sk_sp<SkShader> make_null_shader() { return nullptr; }
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
enum BleedTest {
|
|
|
|
kUseBitmap_BleedTest,
|
2015-11-02 20:33:21 +00:00
|
|
|
kUseTextureBitmap_BleedTest,
|
2015-10-23 18:13:01 +00:00
|
|
|
kUseImage_BleedTest,
|
|
|
|
kUseAlphaBitmap_BleedTest,
|
2015-11-02 20:33:21 +00:00
|
|
|
kUseAlphaTextureBitmap_BleedTest,
|
2015-10-23 18:13:01 +00:00
|
|
|
kUseAlphaImage_BleedTest,
|
|
|
|
kUseAlphaBitmapShader_BleedTest,
|
2015-11-02 20:33:21 +00:00
|
|
|
kUseAlphaTextureBitmapShader_BleedTest,
|
2015-10-23 18:13:01 +00:00
|
|
|
kUseAlphaImageShader_BleedTest,
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct {
|
|
|
|
const char* fName;
|
2015-11-09 18:06:06 +00:00
|
|
|
bool (*fPixelMaker)(GrContext*, TestPixels* result, int width, int height);
|
2016-03-09 17:50:50 +00:00
|
|
|
sk_sp<SkShader> (*fShaderMaker)();
|
2015-10-23 18:13:01 +00:00
|
|
|
} gBleedRec[] = {
|
2015-11-09 18:06:06 +00:00
|
|
|
{ "bleed", make_ringed_color_bitmap, make_null_shader },
|
|
|
|
{ "bleed_texture_bmp", make_ringed_oversized_color_texture_bitmap, make_null_shader },
|
|
|
|
{ "bleed_image", make_ringed_color_image, make_null_shader },
|
|
|
|
{ "bleed_alpha_bmp", make_ringed_alpha_bitmap, make_null_shader },
|
|
|
|
{ "bleed_alpha_texture_bmp", make_ringed_oversized_alpha_texture_bitmap, make_null_shader },
|
|
|
|
{ "bleed_alpha_image", make_ringed_alpha_image, make_null_shader },
|
|
|
|
{ "bleed_alpha_bmp_shader", make_ringed_alpha_bitmap, make_shader },
|
|
|
|
{ "bleed_alpha_texture_bmp_shader", make_ringed_oversized_alpha_texture_bitmap, make_shader },
|
|
|
|
{ "bleed_alpha_image_shader", make_ringed_alpha_image, make_shader },
|
2015-10-23 18:13:01 +00:00
|
|
|
};
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
/** This GM exercises the behavior of the drawBitmapRect & drawImageRect calls. Specifically their
|
|
|
|
handling of :
|
|
|
|
- SrcRectConstraint(bleed vs.no - bleed)
|
|
|
|
- handling of the sub - region feature(area - of - interest) of drawBitmap*
|
|
|
|
- handling of 8888 vs. A8 (including presence of a shader in the A8 case).
|
|
|
|
- (gpu - only) handling of tiled vs.non - tiled drawing)
|
|
|
|
- (gpu - only) texture's backing a bmp where the texture is larger than the bmp.
|
|
|
|
In particular, we should never see the padding outside of an SkBitmap's sub - region (green for
|
|
|
|
8888, 1/4 for alpha). In some instances we can see the two outer rings outside of the area o
|
|
|
|
interest (i.e., the inner four checks) due to AA or filtering if allowed by the
|
|
|
|
SrcRectConstraint.
|
|
|
|
*/
|
2013-07-25 21:34:00 +00:00
|
|
|
class BleedGM : public skiagm::GM {
|
|
|
|
public:
|
2015-11-09 18:06:06 +00:00
|
|
|
BleedGM(BleedTest bt) : fCreatedPixels(false), fBT(bt){}
|
2013-07-25 21:34:00 +00:00
|
|
|
|
|
|
|
protected:
|
2014-04-30 13:20:45 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkString onShortName() override {
|
2015-07-14 17:54:12 +00:00
|
|
|
return SkString(gBleedRec[fBT].fName);
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkISize onISize() override {
|
2015-11-04 12:36:12 +00:00
|
|
|
return SkISize::Make(1200, 1080);
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
void drawPixels(SkCanvas* canvas, const TestPixels& pixels, const SkRect& src,
|
|
|
|
const SkRect& dst, const SkPaint* paint,
|
|
|
|
SkCanvas::SrcRectConstraint constraint) {
|
|
|
|
if (TestPixels::kBitmap == pixels.fType) {
|
|
|
|
canvas->drawBitmapRect(pixels.fBitmap, src, dst, paint, constraint);
|
|
|
|
} else {
|
|
|
|
canvas->drawImageRect(pixels.fImage, src, dst, paint, constraint);
|
|
|
|
}
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw the area of interest of the small image
|
2015-10-23 18:13:01 +00:00
|
|
|
void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
|
|
|
|
SkRect src = SkRect::Make(fSmallTestPixels.fRect);
|
2015-07-14 17:54:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
2013-07-26 07:00:58 +00:00
|
|
|
|
2013-08-20 12:09:32 +00:00
|
|
|
SkPaint paint;
|
2015-03-16 17:08:34 +00:00
|
|
|
paint.setFilterQuality(filter);
|
2015-10-23 18:13:01 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
2013-08-20 12:09:32 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
|
2013-08-20 12:09:32 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw the area of interest of the large image
|
2015-10-23 18:13:01 +00:00
|
|
|
void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
SkRect src = SkRect::Make(fBigTestPixels.fRect);
|
2015-07-14 17:54:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
2013-07-25 21:34:00 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
2015-03-16 17:08:34 +00:00
|
|
|
paint.setFilterQuality(filter);
|
2015-10-23 18:13:01 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
|
2013-08-20 12:09:32 +00:00
|
|
|
}
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw upper-left 1/4 of the area of interest of the large image
|
2015-10-23 18:13:01 +00:00
|
|
|
void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
SkRect src = SkRect::MakeXYWH(SkIntToScalar(fBigTestPixels.fRect.fLeft),
|
|
|
|
SkIntToScalar(fBigTestPixels.fRect.fTop),
|
|
|
|
fBigTestPixels.fRect.width()/2.f,
|
|
|
|
fBigTestPixels.fRect.height()/2.f);
|
2015-07-14 17:54:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2013-08-20 12:09:32 +00:00
|
|
|
SkPaint paint;
|
2015-03-16 17:08:34 +00:00
|
|
|
paint.setFilterQuality(filter);
|
2015-10-23 18:13:01 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
|
2013-08-20 12:09:32 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw the area of interest of the small image with a normal blur
|
2015-10-23 18:13:01 +00:00
|
|
|
void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
SkRect src = SkRect::Make(fSmallTestPixels.fRect);
|
2015-07-14 17:54:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
2013-08-20 16:51:20 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
2015-03-16 17:08:34 +00:00
|
|
|
paint.setFilterQuality(filter);
|
2014-04-28 16:25:35 +00:00
|
|
|
SkMaskFilter* mf = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkBlurMask::ConvertRadiusToSigma(3));
|
2013-08-20 16:51:20 +00:00
|
|
|
paint.setMaskFilter(mf)->unref();
|
2015-10-23 18:13:01 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
2013-08-20 16:51:20 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
|
2013-08-20 16:51:20 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw the area of interest of the small image with a outer blur
|
2015-11-04 12:36:12 +00:00
|
|
|
void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
|
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
SkRect src = SkRect::Make(fSmallTestPixels.fRect);
|
2015-11-04 12:36:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setFilterQuality(filter);
|
|
|
|
SkMaskFilter* mf = SkBlurMaskFilter::Create(kOuter_SkBlurStyle,
|
|
|
|
SkBlurMask::ConvertRadiusToSigma(7));
|
|
|
|
paint.setMaskFilter(mf)->unref();
|
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
|
2015-11-04 12:36:12 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2015-11-09 18:06:06 +00:00
|
|
|
// We don't create pixels in an onOnceBeforeDraw() override because we want access to
|
|
|
|
// GrContext.
|
|
|
|
GrContext* context = canvas->getGrContext();
|
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
// Workaround for SampleApp.
|
|
|
|
if (GrTexture* tex = fBigTestPixels.fBitmap.getTexture()) {
|
|
|
|
if (tex->wasDestroyed()) {
|
|
|
|
fCreatedPixels = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
bool madePixels = fCreatedPixels;
|
|
|
|
|
|
|
|
if (!madePixels) {
|
|
|
|
madePixels = gBleedRec[fBT].fPixelMaker(context, &fSmallTestPixels, kSmallTextureSize,
|
|
|
|
kSmallTextureSize);
|
|
|
|
madePixels &= gBleedRec[fBT].fPixelMaker(context, &fBigTestPixels, 2 * kMaxTileSize,
|
|
|
|
2 * kMaxTileSize);
|
|
|
|
fCreatedPixels = madePixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assume that if we coulnd't make the bitmap/image it's because it's a GPU test on a
|
|
|
|
// non-GPU backend.
|
|
|
|
if (!madePixels) {
|
|
|
|
skiagm::GM::DrawGpuOnlyMessage(canvas);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
fShader = gBleedRec[fBT].fShaderMaker();
|
2015-11-09 18:06:06 +00:00
|
|
|
|
2013-08-20 12:09:32 +00:00
|
|
|
canvas->clear(SK_ColorGRAY);
|
2015-10-23 18:13:01 +00:00
|
|
|
SkTDArray<SkMatrix> matrices;
|
|
|
|
// Draw with identity
|
|
|
|
*matrices.append() = SkMatrix::I();
|
|
|
|
|
|
|
|
// Draw with rotation and scale down in x, up in y.
|
|
|
|
SkMatrix m;
|
2015-11-04 12:36:12 +00:00
|
|
|
static const SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
|
2015-10-23 18:13:01 +00:00
|
|
|
m.setTranslate(0, kBottom);
|
|
|
|
m.preRotate(15.f, 0, kBottom + kBlockSpacing);
|
|
|
|
m.preScale(0.71f, 1.22f);
|
|
|
|
*matrices.append() = m;
|
|
|
|
|
|
|
|
// Align the next set with the middle of the previous in y, translated to the right in x.
|
|
|
|
SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
|
|
|
|
matrices[matrices.count()-1].mapPoints(corners, 4);
|
|
|
|
SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
|
|
|
|
SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
|
|
|
|
SkTMax(corners[2].fX, corners[3].fX));
|
|
|
|
m.setTranslate(x, y);
|
|
|
|
m.preScale(0.2f, 0.2f);
|
|
|
|
*matrices.append() = m;
|
|
|
|
|
|
|
|
SkScalar maxX = 0;
|
|
|
|
for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
|
2013-11-22 20:34:59 +00:00
|
|
|
canvas->save();
|
2015-10-23 18:13:01 +00:00
|
|
|
canvas->translate(maxX, 0);
|
|
|
|
for (int m = 0; m < matrices.count(); ++m) {
|
|
|
|
canvas->save();
|
|
|
|
canvas->concat(matrices[m]);
|
|
|
|
bool aa = SkToBool(antiAlias);
|
|
|
|
|
|
|
|
// First draw a column with no bleeding and no filtering
|
|
|
|
this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Then draw a column with no bleeding and low filtering
|
|
|
|
this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Then draw a column with no bleeding and high filtering
|
|
|
|
this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
|
|
|
|
this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Then draw a column with bleeding and low filtering
|
|
|
|
this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Finally draw a column with bleeding and high filtering
|
|
|
|
this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
|
|
|
|
matrices[m].mapPoints(corners, 4);
|
|
|
|
SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
|
|
|
|
SkTMax(corners[2].fX, corners[3].fX));
|
|
|
|
maxX = SkTMax(maxX, x);
|
|
|
|
canvas->restore();
|
2013-11-22 20:34:59 +00:00
|
|
|
}
|
|
|
|
canvas->restore();
|
|
|
|
}
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 20:23:23 +00:00
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
void modifyGrContextOptions(GrContextOptions* options) override {
|
2015-11-02 19:36:52 +00:00
|
|
|
options->fMaxTileSizeOverride = kMaxTileSize;
|
2015-05-27 20:23:23 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-25 21:34:00 +00:00
|
|
|
private:
|
2013-11-08 15:09:22 +00:00
|
|
|
static const int kBlockSize = 70;
|
2015-11-04 12:36:12 +00:00
|
|
|
static const int kBlockSpacing = 12;
|
2013-08-20 12:09:32 +00:00
|
|
|
|
|
|
|
static const int kCol0X = kBlockSpacing;
|
|
|
|
static const int kCol1X = 2*kBlockSpacing + kBlockSize;
|
|
|
|
static const int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
|
|
|
|
static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
|
2013-11-08 15:09:22 +00:00
|
|
|
static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
|
|
|
|
static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
|
2015-05-27 20:23:23 +00:00
|
|
|
static const int kWidth = 7*kBlockSpacing + 6*kBlockSize;
|
2013-08-20 12:09:32 +00:00
|
|
|
|
|
|
|
static const int kRow0Y = kBlockSpacing;
|
|
|
|
static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
|
|
|
|
static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
|
2013-08-20 16:51:20 +00:00
|
|
|
static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
|
2015-11-04 12:36:12 +00:00
|
|
|
static const int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2013-11-08 15:09:22 +00:00
|
|
|
static const int kSmallTextureSize = 6;
|
2015-11-02 19:36:52 +00:00
|
|
|
static const int kMaxTileSize = 32;
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
bool fCreatedPixels;
|
|
|
|
TestPixels fBigTestPixels;
|
|
|
|
TestPixels fSmallTestPixels;
|
2015-10-23 18:13:01 +00:00
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
sk_sp<SkShader> fShader;
|
2015-10-23 18:13:01 +00:00
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
const BleedTest fBT;
|
2013-07-25 21:34:00 +00:00
|
|
|
|
|
|
|
typedef GM INHERITED;
|
|
|
|
};
|
|
|
|
|
2015-11-02 20:33:21 +00:00
|
|
|
|
2015-07-14 17:54:12 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
|
2015-11-02 20:33:21 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseTextureBitmap_BleedTest); )
|
2015-07-14 17:54:12 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseImage_BleedTest); )
|
2015-10-23 18:13:01 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
|
2015-11-02 20:33:21 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseAlphaTextureBitmap_BleedTest); )
|
2015-10-23 18:13:01 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
|
2015-11-02 20:33:21 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
|
|
|
|
DEF_GM( return new BleedGM(kUseAlphaTextureBitmapShader_BleedTest); )
|
|
|
|
DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )
|