blob: 38a22e69f5ae87a263f31f362999dfcb42becf65 [file] [log] [blame]
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001/*
2 * Copyright 2011 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 "SkGpuDevice.h"
9
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000010#include "GrBitmapTextContext.h"
kkinnunenabcfab42015-02-22 22:53:44 -080011#include "GrContext.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000012#include "GrDistanceFieldTextContext.h"
kkinnunenabcfab42015-02-22 22:53:44 -080013#include "GrGpu.h"
14#include "GrGpuResourcePriv.h"
robertphillips98d709b2014-09-02 10:20:50 -070015#include "GrLayerHoister.h"
robertphillips274b4ba2014-09-04 07:24:18 -070016#include "GrRecordReplaceDraw.h"
egdanield58a0ba2014-06-11 10:30:05 -070017#include "GrStrokeInfo.h"
egdanielbbcb38d2014-06-19 10:19:29 -070018#include "GrTracing.h"
robertphillips30d78412014-11-24 09:49:17 -080019#include "SkCanvasPriv.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000020#include "SkDeviceImageFilterProxy.h"
21#include "SkDrawProcs.h"
kkinnunenabcfab42015-02-22 22:53:44 -080022#include "SkErrorInternals.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000023#include "SkGlyphCache.h"
kkinnunenabcfab42015-02-22 22:53:44 -080024#include "SkGrTexturePixelRef.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000025#include "SkImageFilter.h"
robertphillips82365912014-11-12 09:32:34 -080026#include "SkLayerInfo.h"
commit-bot@chromium.org82139702014-03-10 22:53:20 +000027#include "SkMaskFilter.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000028#include "SkPathEffect.h"
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +000029#include "SkPicture.h"
robertphillipsdb539902014-07-01 08:47:04 -070030#include "SkPictureData.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000031#include "SkRRect.h"
kkinnunenabcfab42015-02-22 22:53:44 -080032#include "SkRecord.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000033#include "SkStroke.h"
reed@google.com76f10a32014-02-05 15:32:21 +000034#include "SkSurface.h"
kkinnunenabcfab42015-02-22 22:53:44 -080035#include "SkSurface_Gpu.h"
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +000036#include "SkTLazy.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000037#include "SkUtils.h"
commit-bot@chromium.org559a8832014-05-30 10:08:22 +000038#include "SkVertState.h"
robertphillips320c9232014-07-29 06:07:19 -070039#include "SkXfermode.h"
kkinnunenabcfab42015-02-22 22:53:44 -080040#include "effects/GrBicubicEffect.h"
41#include "effects/GrDashingEffect.h"
42#include "effects/GrSimpleTextureEffect.h"
43#include "effects/GrTextureDomain.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000044
reedf037e0b2014-10-30 11:34:15 -070045#if SK_SUPPORT_GPU
46
senorblanco55b6d8b2014-07-30 11:26:46 -070047enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 };
48
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000049#if 0
50 extern bool (*gShouldDrawProc)();
joshualitt5531d512014-12-17 15:50:11 -080051 #define CHECK_SHOULD_DRAW(draw) \
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000052 do { \
53 if (gShouldDrawProc && !gShouldDrawProc()) return; \
joshualitt5531d512014-12-17 15:50:11 -080054 this->prepareDraw(draw); \
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000055 } while (0)
56#else
joshualitt5531d512014-12-17 15:50:11 -080057 #define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw)
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000058#endif
59
60// This constant represents the screen alignment criterion in texels for
61// requiring texture domain clamping to prevent color bleeding when drawing
62// a sub region of a larger source image.
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000063#define COLOR_BLEED_TOLERANCE 0.001f
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000064
65#define DO_DEFERRED_CLEAR() \
66 do { \
bsalomonafe30052015-01-16 07:32:33 -080067 if (fNeedClear) { \
68 this->clearAll(); \
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000069 } \
70 } while (false) \
71
72///////////////////////////////////////////////////////////////////////////////
73
74#define CHECK_FOR_ANNOTATION(paint) \
75 do { if (paint.getAnnotation()) { return; } } while (0)
76
77///////////////////////////////////////////////////////////////////////////////
78
bsalomonbcf0a522014-10-08 08:40:09 -070079// Helper for turning a bitmap into a texture. If the bitmap is GrTexture backed this
80// just accesses the backing GrTexture. Otherwise, it creates a cached texture
81// representation and releases it in the destructor.
82class AutoBitmapTexture : public SkNoncopyable {
Brian Salomon9323b8b2014-10-07 15:07:38 -040083public:
bsalomonbcf0a522014-10-08 08:40:09 -070084 AutoBitmapTexture() {}
robertphillipsdbe60742014-09-30 06:54:17 -070085
bsalomonbcf0a522014-10-08 08:40:09 -070086 AutoBitmapTexture(GrContext* context,
87 const SkBitmap& bitmap,
88 const GrTextureParams* params,
89 GrTexture** texture) {
Brian Salomon9323b8b2014-10-07 15:07:38 -040090 SkASSERT(texture);
bsalomonbcf0a522014-10-08 08:40:09 -070091 *texture = this->set(context, bitmap, params);
Brian Salomon9323b8b2014-10-07 15:07:38 -040092 }
93
bsalomonbcf0a522014-10-08 08:40:09 -070094 GrTexture* set(GrContext* context,
Brian Salomon9323b8b2014-10-07 15:07:38 -040095 const SkBitmap& bitmap,
96 const GrTextureParams* params) {
bsalomonbcf0a522014-10-08 08:40:09 -070097 // Either get the texture directly from the bitmap, or else use the cache and
98 // remember to unref it.
99 if (GrTexture* bmpTexture = bitmap.getTexture()) {
100 fTexture.reset(NULL);
101 return bmpTexture;
102 } else {
103 fTexture.reset(GrRefCachedBitmapTexture(context, bitmap, params));
104 return fTexture.get();
Brian Salomon9323b8b2014-10-07 15:07:38 -0400105 }
Brian Salomon9323b8b2014-10-07 15:07:38 -0400106 }
107
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000108private:
bsalomonbcf0a522014-10-08 08:40:09 -0700109 SkAutoTUnref<GrTexture> fTexture;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000110};
111
112///////////////////////////////////////////////////////////////////////////////
113
114struct GrSkDrawProcs : public SkDrawProcs {
115public:
116 GrContext* fContext;
117 GrTextContext* fTextContext;
118 GrFontScaler* fFontScaler; // cached in the skia glyphcache
119};
120
121///////////////////////////////////////////////////////////////////////////////
122
bsalomonafe30052015-01-16 07:32:33 -0800123SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, const SkSurfaceProps* props, unsigned flags) {
124 if (!rt || rt->wasDestroyed()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000125 return NULL;
126 }
rmistry82973db2015-04-01 15:53:13 -0700127 return SkNEW_ARGS(SkGpuDevice, (rt, props, flags));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000128}
129
bsalomonafe30052015-01-16 07:32:33 -0800130static SkDeviceProperties surfaceprops_to_deviceprops(const SkSurfaceProps* props) {
131 if (props) {
132 return SkDeviceProperties(props->pixelGeometry());
133 } else {
134 return SkDeviceProperties(SkDeviceProperties::kLegacyLCD_InitType);
135 }
reedb2db8982014-11-13 12:41:02 -0800136}
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000137
bsalomonafe30052015-01-16 07:32:33 -0800138static SkSurfaceProps copy_or_default_props(const SkSurfaceProps* props) {
139 if (props) {
140 return SkSurfaceProps(*props);
141 } else {
142 return SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
143 }
144}
145
rmistry82973db2015-04-01 15:53:13 -0700146SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, const SkSurfaceProps* props, unsigned flags)
reedb2db8982014-11-13 12:41:02 -0800147 : INHERITED(surfaceprops_to_deviceprops(props))
bsalomonafe30052015-01-16 07:32:33 -0800148 , fSurfaceProps(copy_or_default_props(props))
reedb2db8982014-11-13 12:41:02 -0800149{
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000150 fDrawProcs = NULL;
151
bsalomonafe30052015-01-16 07:32:33 -0800152 fContext = SkRef(rt->getContext());
153 fNeedClear = flags & kNeedClear_Flag;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000154
bsalomonafe30052015-01-16 07:32:33 -0800155 fRenderTarget = SkRef(rt);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000156
rmistry82973db2015-04-01 15:53:13 -0700157 SkImageInfo info = rt->surfacePriv().info();
bsalomonafe30052015-01-16 07:32:33 -0800158 SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, rt));
bsalomonafbf2d62014-09-30 12:18:44 -0700159 fLegacyBitmap.setInfo(info);
reed89443ab2014-06-27 11:34:19 -0700160 fLegacyBitmap.setPixelRef(pr)->unref();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700161
bsalomonafe30052015-01-16 07:32:33 -0800162 bool useDFT = fSurfaceProps.isUseDistanceFieldFonts();
joshualitt6e8cd962015-03-20 10:30:14 -0700163 fTextContext = fContext->createTextContext(fRenderTarget, this, this->getLeakyProperties(),
164 useDFT);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000165}
166
kkinnunenabcfab42015-02-22 22:53:44 -0800167GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::Budgeted budgeted,
168 const SkImageInfo& origInfo, int sampleCount) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000169 if (kUnknown_SkColorType == origInfo.colorType() ||
170 origInfo.width() < 0 || origInfo.height() < 0) {
171 return NULL;
172 }
173
bsalomonafe30052015-01-16 07:32:33 -0800174 if (!context) {
175 return NULL;
176 }
177
reede5ea5002014-09-03 11:54:58 -0700178 SkColorType ct = origInfo.colorType();
179 SkAlphaType at = origInfo.alphaType();
reede5ea5002014-09-03 11:54:58 -0700180 if (kRGB_565_SkColorType == ct) {
181 at = kOpaque_SkAlphaType; // force this setting
bsalomonafe30052015-01-16 07:32:33 -0800182 } else if (ct != kBGRA_8888_SkColorType && ct != kRGBA_8888_SkColorType) {
183 // Fall back from whatever ct was to default of kRGBA or kBGRA which is aliased as kN32
reede5ea5002014-09-03 11:54:58 -0700184 ct = kN32_SkColorType;
bsalomonafe30052015-01-16 07:32:33 -0800185 }
186 if (kOpaque_SkAlphaType != at) {
187 at = kPremul_SkAlphaType; // force this setting
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000188 }
reede5ea5002014-09-03 11:54:58 -0700189 const SkImageInfo info = SkImageInfo::Make(origInfo.width(), origInfo.height(), ct, at);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000190
bsalomonf2703d82014-10-28 14:33:06 -0700191 GrSurfaceDesc desc;
192 desc.fFlags = kRenderTarget_GrSurfaceFlag;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000193 desc.fWidth = info.width();
194 desc.fHeight = info.height();
commit-bot@chromium.org3adcc342014-04-23 19:18:09 +0000195 desc.fConfig = SkImageInfo2GrPixelConfig(info);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000196 desc.fSampleCnt = sampleCount;
kkinnunenabcfab42015-02-22 22:53:44 -0800197 GrTexture* texture = context->createTexture(desc, SkToBool(budgeted), NULL, 0);
198 if (NULL == texture) {
199 return NULL;
200 }
201 SkASSERT(NULL != texture->asRenderTarget());
202 return texture->asRenderTarget();
203}
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000204
kkinnunenabcfab42015-02-22 22:53:44 -0800205SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgeted,
206 const SkImageInfo& info, int sampleCount,
207 const SkSurfaceProps* props, unsigned flags) {
208
209 SkAutoTUnref<GrRenderTarget> rt(CreateRenderTarget(context, budgeted, info, sampleCount));
210 if (NULL == rt) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000211 return NULL;
212 }
skia.committer@gmail.com969588f2014-02-16 03:01:56 +0000213
rmistry82973db2015-04-01 15:53:13 -0700214 return SkNEW_ARGS(SkGpuDevice, (rt, props, flags));
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000215}
216
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000217SkGpuDevice::~SkGpuDevice() {
218 if (fDrawProcs) {
219 delete fDrawProcs;
220 }
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000221
jvanverth8c27a182014-10-14 08:45:50 -0700222 delete fTextContext;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000223
bsalomon32d0b3b2014-08-29 07:50:23 -0700224 fRenderTarget->unref();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000225 fContext->unref();
226}
227
228///////////////////////////////////////////////////////////////////////////////
229
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000230bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
231 int x, int y) {
232 DO_DEFERRED_CLEAR();
233
234 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
commit-bot@chromium.org3adcc342014-04-23 19:18:09 +0000235 GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000236 if (kUnknown_GrPixelConfig == config) {
237 return false;
238 }
239
240 uint32_t flags = 0;
241 if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
242 flags = GrContext::kUnpremul_PixelOpsFlag;
243 }
244 return fContext->readRenderTargetPixels(fRenderTarget, x, y, dstInfo.width(), dstInfo.height(),
245 config, dstPixels, dstRowBytes, flags);
246}
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000247
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000248bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
249 int x, int y) {
250 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
commit-bot@chromium.org3adcc342014-04-23 19:18:09 +0000251 GrPixelConfig config = SkImageInfo2GrPixelConfig(info);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000252 if (kUnknown_GrPixelConfig == config) {
253 return false;
254 }
255 uint32_t flags = 0;
256 if (kUnpremul_SkAlphaType == info.alphaType()) {
257 flags = GrContext::kUnpremul_PixelOpsFlag;
258 }
259 fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags);
260
261 // need to bump our genID for compatibility with clients that "know" we have a bitmap
reed89443ab2014-06-27 11:34:19 -0700262 fLegacyBitmap.notifyPixelsChanged();
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000263
264 return true;
265}
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000266
senorblanco@chromium.orgb7b7eb32014-03-19 18:24:04 +0000267const SkBitmap& SkGpuDevice::onAccessBitmap() {
268 DO_DEFERRED_CLEAR();
reed89443ab2014-06-27 11:34:19 -0700269 return fLegacyBitmap;
senorblanco@chromium.orgb7b7eb32014-03-19 18:24:04 +0000270}
271
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000272void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
273 INHERITED::onAttachToCanvas(canvas);
274
275 // Canvas promises that this ptr is valid until onDetachFromCanvas is called
joshualitt44701df2015-02-23 14:44:57 -0800276 fClipStack.reset(SkRef(canvas->getClipStack()));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000277}
278
279void SkGpuDevice::onDetachFromCanvas() {
280 INHERITED::onDetachFromCanvas();
joshualitt570d2f82015-02-25 13:19:48 -0800281 fClip.reset();
joshualitt44701df2015-02-23 14:44:57 -0800282 fClipStack.reset(NULL);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000283}
284
285// call this every draw call, to ensure that the context reflects our state,
286// and not the state from some other canvas/device
joshualitt5531d512014-12-17 15:50:11 -0800287void SkGpuDevice::prepareDraw(const SkDraw& draw) {
joshualitt44701df2015-02-23 14:44:57 -0800288 SkASSERT(fClipStack.get());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000289
joshualitt44701df2015-02-23 14:44:57 -0800290 SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000291
joshualitt570d2f82015-02-25 13:19:48 -0800292 fClip.setClipStack(fClipStack, &this->getOrigin());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000293
294 DO_DEFERRED_CLEAR();
295}
296
297GrRenderTarget* SkGpuDevice::accessRenderTarget() {
298 DO_DEFERRED_CLEAR();
299 return fRenderTarget;
300}
301
reed8eddfb52014-12-04 07:50:14 -0800302void SkGpuDevice::clearAll() {
303 GrColor color = 0;
304 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::clearAll", fContext);
305 SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
306 fContext->clear(&rect, color, true, fRenderTarget);
bsalomonafe30052015-01-16 07:32:33 -0800307 fNeedClear = false;
reed8eddfb52014-12-04 07:50:14 -0800308}
309
kkinnunenabcfab42015-02-22 22:53:44 -0800310void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) {
311 // Caller must have accessed the render target, because it knows the rt must be replaced.
312 SkASSERT(!fNeedClear);
313
314 SkSurface::Budgeted budgeted =
315 fRenderTarget->resourcePriv().isBudgeted() ? SkSurface::kYes_Budgeted
316 : SkSurface::kNo_Budgeted;
317
318 SkAutoTUnref<GrRenderTarget> newRT(CreateRenderTarget(
319 fRenderTarget->getContext(), budgeted, this->imageInfo(), fRenderTarget->numSamples()));
320
321 if (NULL == newRT) {
322 return;
323 }
324
325 if (shouldRetainContent) {
326 if (fRenderTarget->wasDestroyed()) {
327 return;
328 }
329 this->context()->copySurface(newRT, fRenderTarget);
330 }
331
332 SkASSERT(fRenderTarget != newRT);
333
334 fRenderTarget->unref();
335 fRenderTarget = newRT.detach();
336
337 SkASSERT(fRenderTarget->surfacePriv().info() == fLegacyBitmap.info());
338 SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (fRenderTarget->surfacePriv().info(), fRenderTarget));
339 fLegacyBitmap.setPixelRef(pr)->unref();
340}
341
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000342///////////////////////////////////////////////////////////////////////////////
343
344SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
345SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
346SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
347SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
348SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
349 shader_type_mismatch);
350SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5,
351 shader_type_mismatch);
352SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch);
353SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch);
354
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000355///////////////////////////////////////////////////////////////////////////////
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000356
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000357void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
joshualitt5531d512014-12-17 15:50:11 -0800358 CHECK_SHOULD_DRAW(draw);
egdanield78a1682014-07-09 10:41:26 -0700359 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPaint", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000360
361 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -0800362 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000363
joshualitt570d2f82015-02-25 13:19:48 -0800364 fContext->drawPaint(fRenderTarget, fClip, grPaint, *draw.fMatrix);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000365}
366
367// must be in SkCanvas::PointMode order
368static const GrPrimitiveType gPointMode2PrimtiveType[] = {
369 kPoints_GrPrimitiveType,
370 kLines_GrPrimitiveType,
371 kLineStrip_GrPrimitiveType
372};
373
374void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
375 size_t count, const SkPoint pts[], const SkPaint& paint) {
376 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800377 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000378
379 SkScalar width = paint.getStrokeWidth();
380 if (width < 0) {
381 return;
382 }
383
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000384 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
egdaniele61c4112014-06-12 10:24:21 -0700385 GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style);
386 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -0800387 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
egdaniele61c4112014-06-12 10:24:21 -0700388 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700389 path.setIsVolatile(true);
egdaniele61c4112014-06-12 10:24:21 -0700390 path.moveTo(pts[0]);
391 path.lineTo(pts[1]);
joshualitt570d2f82015-02-25 13:19:48 -0800392 fContext->drawPath(fRenderTarget, fClip, grPaint, *draw.fMatrix, path, strokeInfo);
egdaniele61c4112014-06-12 10:24:21 -0700393 return;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000394 }
395
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000396 // we only handle hairlines and paints without path effects or mask filters,
397 // else we let the SkDraw call our drawPath()
398 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) {
399 draw.drawPoints(mode, count, pts, paint, true);
400 return;
401 }
402
403 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -0800404 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000405
joshualitt25d9c152015-02-18 12:29:52 -0800406 fContext->drawVertices(fRenderTarget,
joshualitt570d2f82015-02-25 13:19:48 -0800407 fClip,
joshualitt25d9c152015-02-18 12:29:52 -0800408 grPaint,
joshualitt5531d512014-12-17 15:50:11 -0800409 *draw.fMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000410 gPointMode2PrimtiveType[mode],
robertphillips@google.coma4662862013-11-21 14:24:16 +0000411 SkToS32(count),
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000412 (SkPoint*)pts,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000413 NULL,
414 NULL,
415 NULL,
416 0);
417}
418
419///////////////////////////////////////////////////////////////////////////////
420
421void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
422 const SkPaint& paint) {
egdanielbbcb38d2014-06-19 10:19:29 -0700423 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRect", fContext);
424
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000425 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800426 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000427
428 bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
429 SkScalar width = paint.getStrokeWidth();
430
431 /*
432 We have special code for hairline strokes, miter-strokes, bevel-stroke
433 and fills. Anything else we just call our path code.
434 */
435 bool usePath = doStroke && width > 0 &&
436 (paint.getStrokeJoin() == SkPaint::kRound_Join ||
437 (paint.getStrokeJoin() == SkPaint::kBevel_Join && rect.isEmpty()));
438 // another two reasons we might need to call drawPath...
egdanield58a0ba2014-06-11 10:30:05 -0700439
440 if (paint.getMaskFilter()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000441 usePath = true;
442 }
egdanield58a0ba2014-06-11 10:30:05 -0700443
joshualitt5531d512014-12-17 15:50:11 -0800444 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000445#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
446 if (doStroke) {
447#endif
448 usePath = true;
449#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
450 } else {
joshualitt5531d512014-12-17 15:50:11 -0800451 usePath = !draw.fMatrix->preservesRightAngles();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000452 }
453#endif
454 }
455 // until we can both stroke and fill rectangles
456 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
457 usePath = true;
458 }
459
egdanield58a0ba2014-06-11 10:30:05 -0700460 GrStrokeInfo strokeInfo(paint);
461
462 const SkPathEffect* pe = paint.getPathEffect();
bsalomon49f085d2014-09-05 13:34:00 -0700463 if (!usePath && pe && !strokeInfo.isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700464 usePath = true;
465 }
466
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000467 if (usePath) {
468 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700469 path.setIsVolatile(true);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000470 path.addRect(rect);
471 this->drawPath(draw, path, paint, NULL, true);
472 return;
473 }
474
475 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -0800476 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
Mike Klein744fb732014-06-23 15:13:26 -0400477
joshualitt570d2f82015-02-25 13:19:48 -0800478 fContext->drawRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, rect, &strokeInfo);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000479}
480
481///////////////////////////////////////////////////////////////////////////////
482
483void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
joshualitt5531d512014-12-17 15:50:11 -0800484 const SkPaint& paint) {
egdanield78a1682014-07-09 10:41:26 -0700485 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRRect", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000486 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800487 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000488
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000489 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -0800490 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
Mike Klein744fb732014-06-23 15:13:26 -0400491
egdanield58a0ba2014-06-11 10:30:05 -0700492 GrStrokeInfo strokeInfo(paint);
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000493 if (paint.getMaskFilter()) {
494 // try to hit the fast path for drawing filtered round rects
495
496 SkRRect devRRect;
joshualitt5531d512014-12-17 15:50:11 -0800497 if (rect.transform(*draw.fMatrix, &devRRect)) {
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000498 if (devRRect.allCornersCircular()) {
499 SkRect maskRect;
500 if (paint.getMaskFilter()->canFilterMaskGPU(devRRect.rect(),
joshualitt5531d512014-12-17 15:50:11 -0800501 draw.fClip->getBounds(),
502 *draw.fMatrix,
503 &maskRect)) {
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000504 SkIRect finalIRect;
505 maskRect.roundOut(&finalIRect);
506 if (draw.fClip->quickReject(finalIRect)) {
507 // clipped out
508 return;
509 }
joshualitt25d9c152015-02-18 12:29:52 -0800510 if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext,
511 fRenderTarget,
512 &grPaint,
joshualitt570d2f82015-02-25 13:19:48 -0800513 fClip,
joshualitt5531d512014-12-17 15:50:11 -0800514 *draw.fMatrix,
egdanield58a0ba2014-06-11 10:30:05 -0700515 strokeInfo.getStrokeRec(),
516 devRRect)) {
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000517 return;
518 }
519 }
520
521 }
522 }
523
524 }
525
egdanield58a0ba2014-06-11 10:30:05 -0700526 bool usePath = false;
527
528 if (paint.getMaskFilter()) {
529 usePath = true;
530 } else {
531 const SkPathEffect* pe = paint.getPathEffect();
bsalomon49f085d2014-09-05 13:34:00 -0700532 if (pe && !strokeInfo.isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700533 usePath = true;
534 }
535 }
536
537
538 if (usePath) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000539 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700540 path.setIsVolatile(true);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000541 path.addRRect(rect);
542 this->drawPath(draw, path, paint, NULL, true);
543 return;
544 }
Mike Klein744fb732014-06-23 15:13:26 -0400545
joshualitt570d2f82015-02-25 13:19:48 -0800546 fContext->drawRRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, rect, strokeInfo);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000547}
548
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000549void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
joshualitt5531d512014-12-17 15:50:11 -0800550 const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000551 SkStrokeRec stroke(paint);
552 if (stroke.isFillStyle()) {
553
554 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800555 CHECK_SHOULD_DRAW(draw);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000556
557 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -0800558 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000559
560 if (NULL == paint.getMaskFilter() && NULL == paint.getPathEffect()) {
joshualitt570d2f82015-02-25 13:19:48 -0800561 fContext->drawDRRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, outer, inner);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000562 return;
563 }
564 }
565
566 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700567 path.setIsVolatile(true);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000568 path.addRRect(outer);
569 path.addRRect(inner);
570 path.setFillType(SkPath::kEvenOdd_FillType);
571
572 this->drawPath(draw, path, paint, NULL, true);
573}
574
575
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000576/////////////////////////////////////////////////////////////////////////////
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000577
578void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval,
579 const SkPaint& paint) {
egdanield78a1682014-07-09 10:41:26 -0700580 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawOval", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000581 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800582 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000583
egdanield58a0ba2014-06-11 10:30:05 -0700584 GrStrokeInfo strokeInfo(paint);
585
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000586 bool usePath = false;
587 // some basic reasons we might need to call drawPath...
egdanield58a0ba2014-06-11 10:30:05 -0700588 if (paint.getMaskFilter()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000589 usePath = true;
egdanield58a0ba2014-06-11 10:30:05 -0700590 } else {
591 const SkPathEffect* pe = paint.getPathEffect();
bsalomon49f085d2014-09-05 13:34:00 -0700592 if (pe && !strokeInfo.isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700593 usePath = true;
594 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000595 }
596
597 if (usePath) {
598 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700599 path.setIsVolatile(true);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000600 path.addOval(oval);
601 this->drawPath(draw, path, paint, NULL, true);
602 return;
603 }
604
605 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -0800606 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000607
joshualitt570d2f82015-02-25 13:19:48 -0800608 fContext->drawOval(fRenderTarget, fClip, grPaint, *draw.fMatrix, oval, strokeInfo);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000609}
610
611#include "SkMaskFilter.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000612
613///////////////////////////////////////////////////////////////////////////////
614
615// helpers for applying mask filters
616namespace {
617
618// Draw a mask using the supplied paint. Since the coverage/geometry
619// is already burnt into the mask this boils down to a rect draw.
620// Return true if the mask was successfully drawn.
joshualitt25d9c152015-02-18 12:29:52 -0800621bool draw_mask(GrContext* context,
622 GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800623 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800624 const SkMatrix& viewMatrix,
625 const SkRect& maskRect,
626 GrPaint* grp,
627 GrTexture* mask) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000628 SkMatrix matrix;
629 matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
630 matrix.postIDiv(mask->width(), mask->height());
631
joshualitt16b27892014-12-18 07:47:16 -0800632 grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix,
633 kDevice_GrCoordSet))->unref();
634
635 SkMatrix inverse;
636 if (!viewMatrix.invert(&inverse)) {
637 return false;
638 }
joshualitt570d2f82015-02-25 13:19:48 -0800639 context->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), maskRect, inverse);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000640 return true;
641}
642
joshualitt5efb8b82015-03-18 11:49:12 -0700643static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) {
644 return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect);
645}
646
joshualitt25d9c152015-02-18 12:29:52 -0800647bool draw_with_mask_filter(GrContext* context,
648 GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800649 const GrClip& clipData,
joshualitt25d9c152015-02-18 12:29:52 -0800650 const SkMatrix& viewMatrix,
651 const SkPath& devPath,
652 SkMaskFilter* filter,
joshualitt5efb8b82015-03-18 11:49:12 -0700653 const SkIRect& clipBounds,
joshualitt25d9c152015-02-18 12:29:52 -0800654 GrPaint* grp,
655 SkPaint::Style style) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000656 SkMask srcM, dstM;
657
joshualitt5efb8b82015-03-18 11:49:12 -0700658 if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000659 SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
660 return false;
661 }
662 SkAutoMaskFreeImage autoSrc(srcM.fImage);
663
joshualitt5531d512014-12-17 15:50:11 -0800664 if (!filter->filterMask(&dstM, srcM, viewMatrix, NULL)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000665 return false;
666 }
667 // this will free-up dstM when we're done (allocated in filterMask())
668 SkAutoMaskFreeImage autoDst(dstM.fImage);
669
joshualitt5efb8b82015-03-18 11:49:12 -0700670 if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000671 return false;
672 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000673
674 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
675 // the current clip (and identity matrix) and GrPaint settings
bsalomonf2703d82014-10-28 14:33:06 -0700676 GrSurfaceDesc desc;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000677 desc.fWidth = dstM.fBounds.width();
678 desc.fHeight = dstM.fBounds.height();
679 desc.fConfig = kAlpha_8_GrPixelConfig;
680
bsalomone3059732014-10-14 11:47:22 -0700681 SkAutoTUnref<GrTexture> texture(
682 context->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
683 if (!texture) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000684 return false;
685 }
686 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
687 dstM.fImage, dstM.fRowBytes);
688
689 SkRect maskRect = SkRect::Make(dstM.fBounds);
690
joshualitt570d2f82015-02-25 13:19:48 -0800691 return draw_mask(context, rt, clipData, viewMatrix, maskRect, grp, texture);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000692}
693
bsalomone3059732014-10-14 11:47:22 -0700694// Create a mask of 'devPath' and place the result in 'mask'.
695GrTexture* create_mask_GPU(GrContext* context,
joshualitt25d9c152015-02-18 12:29:52 -0800696 GrRenderTarget* rt,
bsalomone3059732014-10-14 11:47:22 -0700697 const SkRect& maskRect,
698 const SkPath& devPath,
699 const GrStrokeInfo& strokeInfo,
700 bool doAA,
701 int sampleCnt) {
bsalomonf2703d82014-10-28 14:33:06 -0700702 GrSurfaceDesc desc;
703 desc.fFlags = kRenderTarget_GrSurfaceFlag;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000704 desc.fWidth = SkScalarCeilToInt(maskRect.width());
705 desc.fHeight = SkScalarCeilToInt(maskRect.height());
bsalomone3059732014-10-14 11:47:22 -0700706 desc.fSampleCnt = doAA ? sampleCnt : 0;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000707 // We actually only need A8, but it often isn't supported as a
708 // render target so default to RGBA_8888
709 desc.fConfig = kRGBA_8888_GrPixelConfig;
derekff4555aa2014-10-06 12:19:12 -0700710
711 if (context->isConfigRenderable(kAlpha_8_GrPixelConfig,
712 desc.fSampleCnt > 0)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000713 desc.fConfig = kAlpha_8_GrPixelConfig;
714 }
715
bsalomone3059732014-10-14 11:47:22 -0700716 GrTexture* mask = context->refScratchTexture(desc,GrContext::kApprox_ScratchTexMatch);
717 if (NULL == mask) {
718 return NULL;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000719 }
720
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000721 SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
722
bsalomon89c62982014-11-03 12:08:42 -0800723 context->clear(NULL, 0x0, true, mask->asRenderTarget());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000724
725 GrPaint tempPaint;
egdanielb197b8f2015-02-17 07:34:43 -0800726 tempPaint.setAntiAlias(doAA);
727 tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000728
joshualitt570d2f82015-02-25 13:19:48 -0800729 // setup new clip
730 GrClip clip(clipRect);
731
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000732 // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
733 SkMatrix translate;
734 translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
joshualitt570d2f82015-02-25 13:19:48 -0800735 context->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo);
bsalomone3059732014-10-14 11:47:22 -0700736 return mask;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000737}
738
rmistry82973db2015-04-01 15:53:13 -0700739SkBitmap wrap_texture(GrTexture* texture) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000740 SkBitmap result;
rmistry82973db2015-04-01 15:53:13 -0700741 result.setInfo(texture->surfacePriv().info());
reed6c225732014-06-09 19:52:07 -0700742 result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unref();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000743 return result;
744}
745
746};
747
748void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
749 const SkPaint& paint, const SkMatrix* prePathMatrix,
750 bool pathIsMutable) {
751 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800752 CHECK_SHOULD_DRAW(draw);
egdanield78a1682014-07-09 10:41:26 -0700753 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPath", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000754
joshualitt5efb8b82015-03-18 11:49:12 -0700755 return this->internalDrawPath(origSrcPath, paint, *draw.fMatrix, prePathMatrix,
756 draw.fClip->getBounds(), pathIsMutable);
757}
758
759void SkGpuDevice::internalDrawPath(const SkPath& origSrcPath, const SkPaint& paint,
760 const SkMatrix& origViewMatrix, const SkMatrix* prePathMatrix,
761 const SkIRect& clipBounds, bool pathIsMutable) {
jvanverthb3eb6872014-10-24 07:12:51 -0700762 SkASSERT(!pathIsMutable || origSrcPath.isVolatile());
joshualitt5531d512014-12-17 15:50:11 -0800763
bsalomon54443932015-01-29 09:34:18 -0800764 GrStrokeInfo strokeInfo(paint);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000765
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000766 // If we have a prematrix, apply it to the path, optimizing for the case
767 // where the original path can in fact be modified in place (even though
768 // its parameter type is const).
769 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +0000770 SkTLazy<SkPath> tmpPath;
771 SkTLazy<SkPath> effectPath;
bsalomon54443932015-01-29 09:34:18 -0800772 SkPathEffect* pathEffect = paint.getPathEffect();
773
joshualitt5efb8b82015-03-18 11:49:12 -0700774 SkMatrix viewMatrix = origViewMatrix;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000775
776 if (prePathMatrix) {
bsalomon54443932015-01-29 09:34:18 -0800777 // stroking and path effects are supposed to be applied *after* the prePathMatrix.
778 // The pre-path-matrix also should not affect shadeing.
779 if (NULL == pathEffect && NULL == paint.getShader() &&
780 (strokeInfo.getStrokeRec().isFillStyle() ||
781 strokeInfo.getStrokeRec().isHairlineStyle())) {
782 viewMatrix.preConcat(*prePathMatrix);
783 } else {
784 SkPath* result = pathPtr;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000785
bsalomon54443932015-01-29 09:34:18 -0800786 if (!pathIsMutable) {
787 result = tmpPath.init();
788 result->setIsVolatile(true);
789 pathIsMutable = true;
790 }
791 // should I push prePathMatrix on our MV stack temporarily, instead
792 // of applying it here? See SkDraw.cpp
793 pathPtr->transform(*prePathMatrix, result);
794 pathPtr = result;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000795 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000796 }
797 // at this point we're done with prePathMatrix
798 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
799
bsalomon54443932015-01-29 09:34:18 -0800800 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -0800801 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, viewMatrix, true, &grPaint);
bsalomon54443932015-01-29 09:34:18 -0800802
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000803 const SkRect* cullRect = NULL; // TODO: what is our bounds?
egdanield58a0ba2014-06-11 10:30:05 -0700804 SkStrokeRec* strokePtr = strokeInfo.getStrokeRecPtr();
805 if (pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr, strokePtr,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000806 cullRect)) {
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +0000807 pathPtr = effectPath.get();
808 pathIsMutable = true;
egdanield58a0ba2014-06-11 10:30:05 -0700809 strokeInfo.removeDash();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000810 }
811
egdanield58a0ba2014-06-11 10:30:05 -0700812 const SkStrokeRec& stroke = strokeInfo.getStrokeRec();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000813 if (paint.getMaskFilter()) {
814 if (!stroke.isHairlineStyle()) {
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +0000815 SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
816 if (stroke.applyToPath(strokedPath, *pathPtr)) {
817 pathPtr = strokedPath;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000818 pathIsMutable = true;
egdanield58a0ba2014-06-11 10:30:05 -0700819 strokeInfo.setFillStyle();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000820 }
821 }
822
823 // avoid possibly allocating a new path in transform if we can
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +0000824 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init();
jvanverthb3eb6872014-10-24 07:12:51 -0700825 if (!pathIsMutable) {
826 devPathPtr->setIsVolatile(true);
827 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000828
829 // transform the path into device space
bsalomon54443932015-01-29 09:34:18 -0800830 pathPtr->transform(viewMatrix, devPathPtr);
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000831
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000832 SkRect maskRect;
833 if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(),
joshualitt5efb8b82015-03-18 11:49:12 -0700834 clipBounds,
bsalomon54443932015-01-29 09:34:18 -0800835 viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000836 &maskRect)) {
837 SkIRect finalIRect;
838 maskRect.roundOut(&finalIRect);
joshualitt5efb8b82015-03-18 11:49:12 -0700839 if (clip_bounds_quick_reject(clipBounds, finalIRect)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000840 // clipped out
841 return;
842 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000843
joshualitt25d9c152015-02-18 12:29:52 -0800844 if (paint.getMaskFilter()->directFilterMaskGPU(fContext,
845 fRenderTarget,
846 &grPaint,
joshualitt570d2f82015-02-25 13:19:48 -0800847 fClip,
joshualitt25d9c152015-02-18 12:29:52 -0800848 viewMatrix,
849 stroke,
850 *devPathPtr)) {
commit-bot@chromium.orgcf34bc02014-01-30 15:34:43 +0000851 // the mask filter was able to draw itself directly, so there's nothing
852 // left to do.
853 return;
854 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000855
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000856
joshualitt25d9c152015-02-18 12:29:52 -0800857 SkAutoTUnref<GrTexture> mask(create_mask_GPU(fContext,
858 fRenderTarget,
859 maskRect,
860 *devPathPtr,
861 strokeInfo,
862 grPaint.isAntiAlias(),
bsalomone3059732014-10-14 11:47:22 -0700863 fRenderTarget->numSamples()));
864 if (mask) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000865 GrTexture* filtered;
866
bsalomon54443932015-01-29 09:34:18 -0800867 if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskRect, &filtered, true)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000868 // filterMaskGPU gives us ownership of a ref to the result
869 SkAutoTUnref<GrTexture> atu(filtered);
joshualitt570d2f82015-02-25 13:19:48 -0800870 if (draw_mask(fContext,
871 fRenderTarget,
872 fClip,
873 viewMatrix,
874 maskRect,
875 &grPaint,
joshualitt25d9c152015-02-18 12:29:52 -0800876 filtered)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000877 // This path is completely drawn
878 return;
879 }
880 }
881 }
882 }
883
884 // draw the mask on the CPU - this is a fallthrough path in case the
885 // GPU path fails
886 SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style :
887 SkPaint::kFill_Style;
joshualitt570d2f82015-02-25 13:19:48 -0800888 draw_with_mask_filter(fContext, fRenderTarget, fClip, viewMatrix, *devPathPtr,
joshualitt5efb8b82015-03-18 11:49:12 -0700889 paint.getMaskFilter(), clipBounds, &grPaint, style);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000890 return;
891 }
892
joshualitt570d2f82015-02-25 13:19:48 -0800893 fContext->drawPath(fRenderTarget, fClip, grPaint, viewMatrix, *pathPtr, strokeInfo);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000894}
895
896static const int kBmpSmallTileSize = 1 << 10;
897
898static inline int get_tile_count(const SkIRect& srcRect, int tileSize) {
899 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
900 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
901 return tilesX * tilesY;
902}
903
904static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int maxTileSize) {
905 if (maxTileSize <= kBmpSmallTileSize) {
906 return maxTileSize;
907 }
908
909 size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
910 size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
911
912 maxTileTotalTileSize *= maxTileSize * maxTileSize;
913 smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
914
915 if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
916 return kBmpSmallTileSize;
917 } else {
918 return maxTileSize;
919 }
920}
921
922// Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
923// pixels from the bitmap are necessary.
924static void determine_clipped_src_rect(const GrContext* context,
joshualitt25d9c152015-02-18 12:29:52 -0800925 const GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800926 const GrClip& clip,
joshualitt5531d512014-12-17 15:50:11 -0800927 const SkMatrix& viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000928 const SkBitmap& bitmap,
929 const SkRect* srcRectPtr,
930 SkIRect* clippedSrcIRect) {
joshualitt570d2f82015-02-25 13:19:48 -0800931 clip.getConservativeBounds(rt, clippedSrcIRect, NULL);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000932 SkMatrix inv;
joshualitt5531d512014-12-17 15:50:11 -0800933 if (!viewMatrix.invert(&inv)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000934 clippedSrcIRect->setEmpty();
935 return;
936 }
937 SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
938 inv.mapRect(&clippedSrcRect);
bsalomon49f085d2014-09-05 13:34:00 -0700939 if (srcRectPtr) {
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +0000940 // we've setup src space 0,0 to map to the top left of the src rect.
941 clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000942 if (!clippedSrcRect.intersect(*srcRectPtr)) {
943 clippedSrcIRect->setEmpty();
944 return;
945 }
946 }
947 clippedSrcRect.roundOut(clippedSrcIRect);
948 SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
949 if (!clippedSrcIRect->intersect(bmpBounds)) {
950 clippedSrcIRect->setEmpty();
951 }
952}
953
954bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
joshualitt5531d512014-12-17 15:50:11 -0800955 const SkMatrix& viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000956 const GrTextureParams& params,
957 const SkRect* srcRectPtr,
958 int maxTileSize,
959 int* tileSize,
960 SkIRect* clippedSrcRect) const {
961 // if bitmap is explictly texture backed then just use the texture
bsalomon49f085d2014-09-05 13:34:00 -0700962 if (bitmap.getTexture()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000963 return false;
964 }
965
966 // if it's larger than the max tile size, then we have no choice but tiling.
967 if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) {
joshualitt570d2f82015-02-25 13:19:48 -0800968 determine_clipped_src_rect(fContext, fRenderTarget, fClip, viewMatrix, bitmap,
969 srcRectPtr, clippedSrcRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000970 *tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize);
971 return true;
972 }
973
974 if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
975 return false;
976 }
977
978 // if the entire texture is already in our cache then no reason to tile it
979 if (GrIsBitmapInCache(fContext, bitmap, &params)) {
980 return false;
981 }
982
983 // At this point we know we could do the draw by uploading the entire bitmap
984 // as a texture. However, if the texture would be large compared to the
985 // cache size and we don't require most of it for this draw then tile to
986 // reduce the amount of upload and cache spill.
987
988 // assumption here is that sw bitmap size is a good proxy for its size as
989 // a texture
990 size_t bmpSize = bitmap.getSize();
991 size_t cacheSize;
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000992 fContext->getResourceCacheLimits(NULL, &cacheSize);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000993 if (bmpSize < cacheSize / 2) {
994 return false;
995 }
996
997 // Figure out how much of the src we will need based on the src rect and clipping.
joshualitt570d2f82015-02-25 13:19:48 -0800998 determine_clipped_src_rect(fContext, fRenderTarget, fClip, viewMatrix, bitmap, srcRectPtr,
joshualitt25d9c152015-02-18 12:29:52 -0800999 clippedSrcRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001000 *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
1001 size_t usedTileBytes = get_tile_count(*clippedSrcRect, kBmpSmallTileSize) *
1002 kBmpSmallTileSize * kBmpSmallTileSize;
1003
1004 return usedTileBytes < 2 * bmpSize;
1005}
1006
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001007void SkGpuDevice::drawBitmap(const SkDraw& origDraw,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001008 const SkBitmap& bitmap,
1009 const SkMatrix& m,
1010 const SkPaint& paint) {
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001011 SkMatrix concat;
1012 SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
1013 if (!m.isIdentity()) {
1014 concat.setConcat(*draw->fMatrix, m);
1015 draw.writable()->fMatrix = &concat;
1016 }
1017 this->drawBitmapCommon(*draw, bitmap, NULL, NULL, paint, SkCanvas::kNone_DrawBitmapRectFlag);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001018}
1019
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001020// This method outsets 'iRect' by 'outset' all around and then clamps its extents to
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001021// 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
1022// of 'iRect' for all possible outsets/clamps.
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001023static inline void clamped_outset_with_offset(SkIRect* iRect,
1024 int outset,
1025 SkPoint* offset,
1026 const SkIRect& clamp) {
1027 iRect->outset(outset, outset);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001028
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001029 int leftClampDelta = clamp.fLeft - iRect->fLeft;
1030 if (leftClampDelta > 0) {
1031 offset->fX -= outset - leftClampDelta;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001032 iRect->fLeft = clamp.fLeft;
1033 } else {
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001034 offset->fX -= outset;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001035 }
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001036
1037 int topClampDelta = clamp.fTop - iRect->fTop;
1038 if (topClampDelta > 0) {
1039 offset->fY -= outset - topClampDelta;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001040 iRect->fTop = clamp.fTop;
1041 } else {
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001042 offset->fY -= outset;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001043 }
1044
1045 if (iRect->fRight > clamp.fRight) {
1046 iRect->fRight = clamp.fRight;
1047 }
1048 if (iRect->fBottom > clamp.fBottom) {
1049 iRect->fBottom = clamp.fBottom;
1050 }
1051}
1052
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001053static bool has_aligned_samples(const SkRect& srcRect,
1054 const SkRect& transformedRect) {
1055 // detect pixel disalignment
1056 if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
1057 transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
1058 SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
1059 transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
1060 SkScalarAbs(transformedRect.width() - srcRect.width()) <
1061 COLOR_BLEED_TOLERANCE &&
1062 SkScalarAbs(transformedRect.height() - srcRect.height()) <
1063 COLOR_BLEED_TOLERANCE) {
1064 return true;
1065 }
1066 return false;
1067}
1068
1069static bool may_color_bleed(const SkRect& srcRect,
1070 const SkRect& transformedRect,
1071 const SkMatrix& m) {
1072 // Only gets called if has_aligned_samples returned false.
1073 // So we can assume that sampling is axis aligned but not texel aligned.
1074 SkASSERT(!has_aligned_samples(srcRect, transformedRect));
1075 SkRect innerSrcRect(srcRect), innerTransformedRect,
1076 outerTransformedRect(transformedRect);
1077 innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
1078 m.mapRect(&innerTransformedRect, innerSrcRect);
1079
1080 // The gap between outerTransformedRect and innerTransformedRect
1081 // represents the projection of the source border area, which is
1082 // problematic for color bleeding. We must check whether any
1083 // destination pixels sample the border area.
1084 outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
1085 innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
1086 SkIRect outer, inner;
1087 outerTransformedRect.round(&outer);
1088 innerTransformedRect.round(&inner);
1089 // If the inner and outer rects round to the same result, it means the
1090 // border does not overlap any pixel centers. Yay!
1091 return inner != outer;
1092}
1093
1094static bool needs_texture_domain(const SkBitmap& bitmap,
1095 const SkRect& srcRect,
1096 GrTextureParams &params,
1097 const SkMatrix& contextMatrix,
1098 bool bicubic) {
1099 bool needsTextureDomain = false;
1100
1101 if (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode) {
1102 // Need texture domain if drawing a sub rect
rmistry82973db2015-04-01 15:53:13 -07001103 needsTextureDomain = srcRect.width() < bitmap.width() ||
1104 srcRect.height() < bitmap.height();
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001105 if (!bicubic && needsTextureDomain && contextMatrix.rectStaysRect()) {
1106 // sampling is axis-aligned
1107 SkRect transformedRect;
1108 contextMatrix.mapRect(&transformedRect, srcRect);
1109
1110 if (has_aligned_samples(srcRect, transformedRect)) {
1111 params.setFilterMode(GrTextureParams::kNone_FilterMode);
1112 needsTextureDomain = false;
1113 } else {
1114 needsTextureDomain = may_color_bleed(srcRect, transformedRect, contextMatrix);
1115 }
1116 }
1117 }
1118 return needsTextureDomain;
1119}
1120
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001121void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
1122 const SkBitmap& bitmap,
1123 const SkRect* srcRectPtr,
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001124 const SkSize* dstSizePtr,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001125 const SkPaint& paint,
1126 SkCanvas::DrawBitmapRectFlags flags) {
joshualitt5531d512014-12-17 15:50:11 -08001127 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001128
1129 SkRect srcRect;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001130 SkSize dstSize;
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001131 // If there is no src rect, or the src rect contains the entire bitmap then we're effectively
1132 // in the (easier) bleed case, so update flags.
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001133 if (NULL == srcRectPtr) {
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001134 SkScalar w = SkIntToScalar(bitmap.width());
1135 SkScalar h = SkIntToScalar(bitmap.height());
1136 dstSize.fWidth = w;
1137 dstSize.fHeight = h;
1138 srcRect.set(0, 0, w, h);
rmistry82973db2015-04-01 15:53:13 -07001139 flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001140 } else {
bsalomon49f085d2014-09-05 13:34:00 -07001141 SkASSERT(dstSizePtr);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001142 srcRect = *srcRectPtr;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001143 dstSize = *dstSizePtr;
rmistry82973db2015-04-01 15:53:13 -07001144 if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 &&
1145 srcRect.fRight >= bitmap.width() && srcRect.fBottom >= bitmap.height()) {
1146 flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
1147 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001148 }
1149
derekf367e1862014-12-02 11:02:06 -08001150 // If the render target is not msaa and draw is antialiased, we call
1151 // drawRect instead of drawing on the render target directly.
1152 // FIXME: the tiled bitmap code path doesn't currently support
1153 // anti-aliased edges, we work around that for now by drawing directly
1154 // if the image size exceeds maximum texture size.
1155 int maxTextureSize = fContext->getMaxTextureSize();
1156 bool directDraw = fRenderTarget->isMultisampled() ||
1157 !paint.isAntiAlias() ||
1158 bitmap.width() > maxTextureSize ||
1159 bitmap.height() > maxTextureSize;
1160
1161 // we check whether dst rect are pixel aligned
1162 if (!directDraw) {
joshualitt5531d512014-12-17 15:50:11 -08001163 bool staysRect = draw.fMatrix->rectStaysRect();
derekf367e1862014-12-02 11:02:06 -08001164
1165 if (staysRect) {
1166 SkRect rect;
1167 SkRect dstRect = SkRect::MakeXYWH(0, 0, dstSize.fWidth, dstSize.fHeight);
joshualitt5531d512014-12-17 15:50:11 -08001168 draw.fMatrix->mapRect(&rect, dstRect);
derekf367e1862014-12-02 11:02:06 -08001169 const SkScalar *scalars = rect.asScalars();
1170 bool isDstPixelAligned = true;
1171 for (int i = 0; i < 4; i++) {
1172 if (!SkScalarIsInt(scalars[i])) {
1173 isDstPixelAligned = false;
1174 break;
1175 }
1176 }
1177
1178 if (isDstPixelAligned)
1179 directDraw = true;
1180 }
1181 }
1182
1183 if (paint.getMaskFilter() || !directDraw) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001184 // Convert the bitmap to a shader so that the rect can be drawn
1185 // through drawRect, which supports mask filters.
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001186 SkBitmap tmp; // subset of bitmap, if necessary
1187 const SkBitmap* bitmapPtr = &bitmap;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001188 SkMatrix localM;
bsalomon49f085d2014-09-05 13:34:00 -07001189 if (srcRectPtr) {
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001190 localM.setTranslate(-srcRectPtr->fLeft, -srcRectPtr->fTop);
1191 localM.postScale(dstSize.fWidth / srcRectPtr->width(),
1192 dstSize.fHeight / srcRectPtr->height());
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +00001193 // In bleed mode we position and trim the bitmap based on the src rect which is
1194 // already accounted for in 'm' and 'srcRect'. In clamp mode we need to chop out
1195 // the desired portion of the bitmap and then update 'm' and 'srcRect' to
1196 // compensate.
1197 if (!(SkCanvas::kBleed_DrawBitmapRectFlag & flags)) {
1198 SkIRect iSrc;
1199 srcRect.roundOut(&iSrc);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001200
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +00001201 SkPoint offset = SkPoint::Make(SkIntToScalar(iSrc.fLeft),
1202 SkIntToScalar(iSrc.fTop));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001203
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +00001204 if (!bitmap.extractSubset(&tmp, iSrc)) {
1205 return; // extraction failed
1206 }
1207 bitmapPtr = &tmp;
1208 srcRect.offset(-offset.fX, -offset.fY);
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001209
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +00001210 // The source rect has changed so update the matrix
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001211 localM.preTranslate(offset.fX, offset.fY);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001212 }
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001213 } else {
1214 localM.reset();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001215 }
1216
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001217 SkPaint paintWithShader(paint);
1218 paintWithShader.setShader(SkShader::CreateBitmapShader(*bitmapPtr,
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +00001219 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &localM))->unref();
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001220 SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight};
1221 this->drawRect(draw, dstRect, paintWithShader);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001222
1223 return;
1224 }
1225
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001226 // If there is no mask filter than it is OK to handle the src rect -> dst rect scaling using
1227 // the view matrix rather than a local matrix.
1228 SkMatrix m;
1229 m.setScale(dstSize.fWidth / srcRect.width(),
1230 dstSize.fHeight / srcRect.height());
joshualitt5531d512014-12-17 15:50:11 -08001231 SkMatrix viewM = *draw.fMatrix;
1232 viewM.preConcat(m);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001233
1234 GrTextureParams params;
reed93a12152015-03-16 10:08:34 -07001235 SkFilterQuality paintFilterQuality = paint.getFilterQuality();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001236 GrTextureParams::FilterMode textureFilterMode;
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001237
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001238 bool doBicubic = false;
1239
reed93a12152015-03-16 10:08:34 -07001240 switch(paintFilterQuality) {
1241 case kNone_SkFilterQuality:
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001242 textureFilterMode = GrTextureParams::kNone_FilterMode;
1243 break;
reed93a12152015-03-16 10:08:34 -07001244 case kLow_SkFilterQuality:
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001245 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
1246 break;
reed93a12152015-03-16 10:08:34 -07001247 case kMedium_SkFilterQuality:
joshualitt5531d512014-12-17 15:50:11 -08001248 if (viewM.getMinScale() < SK_Scalar1) {
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +00001249 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
1250 } else {
1251 // Don't trigger MIP level generation unnecessarily.
1252 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
1253 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001254 break;
reed93a12152015-03-16 10:08:34 -07001255 case kHigh_SkFilterQuality:
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +00001256 // Minification can look bad with the bicubic effect.
commit-bot@chromium.org9927bd32014-05-20 17:51:13 +00001257 doBicubic =
joshualitt5531d512014-12-17 15:50:11 -08001258 GrBicubicEffect::ShouldUseBicubic(viewM, &textureFilterMode);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001259 break;
1260 default:
1261 SkErrorInternals::SetError( kInvalidPaint_SkError,
1262 "Sorry, I don't understand the filtering "
1263 "mode you asked for. Falling back to "
1264 "MIPMaps.");
1265 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
1266 break;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001267 }
1268
commit-bot@chromium.org9927bd32014-05-20 17:51:13 +00001269 int tileFilterPad;
1270 if (doBicubic) {
1271 tileFilterPad = GrBicubicEffect::kFilterTexelPad;
1272 } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
1273 tileFilterPad = 0;
1274 } else {
1275 tileFilterPad = 1;
1276 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001277 params.setFilterMode(textureFilterMode);
1278
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001279 int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001280 int tileSize;
1281
1282 SkIRect clippedSrcRect;
joshualitt5531d512014-12-17 15:50:11 -08001283 if (this->shouldTileBitmap(bitmap, viewM, params, srcRectPtr, maxTileSize, &tileSize,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001284 &clippedSrcRect)) {
joshualitt5531d512014-12-17 15:50:11 -08001285 this->drawTiledBitmap(bitmap, viewM, srcRect, clippedSrcRect, params, paint, flags,
1286 tileSize, doBicubic);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001287 } else {
1288 // take the simple case
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001289 bool needsTextureDomain = needs_texture_domain(bitmap,
1290 srcRect,
1291 params,
joshualitt5531d512014-12-17 15:50:11 -08001292 viewM,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001293 doBicubic);
1294 this->internalDrawBitmap(bitmap,
joshualitt5531d512014-12-17 15:50:11 -08001295 viewM,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001296 srcRect,
1297 params,
1298 paint,
1299 flags,
1300 doBicubic,
1301 needsTextureDomain);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001302 }
1303}
1304
1305// Break 'bitmap' into several tiles to draw it since it has already
1306// been determined to be too large to fit in VRAM
1307void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
joshualitt5531d512014-12-17 15:50:11 -08001308 const SkMatrix& viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001309 const SkRect& srcRect,
1310 const SkIRect& clippedSrcIRect,
1311 const GrTextureParams& params,
1312 const SkPaint& paint,
1313 SkCanvas::DrawBitmapRectFlags flags,
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001314 int tileSize,
1315 bool bicubic) {
commit-bot@chromium.org9d5e3f12014-05-01 21:23:19 +00001316 // The following pixel lock is technically redundant, but it is desirable
1317 // to lock outside of the tile loop to prevent redecoding the whole image
1318 // at each tile in cases where 'bitmap' holds an SkDiscardablePixelRef that
1319 // is larger than the limit of the discardable memory pool.
1320 SkAutoLockPixels alp(bitmap);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001321 SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
1322
1323 int nx = bitmap.width() / tileSize;
1324 int ny = bitmap.height() / tileSize;
1325 for (int x = 0; x <= nx; x++) {
1326 for (int y = 0; y <= ny; y++) {
1327 SkRect tileR;
1328 tileR.set(SkIntToScalar(x * tileSize),
1329 SkIntToScalar(y * tileSize),
1330 SkIntToScalar((x + 1) * tileSize),
1331 SkIntToScalar((y + 1) * tileSize));
1332
1333 if (!SkRect::Intersects(tileR, clippedSrcRect)) {
1334 continue;
1335 }
1336
1337 if (!tileR.intersect(srcRect)) {
1338 continue;
1339 }
1340
1341 SkBitmap tmpB;
1342 SkIRect iTileR;
1343 tileR.roundOut(&iTileR);
1344 SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
1345 SkIntToScalar(iTileR.fTop));
1346
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001347 // Adjust the context matrix to draw at the right x,y in device space
joshualitt5531d512014-12-17 15:50:11 -08001348 SkMatrix viewM = viewMatrix;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001349 SkMatrix tmpM;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001350 tmpM.setTranslate(offset.fX - srcRect.fLeft, offset.fY - srcRect.fTop);
joshualitt5531d512014-12-17 15:50:11 -08001351 viewM.preConcat(tmpM);
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001352
robertphillipsec8bb942014-11-21 10:16:25 -08001353 if (GrTextureParams::kNone_FilterMode != params.filterMode() || bicubic) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001354 SkIRect iClampRect;
1355
1356 if (SkCanvas::kBleed_DrawBitmapRectFlag & flags) {
1357 // In bleed mode we want to always expand the tile on all edges
1358 // but stay within the bitmap bounds
1359 iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1360 } else {
1361 // In texture-domain/clamp mode we only want to expand the
1362 // tile on edges interior to "srcRect" (i.e., we want to
1363 // not bleed across the original clamped edges)
1364 srcRect.roundOut(&iClampRect);
1365 }
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001366 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
1367 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001368 }
1369
1370 if (bitmap.extractSubset(&tmpB, iTileR)) {
1371 // now offset it to make it "local" to our tmp bitmap
1372 tileR.offset(-offset.fX, -offset.fY);
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001373 GrTextureParams paramsTemp = params;
1374 bool needsTextureDomain = needs_texture_domain(bitmap,
1375 srcRect,
1376 paramsTemp,
joshualitt5531d512014-12-17 15:50:11 -08001377 viewM,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001378 bicubic);
1379 this->internalDrawBitmap(tmpB,
joshualitt5531d512014-12-17 15:50:11 -08001380 viewM,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001381 tileR,
1382 paramsTemp,
1383 paint,
1384 flags,
1385 bicubic,
1386 needsTextureDomain);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001387 }
1388 }
1389 }
1390}
1391
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001392
1393/*
1394 * This is called by drawBitmap(), which has to handle images that may be too
1395 * large to be represented by a single texture.
1396 *
1397 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1398 * and that non-texture portion of the GrPaint has already been setup.
1399 */
1400void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
joshualitt5531d512014-12-17 15:50:11 -08001401 const SkMatrix& viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001402 const SkRect& srcRect,
1403 const GrTextureParams& params,
1404 const SkPaint& paint,
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001405 SkCanvas::DrawBitmapRectFlags flags,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001406 bool bicubic,
1407 bool needsTextureDomain) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001408 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1409 bitmap.height() <= fContext->getMaxTextureSize());
1410
1411 GrTexture* texture;
bsalomonbcf0a522014-10-08 08:40:09 -07001412 AutoBitmapTexture abt(fContext, bitmap, &params, &texture);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001413 if (NULL == texture) {
1414 return;
1415 }
1416
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001417 SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() };
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001418 SkRect paintRect;
1419 SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width()));
1420 SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height()));
1421 paintRect.setLTRB(SkScalarMul(srcRect.fLeft, wInv),
1422 SkScalarMul(srcRect.fTop, hInv),
1423 SkScalarMul(srcRect.fRight, wInv),
1424 SkScalarMul(srcRect.fBottom, hInv));
1425
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001426 SkRect textureDomain = SkRect::MakeEmpty();
joshualittb0a8a372014-09-23 09:50:21 -07001427 SkAutoTUnref<GrFragmentProcessor> fp;
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001428 if (needsTextureDomain && !(flags & SkCanvas::kBleed_DrawBitmapRectFlag)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001429 // Use a constrained texture domain to avoid color bleeding
1430 SkScalar left, top, right, bottom;
1431 if (srcRect.width() > SK_Scalar1) {
1432 SkScalar border = SK_ScalarHalf / texture->width();
1433 left = paintRect.left() + border;
1434 right = paintRect.right() - border;
1435 } else {
1436 left = right = SkScalarHalf(paintRect.left() + paintRect.right());
1437 }
1438 if (srcRect.height() > SK_Scalar1) {
1439 SkScalar border = SK_ScalarHalf / texture->height();
1440 top = paintRect.top() + border;
1441 bottom = paintRect.bottom() - border;
1442 } else {
1443 top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom());
1444 }
1445 textureDomain.setLTRB(left, top, right, bottom);
commit-bot@chromium.org7d7f3142013-12-16 15:18:11 +00001446 if (bicubic) {
joshualittb0a8a372014-09-23 09:50:21 -07001447 fp.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), textureDomain));
commit-bot@chromium.org7d7f3142013-12-16 15:18:11 +00001448 } else {
joshualittb0a8a372014-09-23 09:50:21 -07001449 fp.reset(GrTextureDomainEffect::Create(texture,
joshualitt5531d512014-12-17 15:50:11 -08001450 SkMatrix::I(),
1451 textureDomain,
1452 GrTextureDomain::kClamp_Mode,
1453 params.filterMode()));
commit-bot@chromium.org7d7f3142013-12-16 15:18:11 +00001454 }
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001455 } else if (bicubic) {
commit-bot@chromium.orgbc91fd72013-12-10 12:53:39 +00001456 SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode());
1457 SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
joshualittb0a8a372014-09-23 09:50:21 -07001458 fp.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), tileModes));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001459 } else {
joshualittb0a8a372014-09-23 09:50:21 -07001460 fp.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001461 }
1462
1463 // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
1464 // the rest from the SkPaint.
1465 GrPaint grPaint;
joshualittb0a8a372014-09-23 09:50:21 -07001466 grPaint.addColorProcessor(fp);
reed0689d7b2014-06-14 05:30:20 -07001467 bool alphaOnly = !(kAlpha_8_SkColorType == bitmap.colorType());
bsalomon83d081a2014-07-08 09:56:10 -07001468 GrColor paintColor = (alphaOnly) ? SkColor2GrColorJustAlpha(paint.getColor()) :
1469 SkColor2GrColor(paint.getColor());
joshualitt25d9c152015-02-18 12:29:52 -08001470 SkPaint2GrPaintNoShader(this->context(), fRenderTarget, paint, paintColor, false, &grPaint);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001471
joshualitt570d2f82015-02-25 13:19:48 -08001472 fContext->drawNonAARectToRect(fRenderTarget, fClip, grPaint, viewMatrix, dstRect,
1473 paintRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001474}
1475
fmalita2d97bc12014-11-20 10:44:58 -08001476bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture,
1477 const SkImageFilter* filter,
1478 const SkImageFilter::Context& ctx,
1479 SkBitmap* result, SkIPoint* offset) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001480 SkASSERT(filter);
fmalita2d97bc12014-11-20 10:44:58 -08001481
1482 // FIXME: plumb actual surface props such that we don't have to lie about the flags here
1483 // (https://code.google.com/p/skia/issues/detail?id=3148).
1484 SkDeviceImageFilterProxy proxy(this, SkSurfaceProps(0, getLeakyProperties().pixelGeometry()));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001485
1486 if (filter->canFilterImageGPU()) {
rmistry82973db2015-04-01 15:53:13 -07001487 return filter->filterImageGPU(&proxy, wrap_texture(texture), ctx, result, offset);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001488 } else {
1489 return false;
1490 }
1491}
1492
1493void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1494 int left, int top, const SkPaint& paint) {
1495 // drawSprite is defined to be in device coords.
joshualitt5531d512014-12-17 15:50:11 -08001496 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001497
1498 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
1499 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1500 return;
1501 }
1502
1503 int w = bitmap.width();
1504 int h = bitmap.height();
1505
1506 GrTexture* texture;
1507 // draw sprite uses the default texture params
bsalomonbcf0a522014-10-08 08:40:09 -07001508 AutoBitmapTexture abt(fContext, bitmap, NULL, &texture);
joshualitt5f5a8d72015-02-25 14:09:45 -08001509 if (!texture) {
1510 return;
1511 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001512
1513 SkImageFilter* filter = paint.getImageFilter();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001514 // This bitmap will own the filtered result as a texture.
1515 SkBitmap filteredBitmap;
1516
bsalomon49f085d2014-09-05 13:34:00 -07001517 if (filter) {
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001518 SkIPoint offset = SkIPoint::Make(0, 0);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001519 SkMatrix matrix(*draw.fMatrix);
1520 matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001521 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
senorblancobe129b22014-08-08 07:14:35 -07001522 SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001523 // This cache is transient, and is freed (along with all its contained
1524 // textures) when it goes out of scope.
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +00001525 SkImageFilter::Context ctx(matrix, clipBounds, cache);
rmistry82973db2015-04-01 15:53:13 -07001526 if (this->filterTexture(fContext, texture, filter, ctx, &filteredBitmap,
fmalita2d97bc12014-11-20 10:44:58 -08001527 &offset)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001528 texture = (GrTexture*) filteredBitmap.getTexture();
1529 w = filteredBitmap.width();
1530 h = filteredBitmap.height();
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001531 left += offset.x();
1532 top += offset.y();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001533 } else {
1534 return;
1535 }
1536 }
1537
1538 GrPaint grPaint;
joshualittb0a8a372014-09-23 09:50:21 -07001539 grPaint.addColorTextureProcessor(texture, SkMatrix::I());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001540
joshualitt25d9c152015-02-18 12:29:52 -08001541 SkPaint2GrPaintNoShader(this->context(), fRenderTarget, paint,
1542 SkColor2GrColorJustAlpha(paint.getColor()), false, &grPaint);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001543
joshualitt25d9c152015-02-18 12:29:52 -08001544 fContext->drawNonAARectToRect(fRenderTarget,
joshualitt570d2f82015-02-25 13:19:48 -08001545 fClip,
joshualitt25d9c152015-02-18 12:29:52 -08001546 grPaint,
joshualitt16b27892014-12-18 07:47:16 -08001547 SkMatrix::I(),
1548 SkRect::MakeXYWH(SkIntToScalar(left),
1549 SkIntToScalar(top),
1550 SkIntToScalar(w),
1551 SkIntToScalar(h)),
1552 SkRect::MakeXYWH(0,
1553 0,
1554 SK_Scalar1 * w / texture->width(),
1555 SK_Scalar1 * h / texture->height()));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001556}
1557
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001558void SkGpuDevice::drawBitmapRect(const SkDraw& origDraw, const SkBitmap& bitmap,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001559 const SkRect* src, const SkRect& dst,
1560 const SkPaint& paint,
1561 SkCanvas::DrawBitmapRectFlags flags) {
1562 SkMatrix matrix;
1563 SkRect bitmapBounds, tmpSrc;
1564
1565 bitmapBounds.set(0, 0,
1566 SkIntToScalar(bitmap.width()),
1567 SkIntToScalar(bitmap.height()));
1568
1569 // Compute matrix from the two rectangles
bsalomon49f085d2014-09-05 13:34:00 -07001570 if (src) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001571 tmpSrc = *src;
1572 } else {
1573 tmpSrc = bitmapBounds;
1574 }
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001575
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001576 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1577
1578 // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null.
bsalomon49f085d2014-09-05 13:34:00 -07001579 if (src) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001580 if (!bitmapBounds.contains(tmpSrc)) {
1581 if (!tmpSrc.intersect(bitmapBounds)) {
1582 return; // nothing to draw
1583 }
1584 }
1585 }
1586
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001587 SkRect tmpDst;
1588 matrix.mapRect(&tmpDst, tmpSrc);
1589
1590 SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
1591 if (0 != tmpDst.fLeft || 0 != tmpDst.fTop) {
1592 // Translate so that tempDst's top left is at the origin.
1593 matrix = *origDraw.fMatrix;
1594 matrix.preTranslate(tmpDst.fLeft, tmpDst.fTop);
1595 draw.writable()->fMatrix = &matrix;
1596 }
1597 SkSize dstSize;
1598 dstSize.fWidth = tmpDst.width();
1599 dstSize.fHeight = tmpDst.height();
1600
1601 this->drawBitmapCommon(*draw, bitmap, &tmpSrc, &dstSize, paint, flags);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001602}
1603
1604void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
1605 int x, int y, const SkPaint& paint) {
1606 // clear of the source device must occur before CHECK_SHOULD_DRAW
egdanield78a1682014-07-09 10:41:26 -07001607 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawDevice", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001608 SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
kkinnunen2e4414e2015-02-19 07:20:40 -08001609
1610 // TODO: If the source device covers the whole of this device, we could
1611 // omit fNeedsClear -related flushing.
1612 // TODO: if source needs clear, we could maybe omit the draw fully.
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001613
1614 // drawDevice is defined to be in device coords.
joshualitt5531d512014-12-17 15:50:11 -08001615 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001616
1617 GrRenderTarget* devRT = dev->accessRenderTarget();
1618 GrTexture* devTex;
1619 if (NULL == (devTex = devRT->asTexture())) {
1620 return;
1621 }
1622
robertphillips7b9e8a42014-12-11 08:20:31 -08001623 const SkImageInfo ii = dev->imageInfo();
1624 int w = ii.width();
1625 int h = ii.height();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001626
1627 SkImageFilter* filter = paint.getImageFilter();
1628 // This bitmap will own the filtered result as a texture.
1629 SkBitmap filteredBitmap;
1630
bsalomon49f085d2014-09-05 13:34:00 -07001631 if (filter) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001632 SkIPoint offset = SkIPoint::Make(0, 0);
1633 SkMatrix matrix(*draw.fMatrix);
1634 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001635 SkIRect clipBounds = SkIRect::MakeWH(devTex->width(), devTex->height());
senorblanco55b6d8b2014-07-30 11:26:46 -07001636 // This cache is transient, and is freed (along with all its contained
1637 // textures) when it goes out of scope.
senorblancobe129b22014-08-08 07:14:35 -07001638 SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +00001639 SkImageFilter::Context ctx(matrix, clipBounds, cache);
rmistry82973db2015-04-01 15:53:13 -07001640 if (this->filterTexture(fContext, devTex, filter, ctx, &filteredBitmap,
1641 &offset)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001642 devTex = filteredBitmap.getTexture();
1643 w = filteredBitmap.width();
1644 h = filteredBitmap.height();
1645 x += offset.fX;
1646 y += offset.fY;
1647 } else {
1648 return;
1649 }
1650 }
1651
1652 GrPaint grPaint;
joshualittb0a8a372014-09-23 09:50:21 -07001653 grPaint.addColorTextureProcessor(devTex, SkMatrix::I());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001654
joshualitt25d9c152015-02-18 12:29:52 -08001655 SkPaint2GrPaintNoShader(this->context(), fRenderTarget, paint,
1656 SkColor2GrColorJustAlpha(paint.getColor()), false, &grPaint);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001657
1658 SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x),
1659 SkIntToScalar(y),
1660 SkIntToScalar(w),
1661 SkIntToScalar(h));
1662
1663 // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate
1664 // scratch texture).
1665 SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(),
1666 SK_Scalar1 * h / devTex->height());
1667
joshualitt570d2f82015-02-25 13:19:48 -08001668 fContext->drawNonAARectToRect(fRenderTarget, fClip, grPaint, SkMatrix::I(), dstRect,
1669 srcRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001670}
1671
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001672bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001673 return filter->canFilterImageGPU();
1674}
1675
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001676bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001677 const SkImageFilter::Context& ctx,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001678 SkBitmap* result, SkIPoint* offset) {
1679 // want explicitly our impl, so guard against a subclass of us overriding it
1680 if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
1681 return false;
1682 }
1683
1684 SkAutoLockPixels alp(src, !src.getTexture());
1685 if (!src.getTexture() && !src.readyToDraw()) {
1686 return false;
1687 }
1688
1689 GrTexture* texture;
1690 // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup
1691 // must be pushed upstack.
bsalomonbcf0a522014-10-08 08:40:09 -07001692 AutoBitmapTexture abt(fContext, src, NULL, &texture);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001693
rmistry82973db2015-04-01 15:53:13 -07001694 return this->filterTexture(fContext, texture, filter, ctx, result, offset);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001695}
1696
1697///////////////////////////////////////////////////////////////////////////////
1698
1699// must be in SkCanvas::VertexMode order
1700static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1701 kTriangles_GrPrimitiveType,
1702 kTriangleStrip_GrPrimitiveType,
1703 kTriangleFan_GrPrimitiveType,
1704};
1705
1706void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1707 int vertexCount, const SkPoint vertices[],
1708 const SkPoint texs[], const SkColor colors[],
1709 SkXfermode* xmode,
1710 const uint16_t indices[], int indexCount,
1711 const SkPaint& paint) {
joshualitt5531d512014-12-17 15:50:11 -08001712 CHECK_SHOULD_DRAW(draw);
egdanield78a1682014-07-09 10:41:26 -07001713 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawVertices", fContext);
mtklein533eb782014-08-27 10:39:42 -07001714
dandov32a311b2014-07-15 19:46:26 -07001715 const uint16_t* outIndices;
1716 SkAutoTDeleteArray<uint16_t> outAlloc(NULL);
1717 GrPrimitiveType primType;
1718 GrPaint grPaint;
bsalomona098dd42014-08-06 11:01:44 -07001719
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001720 // If both textures and vertex-colors are NULL, strokes hairlines with the paint's color.
1721 if ((NULL == texs || NULL == paint.getShader()) && NULL == colors) {
mtklein533eb782014-08-27 10:39:42 -07001722
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001723 texs = NULL;
mtklein533eb782014-08-27 10:39:42 -07001724
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001725 SkPaint copy(paint);
1726 copy.setStyle(SkPaint::kStroke_Style);
1727 copy.setStrokeWidth(0);
mtklein533eb782014-08-27 10:39:42 -07001728
dandov32a311b2014-07-15 19:46:26 -07001729 // we ignore the shader if texs is null.
joshualitt25d9c152015-02-18 12:29:52 -08001730 SkPaint2GrPaintNoShader(this->context(), fRenderTarget, copy,
1731 SkColor2GrColor(copy.getColor()), NULL == colors, &grPaint);
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001732
dandov32a311b2014-07-15 19:46:26 -07001733 primType = kLines_GrPrimitiveType;
1734 int triangleCount = 0;
bsalomona098dd42014-08-06 11:01:44 -07001735 int n = (NULL == indices) ? vertexCount : indexCount;
dandov32a311b2014-07-15 19:46:26 -07001736 switch (vmode) {
1737 case SkCanvas::kTriangles_VertexMode:
bsalomona098dd42014-08-06 11:01:44 -07001738 triangleCount = n / 3;
dandov32a311b2014-07-15 19:46:26 -07001739 break;
1740 case SkCanvas::kTriangleStrip_VertexMode:
1741 case SkCanvas::kTriangleFan_VertexMode:
bsalomona098dd42014-08-06 11:01:44 -07001742 triangleCount = n - 2;
dandov32a311b2014-07-15 19:46:26 -07001743 break;
1744 }
mtklein533eb782014-08-27 10:39:42 -07001745
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001746 VertState state(vertexCount, indices, indexCount);
1747 VertState::Proc vertProc = state.chooseProc(vmode);
mtklein533eb782014-08-27 10:39:42 -07001748
dandov32a311b2014-07-15 19:46:26 -07001749 //number of indices for lines per triangle with kLines
1750 indexCount = triangleCount * 6;
mtklein533eb782014-08-27 10:39:42 -07001751
dandov32a311b2014-07-15 19:46:26 -07001752 outAlloc.reset(SkNEW_ARRAY(uint16_t, indexCount));
1753 outIndices = outAlloc.get();
1754 uint16_t* auxIndices = outAlloc.get();
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001755 int i = 0;
1756 while (vertProc(&state)) {
dandov32a311b2014-07-15 19:46:26 -07001757 auxIndices[i] = state.f0;
1758 auxIndices[i + 1] = state.f1;
1759 auxIndices[i + 2] = state.f1;
1760 auxIndices[i + 3] = state.f2;
1761 auxIndices[i + 4] = state.f2;
1762 auxIndices[i + 5] = state.f0;
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001763 i += 6;
1764 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001765 } else {
dandov32a311b2014-07-15 19:46:26 -07001766 outIndices = indices;
1767 primType = gVertexMode2PrimitiveType[vmode];
mtklein533eb782014-08-27 10:39:42 -07001768
dandov32a311b2014-07-15 19:46:26 -07001769 if (NULL == texs || NULL == paint.getShader()) {
joshualitt25d9c152015-02-18 12:29:52 -08001770 SkPaint2GrPaintNoShader(this->context(), fRenderTarget, paint,
1771 SkColor2GrColor(paint.getColor()),
dandov32a311b2014-07-15 19:46:26 -07001772 NULL == colors, &grPaint);
1773 } else {
joshualitt25d9c152015-02-18 12:29:52 -08001774 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix,
1775 NULL == colors, &grPaint);
dandov32a311b2014-07-15 19:46:26 -07001776 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001777 }
1778
mtklein2583b622014-06-04 08:20:41 -07001779#if 0
bsalomon49f085d2014-09-05 13:34:00 -07001780 if (xmode && texs && colors) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001781 if (!SkXfermode::IsMode(xmode, SkXfermode::kModulate_Mode)) {
1782 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
mtklein2583b622014-06-04 08:20:41 -07001783 return;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001784 }
1785 }
mtklein2583b622014-06-04 08:20:41 -07001786#endif
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001787
1788 SkAutoSTMalloc<128, GrColor> convertedColors(0);
bsalomon49f085d2014-09-05 13:34:00 -07001789 if (colors) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001790 // need to convert byte order and from non-PM to PM
1791 convertedColors.reset(vertexCount);
commit-bot@chromium.orgc93e6812014-05-23 08:09:26 +00001792 SkColor color;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001793 for (int i = 0; i < vertexCount; ++i) {
commit-bot@chromium.orgc93e6812014-05-23 08:09:26 +00001794 color = colors[i];
1795 if (paint.getAlpha() != 255) {
1796 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paint.getAlpha()));
1797 }
1798 convertedColors[i] = SkColor2GrColor(color);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001799 }
1800 colors = convertedColors.get();
1801 }
joshualitt25d9c152015-02-18 12:29:52 -08001802 fContext->drawVertices(fRenderTarget,
joshualitt570d2f82015-02-25 13:19:48 -08001803 fClip,
joshualitt25d9c152015-02-18 12:29:52 -08001804 grPaint,
joshualitt5531d512014-12-17 15:50:11 -08001805 *draw.fMatrix,
dandov32a311b2014-07-15 19:46:26 -07001806 primType,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001807 vertexCount,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +00001808 vertices,
1809 texs,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001810 colors,
dandov32a311b2014-07-15 19:46:26 -07001811 outIndices,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001812 indexCount);
1813}
1814
1815///////////////////////////////////////////////////////////////////////////////
1816
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001817void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
joshualitt5531d512014-12-17 15:50:11 -08001818 size_t byteLength, SkScalar x, SkScalar y,
1819 const SkPaint& paint) {
1820 CHECK_SHOULD_DRAW(draw);
egdanield78a1682014-07-09 10:41:26 -07001821 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawText", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001822
jvanverth8c27a182014-10-14 08:45:50 -07001823 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -08001824 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +00001825
jvanverth8c27a182014-10-14 08:45:50 -07001826 SkDEBUGCODE(this->validate();)
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +00001827
joshualitt6e8cd962015-03-20 10:30:14 -07001828 fTextContext->drawText(fRenderTarget, fClip, grPaint, paint, *draw.fMatrix,
1829 (const char *)text, byteLength, x, y, draw.fClip->getBounds());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001830}
1831
fmalita05c4a432014-09-29 06:29:53 -07001832void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, size_t byteLength,
1833 const SkScalar pos[], int scalarsPerPos,
1834 const SkPoint& offset, const SkPaint& paint) {
egdanielbbcb38d2014-06-19 10:19:29 -07001835 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPosText", fContext);
joshualitt5531d512014-12-17 15:50:11 -08001836 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001837
jvanverth8c27a182014-10-14 08:45:50 -07001838 GrPaint grPaint;
joshualitt25d9c152015-02-18 12:29:52 -08001839 SkPaint2GrPaintShader(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +00001840
jvanverth8c27a182014-10-14 08:45:50 -07001841 SkDEBUGCODE(this->validate();)
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +00001842
joshualitt6e8cd962015-03-20 10:30:14 -07001843 fTextContext->drawPosText(fRenderTarget, fClip, grPaint, paint, *draw.fMatrix,
1844 (const char *)text, byteLength, pos, scalarsPerPos, offset,
1845 draw.fClip->getBounds());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001846}
1847
joshualitt9c328182015-03-23 08:13:04 -07001848void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y,
1849 const SkPaint& paint, SkDrawFilter* drawFilter) {
1850 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawTextBlob", fContext);
1851 CHECK_SHOULD_DRAW(draw);
1852
1853 SkDEBUGCODE(this->validate();)
1854
1855 fTextContext->drawTextBlob(fRenderTarget, fClip, paint, *draw.fMatrix, blob, x, y, drawFilter,
1856 draw.fClip->getBounds());
1857}
1858
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001859///////////////////////////////////////////////////////////////////////////////
1860
reedb2db8982014-11-13 12:41:02 -08001861bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001862 if (paint.getShader() ||
reedb2db8982014-11-13 12:41:02 -08001863 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode) ||
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001864 paint.getMaskFilter() ||
1865 paint.getRasterizer() ||
1866 paint.getColorFilter() ||
1867 paint.getPathEffect() ||
1868 paint.isFakeBoldText() ||
reedb2db8982014-11-13 12:41:02 -08001869 paint.getStyle() != SkPaint::kFill_Style)
1870 {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001871 return true;
1872 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001873 return false;
1874}
1875
1876void SkGpuDevice::flush() {
1877 DO_DEFERRED_CLEAR();
bsalomon87a94eb2014-11-03 14:28:32 -08001878 fRenderTarget->prepareForExternalRead();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001879}
1880
1881///////////////////////////////////////////////////////////////////////////////
1882
reed76033be2015-03-14 10:54:31 -07001883SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
bsalomonf2703d82014-10-28 14:33:06 -07001884 GrSurfaceDesc desc;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001885 desc.fConfig = fRenderTarget->config();
bsalomonf2703d82014-10-28 14:33:06 -07001886 desc.fFlags = kRenderTarget_GrSurfaceFlag;
fmalita6987dca2014-11-13 08:33:37 -08001887 desc.fWidth = cinfo.fInfo.width();
1888 desc.fHeight = cinfo.fInfo.height();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001889 desc.fSampleCnt = fRenderTarget->numSamples();
1890
1891 SkAutoTUnref<GrTexture> texture;
1892 // Skia's convention is to only clear a device if it is non-opaque.
fmalita6987dca2014-11-13 08:33:37 -08001893 unsigned flags = cinfo.fInfo.isOpaque() ? 0 : kNeedClear_Flag;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001894
hcm4396fa52014-10-27 21:43:30 -07001895 // layers are never draw in repeat modes, so we can request an approx
1896 // match and ignore any padding.
reed76033be2015-03-14 10:54:31 -07001897 const GrContext::ScratchTexMatch match = (kNever_TileUsage == cinfo.fTileUsage) ?
hcm4396fa52014-10-27 21:43:30 -07001898 GrContext::kApprox_ScratchTexMatch :
1899 GrContext::kExact_ScratchTexMatch;
bsalomone3059732014-10-14 11:47:22 -07001900 texture.reset(fContext->refScratchTexture(desc, match));
bsalomonafe30052015-01-16 07:32:33 -08001901
1902 if (texture) {
1903 SkSurfaceProps props(fSurfaceProps.flags(), cinfo.fPixelGeometry);
rmistry82973db2015-04-01 15:53:13 -07001904 return SkGpuDevice::Create(texture->asRenderTarget(), &props, flags);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001905 } else {
joshualitt5f5a8d72015-02-25 14:09:45 -08001906 SkErrorInternals::SetError( kInternalError_SkError,
1907 "---- failed to create compatible device texture [%d %d]\n",
1908 cinfo.fInfo.width(), cinfo.fInfo.height());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001909 return NULL;
1910 }
1911}
1912
reed4a8126e2014-09-22 07:29:03 -07001913SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
bsalomonafe30052015-01-16 07:32:33 -08001914 // TODO: Change the signature of newSurface to take a budgeted parameter.
1915 static const SkSurface::Budgeted kBudgeted = SkSurface::kNo_Budgeted;
1916 return SkSurface::NewRenderTarget(fContext, kBudgeted, info, fRenderTarget->numSamples(),
1917 &props);
reed@google.com76f10a32014-02-05 15:32:21 +00001918}
1919
robertphillips30d2cc62014-09-24 08:52:18 -07001920bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* mainPicture,
reedd5fa1a42014-08-09 11:08:05 -07001921 const SkMatrix* matrix, const SkPaint* paint) {
robertphillips63242d72014-12-04 08:31:02 -08001922#ifndef SK_IGNORE_GPU_LAYER_HOISTING
robertphillips30d78412014-11-24 09:49:17 -08001923 // todo: should handle this natively
1924 if (paint) {
reedd5fa1a42014-08-09 11:08:05 -07001925 return false;
1926 }
1927
robertphillips82365912014-11-12 09:32:34 -08001928 SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
robertphillips81f71b62014-11-11 04:54:49 -08001929
1930 const SkPicture::AccelData* data = mainPicture->EXPERIMENTAL_getAccelData(key);
1931 if (!data) {
1932 return false;
1933 }
1934
robertphillipse5524cd2015-02-20 12:30:26 -08001935 const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data);
1936 if (0 == gpuData->numBlocks()) {
1937 return false;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +00001938 }
1939
robertphillipsfd61ed02014-10-28 07:21:44 -07001940 SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled;
robertphillips1c4c5282014-09-18 12:03:15 -07001941
robertphillipse5524cd2015-02-20 12:30:26 -08001942 SkIRect iBounds;
1943 if (!mainCanvas->getClipDeviceBounds(&iBounds)) {
1944 return false;
1945 }
1946
1947 SkRect clipBounds = SkRect::Make(iBounds);
1948
1949 SkMatrix initialMatrix = mainCanvas->getTotalMatrix();
1950
robertphillipsfd61ed02014-10-28 07:21:44 -07001951 GrLayerHoister::FindLayersToAtlas(fContext, mainPicture,
robertphillips30d78412014-11-24 09:49:17 -08001952 initialMatrix,
robertphillipsfd61ed02014-10-28 07:21:44 -07001953 clipBounds,
robertphillipsa63f32e2014-11-10 08:10:42 -08001954 &atlasedNeedRendering, &atlasedRecycled,
1955 fRenderTarget->numSamples());
robertphillipsfd61ed02014-10-28 07:21:44 -07001956
1957 GrLayerHoister::DrawLayersToAtlas(fContext, atlasedNeedRendering);
1958
1959 SkTDArray<GrHoistedLayer> needRendering, recycled;
1960
robertphillipse5524cd2015-02-20 12:30:26 -08001961 SkAutoCanvasMatrixPaint acmp(mainCanvas, matrix, paint, mainPicture->cullRect());
1962
robertphillipsfd61ed02014-10-28 07:21:44 -07001963 GrLayerHoister::FindLayersToHoist(fContext, mainPicture,
robertphillips30d78412014-11-24 09:49:17 -08001964 initialMatrix,
robertphillipsfd61ed02014-10-28 07:21:44 -07001965 clipBounds,
robertphillipsa63f32e2014-11-10 08:10:42 -08001966 &needRendering, &recycled,
1967 fRenderTarget->numSamples());
robertphillipsfd61ed02014-10-28 07:21:44 -07001968
1969 GrLayerHoister::DrawLayers(fContext, needRendering);
robertphillips@google.combeb1af22014-05-07 21:31:09 +00001970
robertphillips64bf7672014-08-21 13:07:35 -07001971 // Render the entire picture using new layers
robertphillipse99d4992014-12-03 07:33:57 -08001972 GrRecordReplaceDraw(mainPicture, mainCanvas, fContext->getLayerCache(),
1973 initialMatrix, NULL);
robertphillips64bf7672014-08-21 13:07:35 -07001974
robertphillipsfd61ed02014-10-28 07:21:44 -07001975 GrLayerHoister::UnlockLayers(fContext, needRendering);
1976 GrLayerHoister::UnlockLayers(fContext, recycled);
1977 GrLayerHoister::UnlockLayers(fContext, atlasedNeedRendering);
1978 GrLayerHoister::UnlockLayers(fContext, atlasedRecycled);
robertphillips64bf7672014-08-21 13:07:35 -07001979
1980 return true;
robertphillips63242d72014-12-04 08:31:02 -08001981#else
1982 return false;
1983#endif
robertphillips64bf7672014-08-21 13:07:35 -07001984}
1985
senorblancobe129b22014-08-08 07:14:35 -07001986SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() {
senorblanco55b6d8b2014-07-30 11:26:46 -07001987 // We always return a transient cache, so it is freed after each
1988 // filter traversal.
senorblancobe129b22014-08-08 07:14:35 -07001989 return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize);
senorblanco55b6d8b2014-07-30 11:26:46 -07001990}
reedf037e0b2014-10-30 11:34:15 -07001991
1992#endif