blob: 0decb32b037b53187844c84443820717e027915b [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
kkinnunenabcfab42015-02-22 22:53:44 -080010#include "GrContext.h"
kkinnunenabcfab42015-02-22 22:53:44 -080011#include "GrGpu.h"
12#include "GrGpuResourcePriv.h"
robertphillips98d709b2014-09-02 10:20:50 -070013#include "GrLayerHoister.h"
robertphillips274b4ba2014-09-04 07:24:18 -070014#include "GrRecordReplaceDraw.h"
egdanield58a0ba2014-06-11 10:30:05 -070015#include "GrStrokeInfo.h"
joshualitt8f94bb22015-04-28 07:04:11 -070016#include "GrTextContext.h"
egdanielbbcb38d2014-06-19 10:19:29 -070017#include "GrTracing.h"
robertphillips30d78412014-11-24 09:49:17 -080018#include "SkCanvasPriv.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000019#include "SkDeviceImageFilterProxy.h"
20#include "SkDrawProcs.h"
kkinnunenabcfab42015-02-22 22:53:44 -080021#include "SkErrorInternals.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000022#include "SkGlyphCache.h"
kkinnunenabcfab42015-02-22 22:53:44 -080023#include "SkGrTexturePixelRef.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000024#include "SkImageFilter.h"
robertphillips82365912014-11-12 09:32:34 -080025#include "SkLayerInfo.h"
commit-bot@chromium.org82139702014-03-10 22:53:20 +000026#include "SkMaskFilter.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000027#include "SkPathEffect.h"
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +000028#include "SkPicture.h"
robertphillipsdb539902014-07-01 08:47:04 -070029#include "SkPictureData.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000030#include "SkRRect.h"
kkinnunenabcfab42015-02-22 22:53:44 -080031#include "SkRecord.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000032#include "SkStroke.h"
reed@google.com76f10a32014-02-05 15:32:21 +000033#include "SkSurface.h"
kkinnunenabcfab42015-02-22 22:53:44 -080034#include "SkSurface_Gpu.h"
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +000035#include "SkTLazy.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000036#include "SkUtils.h"
commit-bot@chromium.org559a8832014-05-30 10:08:22 +000037#include "SkVertState.h"
robertphillips320c9232014-07-29 06:07:19 -070038#include "SkXfermode.h"
kkinnunenabcfab42015-02-22 22:53:44 -080039#include "effects/GrBicubicEffect.h"
40#include "effects/GrDashingEffect.h"
41#include "effects/GrSimpleTextureEffect.h"
42#include "effects/GrTextureDomain.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000043
reedf037e0b2014-10-30 11:34:15 -070044#if SK_SUPPORT_GPU
45
senorblanco55b6d8b2014-07-30 11:26:46 -070046enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 };
47
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000048#if 0
49 extern bool (*gShouldDrawProc)();
joshualitt5531d512014-12-17 15:50:11 -080050 #define CHECK_SHOULD_DRAW(draw) \
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000051 do { \
52 if (gShouldDrawProc && !gShouldDrawProc()) return; \
joshualitt5531d512014-12-17 15:50:11 -080053 this->prepareDraw(draw); \
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000054 } while (0)
55#else
joshualitt5531d512014-12-17 15:50:11 -080056 #define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw)
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000057#endif
58
59// This constant represents the screen alignment criterion in texels for
60// requiring texture domain clamping to prevent color bleeding when drawing
61// a sub region of a larger source image.
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +000062#define COLOR_BLEED_TOLERANCE 0.001f
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000063
64#define DO_DEFERRED_CLEAR() \
65 do { \
bsalomonafe30052015-01-16 07:32:33 -080066 if (fNeedClear) { \
67 this->clearAll(); \
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +000068 } \
69 } while (false) \
70
71///////////////////////////////////////////////////////////////////////////////
72
73#define CHECK_FOR_ANNOTATION(paint) \
74 do { if (paint.getAnnotation()) { return; } } while (0)
75
76///////////////////////////////////////////////////////////////////////////////
77
bsalomonbcf0a522014-10-08 08:40:09 -070078// Helper for turning a bitmap into a texture. If the bitmap is GrTexture backed this
79// just accesses the backing GrTexture. Otherwise, it creates a cached texture
80// representation and releases it in the destructor.
81class AutoBitmapTexture : public SkNoncopyable {
Brian Salomon9323b8b2014-10-07 15:07:38 -040082public:
bsalomonbcf0a522014-10-08 08:40:09 -070083 AutoBitmapTexture() {}
robertphillipsdbe60742014-09-30 06:54:17 -070084
bsalomonbcf0a522014-10-08 08:40:09 -070085 AutoBitmapTexture(GrContext* context,
86 const SkBitmap& bitmap,
87 const GrTextureParams* params,
88 GrTexture** texture) {
Brian Salomon9323b8b2014-10-07 15:07:38 -040089 SkASSERT(texture);
bsalomonbcf0a522014-10-08 08:40:09 -070090 *texture = this->set(context, bitmap, params);
Brian Salomon9323b8b2014-10-07 15:07:38 -040091 }
92
bsalomonbcf0a522014-10-08 08:40:09 -070093 GrTexture* set(GrContext* context,
Brian Salomon9323b8b2014-10-07 15:07:38 -040094 const SkBitmap& bitmap,
95 const GrTextureParams* params) {
bsalomonbcf0a522014-10-08 08:40:09 -070096 // Either get the texture directly from the bitmap, or else use the cache and
97 // remember to unref it.
98 if (GrTexture* bmpTexture = bitmap.getTexture()) {
99 fTexture.reset(NULL);
100 return bmpTexture;
101 } else {
102 fTexture.reset(GrRefCachedBitmapTexture(context, bitmap, params));
103 return fTexture.get();
Brian Salomon9323b8b2014-10-07 15:07:38 -0400104 }
Brian Salomon9323b8b2014-10-07 15:07:38 -0400105 }
106
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000107private:
bsalomonbcf0a522014-10-08 08:40:09 -0700108 SkAutoTUnref<GrTexture> fTexture;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000109};
110
111///////////////////////////////////////////////////////////////////////////////
112
113struct GrSkDrawProcs : public SkDrawProcs {
114public:
115 GrContext* fContext;
116 GrTextContext* fTextContext;
117 GrFontScaler* fFontScaler; // cached in the skia glyphcache
118};
119
120///////////////////////////////////////////////////////////////////////////////
121
bsalomonafe30052015-01-16 07:32:33 -0800122SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, const SkSurfaceProps* props, unsigned flags) {
senorblancod0d37ca2015-04-02 04:54:56 -0700123 return SkGpuDevice::Create(rt, rt->width(), rt->height(), props, flags);
124}
125
126SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, int width, int height,
127 const SkSurfaceProps* props, unsigned flags) {
bsalomonafe30052015-01-16 07:32:33 -0800128 if (!rt || rt->wasDestroyed()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000129 return NULL;
130 }
senorblancod0d37ca2015-04-02 04:54:56 -0700131 return SkNEW_ARGS(SkGpuDevice, (rt, width, height, props, flags));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000132}
133
bsalomonafe30052015-01-16 07:32:33 -0800134static SkDeviceProperties surfaceprops_to_deviceprops(const SkSurfaceProps* props) {
135 if (props) {
136 return SkDeviceProperties(props->pixelGeometry());
137 } else {
138 return SkDeviceProperties(SkDeviceProperties::kLegacyLCD_InitType);
139 }
reedb2db8982014-11-13 12:41:02 -0800140}
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000141
bsalomonafe30052015-01-16 07:32:33 -0800142static SkSurfaceProps copy_or_default_props(const SkSurfaceProps* props) {
143 if (props) {
144 return SkSurfaceProps(*props);
145 } else {
146 return SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
147 }
148}
149
senorblancod0d37ca2015-04-02 04:54:56 -0700150SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height,
151 const SkSurfaceProps* props, unsigned flags)
reedb2db8982014-11-13 12:41:02 -0800152 : INHERITED(surfaceprops_to_deviceprops(props))
bsalomonafe30052015-01-16 07:32:33 -0800153 , fSurfaceProps(copy_or_default_props(props))
reedb2db8982014-11-13 12:41:02 -0800154{
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000155 fDrawProcs = NULL;
156
bsalomonafe30052015-01-16 07:32:33 -0800157 fContext = SkRef(rt->getContext());
158 fNeedClear = flags & kNeedClear_Flag;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000159
bsalomonafe30052015-01-16 07:32:33 -0800160 fRenderTarget = SkRef(rt);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000161
senorblancod0d37ca2015-04-02 04:54:56 -0700162 SkImageInfo info = rt->surfacePriv().info().makeWH(width, height);
bsalomonafe30052015-01-16 07:32:33 -0800163 SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, rt));
bsalomonafbf2d62014-09-30 12:18:44 -0700164 fLegacyBitmap.setInfo(info);
reed89443ab2014-06-27 11:34:19 -0700165 fLegacyBitmap.setPixelRef(pr)->unref();
kkinnunenc6cb56f2014-06-24 00:12:27 -0700166
bsalomonafe30052015-01-16 07:32:33 -0800167 bool useDFT = fSurfaceProps.isUseDistanceFieldFonts();
joshualitt6e8cd962015-03-20 10:30:14 -0700168 fTextContext = fContext->createTextContext(fRenderTarget, this, this->getLeakyProperties(),
169 useDFT);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000170}
171
kkinnunenabcfab42015-02-22 22:53:44 -0800172GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::Budgeted budgeted,
173 const SkImageInfo& origInfo, int sampleCount) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000174 if (kUnknown_SkColorType == origInfo.colorType() ||
175 origInfo.width() < 0 || origInfo.height() < 0) {
176 return NULL;
177 }
178
bsalomonafe30052015-01-16 07:32:33 -0800179 if (!context) {
180 return NULL;
181 }
182
reede5ea5002014-09-03 11:54:58 -0700183 SkColorType ct = origInfo.colorType();
184 SkAlphaType at = origInfo.alphaType();
reede5ea5002014-09-03 11:54:58 -0700185 if (kRGB_565_SkColorType == ct) {
186 at = kOpaque_SkAlphaType; // force this setting
bsalomonafe30052015-01-16 07:32:33 -0800187 } else if (ct != kBGRA_8888_SkColorType && ct != kRGBA_8888_SkColorType) {
188 // Fall back from whatever ct was to default of kRGBA or kBGRA which is aliased as kN32
reede5ea5002014-09-03 11:54:58 -0700189 ct = kN32_SkColorType;
bsalomonafe30052015-01-16 07:32:33 -0800190 }
191 if (kOpaque_SkAlphaType != at) {
192 at = kPremul_SkAlphaType; // force this setting
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000193 }
reede5ea5002014-09-03 11:54:58 -0700194 const SkImageInfo info = SkImageInfo::Make(origInfo.width(), origInfo.height(), ct, at);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000195
bsalomonf2703d82014-10-28 14:33:06 -0700196 GrSurfaceDesc desc;
197 desc.fFlags = kRenderTarget_GrSurfaceFlag;
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000198 desc.fWidth = info.width();
199 desc.fHeight = info.height();
commit-bot@chromium.org3adcc342014-04-23 19:18:09 +0000200 desc.fConfig = SkImageInfo2GrPixelConfig(info);
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000201 desc.fSampleCnt = sampleCount;
kkinnunenabcfab42015-02-22 22:53:44 -0800202 GrTexture* texture = context->createTexture(desc, SkToBool(budgeted), NULL, 0);
203 if (NULL == texture) {
204 return NULL;
205 }
206 SkASSERT(NULL != texture->asRenderTarget());
207 return texture->asRenderTarget();
208}
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000209
kkinnunenabcfab42015-02-22 22:53:44 -0800210SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgeted,
211 const SkImageInfo& info, int sampleCount,
212 const SkSurfaceProps* props, unsigned flags) {
213
214 SkAutoTUnref<GrRenderTarget> rt(CreateRenderTarget(context, budgeted, info, sampleCount));
215 if (NULL == rt) {
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000216 return NULL;
217 }
skia.committer@gmail.com969588f2014-02-16 03:01:56 +0000218
senorblancod0d37ca2015-04-02 04:54:56 -0700219 return SkNEW_ARGS(SkGpuDevice, (rt, info.width(), info.height(), props, flags));
commit-bot@chromium.org15a14052014-02-16 00:59:25 +0000220}
221
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000222SkGpuDevice::~SkGpuDevice() {
223 if (fDrawProcs) {
224 delete fDrawProcs;
225 }
skia.committer@gmail.comd2ac07b2014-01-25 07:01:49 +0000226
jvanverth8c27a182014-10-14 08:45:50 -0700227 delete fTextContext;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000228
bsalomon32d0b3b2014-08-29 07:50:23 -0700229 fRenderTarget->unref();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000230 fContext->unref();
231}
232
233///////////////////////////////////////////////////////////////////////////////
234
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000235bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
236 int x, int y) {
237 DO_DEFERRED_CLEAR();
238
239 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
commit-bot@chromium.org3adcc342014-04-23 19:18:09 +0000240 GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo);
commit-bot@chromium.orga713f9c2014-03-17 21:31:26 +0000241 if (kUnknown_GrPixelConfig == config) {
242 return false;
243 }
244
245 uint32_t flags = 0;
246 if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
247 flags = GrContext::kUnpremul_PixelOpsFlag;
248 }
249 return fContext->readRenderTargetPixels(fRenderTarget, x, y, dstInfo.width(), dstInfo.height(),
250 config, dstPixels, dstRowBytes, flags);
251}
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000252
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000253bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
254 int x, int y) {
255 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
commit-bot@chromium.org3adcc342014-04-23 19:18:09 +0000256 GrPixelConfig config = SkImageInfo2GrPixelConfig(info);
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000257 if (kUnknown_GrPixelConfig == config) {
258 return false;
259 }
260 uint32_t flags = 0;
261 if (kUnpremul_SkAlphaType == info.alphaType()) {
262 flags = GrContext::kUnpremul_PixelOpsFlag;
263 }
264 fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags);
265
266 // need to bump our genID for compatibility with clients that "know" we have a bitmap
reed89443ab2014-06-27 11:34:19 -0700267 fLegacyBitmap.notifyPixelsChanged();
commit-bot@chromium.org4cd9e212014-03-07 03:25:16 +0000268
269 return true;
270}
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000271
senorblanco@chromium.orgb7b7eb32014-03-19 18:24:04 +0000272const SkBitmap& SkGpuDevice::onAccessBitmap() {
273 DO_DEFERRED_CLEAR();
reed89443ab2014-06-27 11:34:19 -0700274 return fLegacyBitmap;
senorblanco@chromium.orgb7b7eb32014-03-19 18:24:04 +0000275}
276
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000277void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
278 INHERITED::onAttachToCanvas(canvas);
279
280 // Canvas promises that this ptr is valid until onDetachFromCanvas is called
joshualitt44701df2015-02-23 14:44:57 -0800281 fClipStack.reset(SkRef(canvas->getClipStack()));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000282}
283
284void SkGpuDevice::onDetachFromCanvas() {
285 INHERITED::onDetachFromCanvas();
joshualitt570d2f82015-02-25 13:19:48 -0800286 fClip.reset();
joshualitt44701df2015-02-23 14:44:57 -0800287 fClipStack.reset(NULL);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000288}
289
290// call this every draw call, to ensure that the context reflects our state,
291// and not the state from some other canvas/device
joshualitt5531d512014-12-17 15:50:11 -0800292void SkGpuDevice::prepareDraw(const SkDraw& draw) {
joshualitt44701df2015-02-23 14:44:57 -0800293 SkASSERT(fClipStack.get());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000294
joshualitt44701df2015-02-23 14:44:57 -0800295 SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000296
joshualitt570d2f82015-02-25 13:19:48 -0800297 fClip.setClipStack(fClipStack, &this->getOrigin());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000298
299 DO_DEFERRED_CLEAR();
300}
301
302GrRenderTarget* SkGpuDevice::accessRenderTarget() {
303 DO_DEFERRED_CLEAR();
304 return fRenderTarget;
305}
306
reed8eddfb52014-12-04 07:50:14 -0800307void SkGpuDevice::clearAll() {
308 GrColor color = 0;
309 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::clearAll", fContext);
310 SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
311 fContext->clear(&rect, color, true, fRenderTarget);
bsalomonafe30052015-01-16 07:32:33 -0800312 fNeedClear = false;
reed8eddfb52014-12-04 07:50:14 -0800313}
314
kkinnunenabcfab42015-02-22 22:53:44 -0800315void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) {
316 // Caller must have accessed the render target, because it knows the rt must be replaced.
317 SkASSERT(!fNeedClear);
318
319 SkSurface::Budgeted budgeted =
320 fRenderTarget->resourcePriv().isBudgeted() ? SkSurface::kYes_Budgeted
321 : SkSurface::kNo_Budgeted;
322
323 SkAutoTUnref<GrRenderTarget> newRT(CreateRenderTarget(
324 fRenderTarget->getContext(), budgeted, this->imageInfo(), fRenderTarget->numSamples()));
325
326 if (NULL == newRT) {
327 return;
328 }
329
330 if (shouldRetainContent) {
331 if (fRenderTarget->wasDestroyed()) {
332 return;
333 }
334 this->context()->copySurface(newRT, fRenderTarget);
335 }
336
337 SkASSERT(fRenderTarget != newRT);
338
339 fRenderTarget->unref();
340 fRenderTarget = newRT.detach();
341
342 SkASSERT(fRenderTarget->surfacePriv().info() == fLegacyBitmap.info());
343 SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (fRenderTarget->surfacePriv().info(), fRenderTarget));
344 fLegacyBitmap.setPixelRef(pr)->unref();
345}
346
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000347///////////////////////////////////////////////////////////////////////////////
348
349SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
350SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
351SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
352SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
353SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
354 shader_type_mismatch);
355SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5,
356 shader_type_mismatch);
357SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch);
358SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch);
359
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000360///////////////////////////////////////////////////////////////////////////////
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000361
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000362void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
joshualitt5531d512014-12-17 15:50:11 -0800363 CHECK_SHOULD_DRAW(draw);
egdanield78a1682014-07-09 10:41:26 -0700364 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPaint", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000365
366 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -0700367 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint)) {
368 return;
369 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000370
joshualitt570d2f82015-02-25 13:19:48 -0800371 fContext->drawPaint(fRenderTarget, fClip, grPaint, *draw.fMatrix);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000372}
373
374// must be in SkCanvas::PointMode order
375static const GrPrimitiveType gPointMode2PrimtiveType[] = {
376 kPoints_GrPrimitiveType,
377 kLines_GrPrimitiveType,
378 kLineStrip_GrPrimitiveType
379};
380
381void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
382 size_t count, const SkPoint pts[], const SkPaint& paint) {
383 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800384 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000385
386 SkScalar width = paint.getStrokeWidth();
387 if (width < 0) {
388 return;
389 }
390
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000391 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
egdaniele61c4112014-06-12 10:24:21 -0700392 GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style);
393 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -0700394 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true,
395 &grPaint)) {
396 return;
397 }
egdaniele61c4112014-06-12 10:24:21 -0700398 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700399 path.setIsVolatile(true);
egdaniele61c4112014-06-12 10:24:21 -0700400 path.moveTo(pts[0]);
401 path.lineTo(pts[1]);
joshualitt570d2f82015-02-25 13:19:48 -0800402 fContext->drawPath(fRenderTarget, fClip, grPaint, *draw.fMatrix, path, strokeInfo);
egdaniele61c4112014-06-12 10:24:21 -0700403 return;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000404 }
405
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000406 // we only handle hairlines and paints without path effects or mask filters,
407 // else we let the SkDraw call our drawPath()
408 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) {
409 draw.drawPoints(mode, count, pts, paint, true);
410 return;
411 }
412
413 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -0700414 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint)) {
415 return;
416 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000417
joshualitt25d9c152015-02-18 12:29:52 -0800418 fContext->drawVertices(fRenderTarget,
joshualitt570d2f82015-02-25 13:19:48 -0800419 fClip,
joshualitt25d9c152015-02-18 12:29:52 -0800420 grPaint,
joshualitt5531d512014-12-17 15:50:11 -0800421 *draw.fMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000422 gPointMode2PrimtiveType[mode],
robertphillips@google.coma4662862013-11-21 14:24:16 +0000423 SkToS32(count),
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000424 (SkPoint*)pts,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000425 NULL,
426 NULL,
427 NULL,
428 0);
429}
430
431///////////////////////////////////////////////////////////////////////////////
432
433void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
434 const SkPaint& paint) {
egdanielbbcb38d2014-06-19 10:19:29 -0700435 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRect", fContext);
436
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000437 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800438 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000439
440 bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
441 SkScalar width = paint.getStrokeWidth();
442
443 /*
444 We have special code for hairline strokes, miter-strokes, bevel-stroke
445 and fills. Anything else we just call our path code.
446 */
447 bool usePath = doStroke && width > 0 &&
448 (paint.getStrokeJoin() == SkPaint::kRound_Join ||
449 (paint.getStrokeJoin() == SkPaint::kBevel_Join && rect.isEmpty()));
450 // another two reasons we might need to call drawPath...
egdanield58a0ba2014-06-11 10:30:05 -0700451
452 if (paint.getMaskFilter()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000453 usePath = true;
454 }
egdanield58a0ba2014-06-11 10:30:05 -0700455
joshualitt5531d512014-12-17 15:50:11 -0800456 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000457#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
458 if (doStroke) {
459#endif
460 usePath = true;
461#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
462 } else {
joshualitt5531d512014-12-17 15:50:11 -0800463 usePath = !draw.fMatrix->preservesRightAngles();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000464 }
465#endif
466 }
467 // until we can both stroke and fill rectangles
468 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
469 usePath = true;
470 }
471
egdanield58a0ba2014-06-11 10:30:05 -0700472 GrStrokeInfo strokeInfo(paint);
473
474 const SkPathEffect* pe = paint.getPathEffect();
bsalomon49f085d2014-09-05 13:34:00 -0700475 if (!usePath && pe && !strokeInfo.isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700476 usePath = true;
477 }
478
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000479 if (usePath) {
480 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700481 path.setIsVolatile(true);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000482 path.addRect(rect);
483 this->drawPath(draw, path, paint, NULL, true);
484 return;
485 }
486
487 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -0700488 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint)) {
489 return;
490 }
Mike Klein744fb732014-06-23 15:13:26 -0400491
joshualitt570d2f82015-02-25 13:19:48 -0800492 fContext->drawRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, rect, &strokeInfo);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000493}
494
495///////////////////////////////////////////////////////////////////////////////
496
497void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect,
joshualitt5531d512014-12-17 15:50:11 -0800498 const SkPaint& paint) {
egdanield78a1682014-07-09 10:41:26 -0700499 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRRect", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000500 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800501 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000502
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000503 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -0700504 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint)) {
505 return;
506 }
Mike Klein744fb732014-06-23 15:13:26 -0400507
egdanield58a0ba2014-06-11 10:30:05 -0700508 GrStrokeInfo strokeInfo(paint);
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000509 if (paint.getMaskFilter()) {
510 // try to hit the fast path for drawing filtered round rects
511
512 SkRRect devRRect;
joshualitt5531d512014-12-17 15:50:11 -0800513 if (rect.transform(*draw.fMatrix, &devRRect)) {
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000514 if (devRRect.allCornersCircular()) {
515 SkRect maskRect;
516 if (paint.getMaskFilter()->canFilterMaskGPU(devRRect.rect(),
joshualitt5531d512014-12-17 15:50:11 -0800517 draw.fClip->getBounds(),
518 *draw.fMatrix,
519 &maskRect)) {
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000520 SkIRect finalIRect;
521 maskRect.roundOut(&finalIRect);
522 if (draw.fClip->quickReject(finalIRect)) {
523 // clipped out
524 return;
525 }
joshualitt25d9c152015-02-18 12:29:52 -0800526 if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext,
527 fRenderTarget,
528 &grPaint,
joshualitt570d2f82015-02-25 13:19:48 -0800529 fClip,
joshualitt5531d512014-12-17 15:50:11 -0800530 *draw.fMatrix,
egdanield58a0ba2014-06-11 10:30:05 -0700531 strokeInfo.getStrokeRec(),
532 devRRect)) {
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000533 return;
534 }
535 }
536
537 }
538 }
539
540 }
541
egdanield58a0ba2014-06-11 10:30:05 -0700542 bool usePath = false;
543
544 if (paint.getMaskFilter()) {
545 usePath = true;
546 } else {
547 const SkPathEffect* pe = paint.getPathEffect();
bsalomon49f085d2014-09-05 13:34:00 -0700548 if (pe && !strokeInfo.isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700549 usePath = true;
550 }
551 }
552
553
554 if (usePath) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000555 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700556 path.setIsVolatile(true);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000557 path.addRRect(rect);
558 this->drawPath(draw, path, paint, NULL, true);
559 return;
560 }
Mike Klein744fb732014-06-23 15:13:26 -0400561
joshualitt570d2f82015-02-25 13:19:48 -0800562 fContext->drawRRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, rect, strokeInfo);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000563}
564
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000565void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
joshualitt5531d512014-12-17 15:50:11 -0800566 const SkRRect& inner, const SkPaint& paint) {
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000567 SkStrokeRec stroke(paint);
568 if (stroke.isFillStyle()) {
569
570 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800571 CHECK_SHOULD_DRAW(draw);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000572
573 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -0700574 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true,
575 &grPaint)) {
576 return;
577 }
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000578
579 if (NULL == paint.getMaskFilter() && NULL == paint.getPathEffect()) {
joshualitt570d2f82015-02-25 13:19:48 -0800580 fContext->drawDRRect(fRenderTarget, fClip, grPaint, *draw.fMatrix, outer, inner);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000581 return;
582 }
583 }
584
585 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700586 path.setIsVolatile(true);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000587 path.addRRect(outer);
588 path.addRRect(inner);
589 path.setFillType(SkPath::kEvenOdd_FillType);
590
591 this->drawPath(draw, path, paint, NULL, true);
592}
593
594
commit-bot@chromium.org82139702014-03-10 22:53:20 +0000595/////////////////////////////////////////////////////////////////////////////
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000596
597void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval,
598 const SkPaint& paint) {
egdanield78a1682014-07-09 10:41:26 -0700599 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawOval", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000600 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800601 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000602
egdanield58a0ba2014-06-11 10:30:05 -0700603 GrStrokeInfo strokeInfo(paint);
604
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000605 bool usePath = false;
606 // some basic reasons we might need to call drawPath...
egdanield58a0ba2014-06-11 10:30:05 -0700607 if (paint.getMaskFilter()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000608 usePath = true;
egdanield58a0ba2014-06-11 10:30:05 -0700609 } else {
610 const SkPathEffect* pe = paint.getPathEffect();
bsalomon49f085d2014-09-05 13:34:00 -0700611 if (pe && !strokeInfo.isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700612 usePath = true;
613 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000614 }
615
616 if (usePath) {
617 SkPath path;
jvanverthb3eb6872014-10-24 07:12:51 -0700618 path.setIsVolatile(true);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000619 path.addOval(oval);
620 this->drawPath(draw, path, paint, NULL, true);
621 return;
622 }
623
624 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -0700625 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint)) {
626 return;
627 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000628
joshualitt570d2f82015-02-25 13:19:48 -0800629 fContext->drawOval(fRenderTarget, fClip, grPaint, *draw.fMatrix, oval, strokeInfo);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000630}
631
632#include "SkMaskFilter.h"
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000633
634///////////////////////////////////////////////////////////////////////////////
635
636// helpers for applying mask filters
637namespace {
638
639// Draw a mask using the supplied paint. Since the coverage/geometry
640// is already burnt into the mask this boils down to a rect draw.
641// Return true if the mask was successfully drawn.
joshualitt25d9c152015-02-18 12:29:52 -0800642bool draw_mask(GrContext* context,
643 GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800644 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800645 const SkMatrix& viewMatrix,
646 const SkRect& maskRect,
647 GrPaint* grp,
648 GrTexture* mask) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000649 SkMatrix matrix;
650 matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
651 matrix.postIDiv(mask->width(), mask->height());
652
joshualitt16b27892014-12-18 07:47:16 -0800653 grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix,
654 kDevice_GrCoordSet))->unref();
655
656 SkMatrix inverse;
657 if (!viewMatrix.invert(&inverse)) {
658 return false;
659 }
joshualitt570d2f82015-02-25 13:19:48 -0800660 context->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), maskRect, inverse);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000661 return true;
662}
663
joshualitt5efb8b82015-03-18 11:49:12 -0700664static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) {
665 return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect);
666}
667
joshualitt25d9c152015-02-18 12:29:52 -0800668bool draw_with_mask_filter(GrContext* context,
669 GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800670 const GrClip& clipData,
joshualitt25d9c152015-02-18 12:29:52 -0800671 const SkMatrix& viewMatrix,
672 const SkPath& devPath,
673 SkMaskFilter* filter,
joshualitt5efb8b82015-03-18 11:49:12 -0700674 const SkIRect& clipBounds,
joshualitt25d9c152015-02-18 12:29:52 -0800675 GrPaint* grp,
676 SkPaint::Style style) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000677 SkMask srcM, dstM;
678
joshualitt5efb8b82015-03-18 11:49:12 -0700679 if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000680 SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
681 return false;
682 }
683 SkAutoMaskFreeImage autoSrc(srcM.fImage);
684
joshualitt5531d512014-12-17 15:50:11 -0800685 if (!filter->filterMask(&dstM, srcM, viewMatrix, NULL)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000686 return false;
687 }
688 // this will free-up dstM when we're done (allocated in filterMask())
689 SkAutoMaskFreeImage autoDst(dstM.fImage);
690
joshualitt5efb8b82015-03-18 11:49:12 -0700691 if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000692 return false;
693 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000694
695 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
696 // the current clip (and identity matrix) and GrPaint settings
bsalomonf2703d82014-10-28 14:33:06 -0700697 GrSurfaceDesc desc;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000698 desc.fWidth = dstM.fBounds.width();
699 desc.fHeight = dstM.fBounds.height();
700 desc.fConfig = kAlpha_8_GrPixelConfig;
701
bsalomone3059732014-10-14 11:47:22 -0700702 SkAutoTUnref<GrTexture> texture(
703 context->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
704 if (!texture) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000705 return false;
706 }
707 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
708 dstM.fImage, dstM.fRowBytes);
709
710 SkRect maskRect = SkRect::Make(dstM.fBounds);
711
joshualitt570d2f82015-02-25 13:19:48 -0800712 return draw_mask(context, rt, clipData, viewMatrix, maskRect, grp, texture);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000713}
714
bsalomone3059732014-10-14 11:47:22 -0700715// Create a mask of 'devPath' and place the result in 'mask'.
716GrTexture* create_mask_GPU(GrContext* context,
joshualitt25d9c152015-02-18 12:29:52 -0800717 GrRenderTarget* rt,
bsalomone3059732014-10-14 11:47:22 -0700718 const SkRect& maskRect,
719 const SkPath& devPath,
720 const GrStrokeInfo& strokeInfo,
721 bool doAA,
722 int sampleCnt) {
bsalomonf2703d82014-10-28 14:33:06 -0700723 GrSurfaceDesc desc;
724 desc.fFlags = kRenderTarget_GrSurfaceFlag;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000725 desc.fWidth = SkScalarCeilToInt(maskRect.width());
726 desc.fHeight = SkScalarCeilToInt(maskRect.height());
bsalomone3059732014-10-14 11:47:22 -0700727 desc.fSampleCnt = doAA ? sampleCnt : 0;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000728 // We actually only need A8, but it often isn't supported as a
729 // render target so default to RGBA_8888
730 desc.fConfig = kRGBA_8888_GrPixelConfig;
derekff4555aa2014-10-06 12:19:12 -0700731
732 if (context->isConfigRenderable(kAlpha_8_GrPixelConfig,
733 desc.fSampleCnt > 0)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000734 desc.fConfig = kAlpha_8_GrPixelConfig;
735 }
736
bsalomone3059732014-10-14 11:47:22 -0700737 GrTexture* mask = context->refScratchTexture(desc,GrContext::kApprox_ScratchTexMatch);
738 if (NULL == mask) {
739 return NULL;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000740 }
741
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000742 SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
743
bsalomon89c62982014-11-03 12:08:42 -0800744 context->clear(NULL, 0x0, true, mask->asRenderTarget());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000745
746 GrPaint tempPaint;
egdanielb197b8f2015-02-17 07:34:43 -0800747 tempPaint.setAntiAlias(doAA);
748 tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000749
joshualitt570d2f82015-02-25 13:19:48 -0800750 // setup new clip
751 GrClip clip(clipRect);
752
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000753 // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
754 SkMatrix translate;
755 translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
joshualitt570d2f82015-02-25 13:19:48 -0800756 context->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo);
bsalomone3059732014-10-14 11:47:22 -0700757 return mask;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000758}
759
senorblancod0d37ca2015-04-02 04:54:56 -0700760SkBitmap wrap_texture(GrTexture* texture, int width, int height) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000761 SkBitmap result;
senorblancod0d37ca2015-04-02 04:54:56 -0700762 result.setInfo(SkImageInfo::MakeN32Premul(width, height));
reed6c225732014-06-09 19:52:07 -0700763 result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unref();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000764 return result;
765}
766
767};
768
769void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
770 const SkPaint& paint, const SkMatrix* prePathMatrix,
771 bool pathIsMutable) {
772 CHECK_FOR_ANNOTATION(paint);
joshualitt5531d512014-12-17 15:50:11 -0800773 CHECK_SHOULD_DRAW(draw);
egdanield78a1682014-07-09 10:41:26 -0700774 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPath", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000775
joshualitt5efb8b82015-03-18 11:49:12 -0700776 return this->internalDrawPath(origSrcPath, paint, *draw.fMatrix, prePathMatrix,
777 draw.fClip->getBounds(), pathIsMutable);
778}
779
780void SkGpuDevice::internalDrawPath(const SkPath& origSrcPath, const SkPaint& paint,
781 const SkMatrix& origViewMatrix, const SkMatrix* prePathMatrix,
782 const SkIRect& clipBounds, bool pathIsMutable) {
jvanverthb3eb6872014-10-24 07:12:51 -0700783 SkASSERT(!pathIsMutable || origSrcPath.isVolatile());
joshualitt5531d512014-12-17 15:50:11 -0800784
bsalomon54443932015-01-29 09:34:18 -0800785 GrStrokeInfo strokeInfo(paint);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000786
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000787 // If we have a prematrix, apply it to the path, optimizing for the case
788 // where the original path can in fact be modified in place (even though
789 // its parameter type is const).
790 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +0000791 SkTLazy<SkPath> tmpPath;
792 SkTLazy<SkPath> effectPath;
bsalomon54443932015-01-29 09:34:18 -0800793 SkPathEffect* pathEffect = paint.getPathEffect();
794
joshualitt5efb8b82015-03-18 11:49:12 -0700795 SkMatrix viewMatrix = origViewMatrix;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000796
797 if (prePathMatrix) {
bsalomon54443932015-01-29 09:34:18 -0800798 // stroking and path effects are supposed to be applied *after* the prePathMatrix.
799 // The pre-path-matrix also should not affect shadeing.
800 if (NULL == pathEffect && NULL == paint.getShader() &&
801 (strokeInfo.getStrokeRec().isFillStyle() ||
802 strokeInfo.getStrokeRec().isHairlineStyle())) {
803 viewMatrix.preConcat(*prePathMatrix);
804 } else {
805 SkPath* result = pathPtr;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000806
bsalomon54443932015-01-29 09:34:18 -0800807 if (!pathIsMutable) {
808 result = tmpPath.init();
809 result->setIsVolatile(true);
810 pathIsMutable = true;
811 }
812 // should I push prePathMatrix on our MV stack temporarily, instead
813 // of applying it here? See SkDraw.cpp
814 pathPtr->transform(*prePathMatrix, result);
815 pathPtr = result;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000816 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000817 }
818 // at this point we're done with prePathMatrix
819 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
820
bsalomon54443932015-01-29 09:34:18 -0800821 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -0700822 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, viewMatrix, true, &grPaint)) {
823 return;
824 }
bsalomon54443932015-01-29 09:34:18 -0800825
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000826 const SkRect* cullRect = NULL; // TODO: what is our bounds?
egdanield58a0ba2014-06-11 10:30:05 -0700827 SkStrokeRec* strokePtr = strokeInfo.getStrokeRecPtr();
828 if (pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr, strokePtr,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000829 cullRect)) {
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +0000830 pathPtr = effectPath.get();
831 pathIsMutable = true;
egdanield58a0ba2014-06-11 10:30:05 -0700832 strokeInfo.removeDash();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000833 }
834
egdanield58a0ba2014-06-11 10:30:05 -0700835 const SkStrokeRec& stroke = strokeInfo.getStrokeRec();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000836 if (paint.getMaskFilter()) {
837 if (!stroke.isHairlineStyle()) {
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +0000838 SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
839 if (stroke.applyToPath(strokedPath, *pathPtr)) {
840 pathPtr = strokedPath;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000841 pathIsMutable = true;
egdanield58a0ba2014-06-11 10:30:05 -0700842 strokeInfo.setFillStyle();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000843 }
844 }
845
846 // avoid possibly allocating a new path in transform if we can
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +0000847 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init();
jvanverthb3eb6872014-10-24 07:12:51 -0700848 if (!pathIsMutable) {
849 devPathPtr->setIsVolatile(true);
850 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000851
852 // transform the path into device space
bsalomon54443932015-01-29 09:34:18 -0800853 pathPtr->transform(viewMatrix, devPathPtr);
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000854
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000855 SkRect maskRect;
856 if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(),
joshualitt5efb8b82015-03-18 11:49:12 -0700857 clipBounds,
bsalomon54443932015-01-29 09:34:18 -0800858 viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000859 &maskRect)) {
860 SkIRect finalIRect;
861 maskRect.roundOut(&finalIRect);
joshualitt5efb8b82015-03-18 11:49:12 -0700862 if (clip_bounds_quick_reject(clipBounds, finalIRect)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000863 // clipped out
864 return;
865 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000866
joshualitt25d9c152015-02-18 12:29:52 -0800867 if (paint.getMaskFilter()->directFilterMaskGPU(fContext,
868 fRenderTarget,
869 &grPaint,
joshualitt570d2f82015-02-25 13:19:48 -0800870 fClip,
joshualitt25d9c152015-02-18 12:29:52 -0800871 viewMatrix,
872 stroke,
873 *devPathPtr)) {
commit-bot@chromium.orgcf34bc02014-01-30 15:34:43 +0000874 // the mask filter was able to draw itself directly, so there's nothing
875 // left to do.
876 return;
877 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000878
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000879
joshualitt25d9c152015-02-18 12:29:52 -0800880 SkAutoTUnref<GrTexture> mask(create_mask_GPU(fContext,
881 fRenderTarget,
882 maskRect,
883 *devPathPtr,
884 strokeInfo,
885 grPaint.isAntiAlias(),
bsalomone3059732014-10-14 11:47:22 -0700886 fRenderTarget->numSamples()));
887 if (mask) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000888 GrTexture* filtered;
889
bsalomon54443932015-01-29 09:34:18 -0800890 if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskRect, &filtered, true)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000891 // filterMaskGPU gives us ownership of a ref to the result
892 SkAutoTUnref<GrTexture> atu(filtered);
joshualitt570d2f82015-02-25 13:19:48 -0800893 if (draw_mask(fContext,
894 fRenderTarget,
895 fClip,
896 viewMatrix,
897 maskRect,
898 &grPaint,
joshualitt25d9c152015-02-18 12:29:52 -0800899 filtered)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000900 // This path is completely drawn
901 return;
902 }
903 }
904 }
905 }
906
907 // draw the mask on the CPU - this is a fallthrough path in case the
908 // GPU path fails
909 SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style :
910 SkPaint::kFill_Style;
joshualitt570d2f82015-02-25 13:19:48 -0800911 draw_with_mask_filter(fContext, fRenderTarget, fClip, viewMatrix, *devPathPtr,
joshualitt5efb8b82015-03-18 11:49:12 -0700912 paint.getMaskFilter(), clipBounds, &grPaint, style);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000913 return;
914 }
915
joshualitt570d2f82015-02-25 13:19:48 -0800916 fContext->drawPath(fRenderTarget, fClip, grPaint, viewMatrix, *pathPtr, strokeInfo);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000917}
918
919static const int kBmpSmallTileSize = 1 << 10;
920
921static inline int get_tile_count(const SkIRect& srcRect, int tileSize) {
922 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
923 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
924 return tilesX * tilesY;
925}
926
927static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int maxTileSize) {
928 if (maxTileSize <= kBmpSmallTileSize) {
929 return maxTileSize;
930 }
931
932 size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
933 size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
934
935 maxTileTotalTileSize *= maxTileSize * maxTileSize;
936 smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
937
938 if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
939 return kBmpSmallTileSize;
940 } else {
941 return maxTileSize;
942 }
943}
944
945// Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
946// pixels from the bitmap are necessary.
947static void determine_clipped_src_rect(const GrContext* context,
joshualitt25d9c152015-02-18 12:29:52 -0800948 const GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800949 const GrClip& clip,
joshualitt5531d512014-12-17 15:50:11 -0800950 const SkMatrix& viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000951 const SkBitmap& bitmap,
952 const SkRect* srcRectPtr,
953 SkIRect* clippedSrcIRect) {
joshualitt570d2f82015-02-25 13:19:48 -0800954 clip.getConservativeBounds(rt, clippedSrcIRect, NULL);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000955 SkMatrix inv;
joshualitt5531d512014-12-17 15:50:11 -0800956 if (!viewMatrix.invert(&inv)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000957 clippedSrcIRect->setEmpty();
958 return;
959 }
960 SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect);
961 inv.mapRect(&clippedSrcRect);
bsalomon49f085d2014-09-05 13:34:00 -0700962 if (srcRectPtr) {
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +0000963 // we've setup src space 0,0 to map to the top left of the src rect.
964 clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000965 if (!clippedSrcRect.intersect(*srcRectPtr)) {
966 clippedSrcIRect->setEmpty();
967 return;
968 }
969 }
970 clippedSrcRect.roundOut(clippedSrcIRect);
971 SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
972 if (!clippedSrcIRect->intersect(bmpBounds)) {
973 clippedSrcIRect->setEmpty();
974 }
975}
976
977bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
joshualitt5531d512014-12-17 15:50:11 -0800978 const SkMatrix& viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000979 const GrTextureParams& params,
980 const SkRect* srcRectPtr,
981 int maxTileSize,
982 int* tileSize,
983 SkIRect* clippedSrcRect) const {
984 // if bitmap is explictly texture backed then just use the texture
bsalomon49f085d2014-09-05 13:34:00 -0700985 if (bitmap.getTexture()) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000986 return false;
987 }
988
989 // if it's larger than the max tile size, then we have no choice but tiling.
990 if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) {
joshualitt570d2f82015-02-25 13:19:48 -0800991 determine_clipped_src_rect(fContext, fRenderTarget, fClip, viewMatrix, bitmap,
992 srcRectPtr, clippedSrcRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000993 *tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize);
994 return true;
995 }
996
997 if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
998 return false;
999 }
1000
1001 // if the entire texture is already in our cache then no reason to tile it
1002 if (GrIsBitmapInCache(fContext, bitmap, &params)) {
1003 return false;
1004 }
1005
1006 // At this point we know we could do the draw by uploading the entire bitmap
1007 // as a texture. However, if the texture would be large compared to the
1008 // cache size and we don't require most of it for this draw then tile to
1009 // reduce the amount of upload and cache spill.
1010
1011 // assumption here is that sw bitmap size is a good proxy for its size as
1012 // a texture
1013 size_t bmpSize = bitmap.getSize();
1014 size_t cacheSize;
commit-bot@chromium.org95c20032014-05-09 14:29:32 +00001015 fContext->getResourceCacheLimits(NULL, &cacheSize);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001016 if (bmpSize < cacheSize / 2) {
1017 return false;
1018 }
1019
1020 // Figure out how much of the src we will need based on the src rect and clipping.
joshualitt570d2f82015-02-25 13:19:48 -08001021 determine_clipped_src_rect(fContext, fRenderTarget, fClip, viewMatrix, bitmap, srcRectPtr,
joshualitt25d9c152015-02-18 12:29:52 -08001022 clippedSrcRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001023 *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
1024 size_t usedTileBytes = get_tile_count(*clippedSrcRect, kBmpSmallTileSize) *
1025 kBmpSmallTileSize * kBmpSmallTileSize;
1026
1027 return usedTileBytes < 2 * bmpSize;
1028}
1029
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001030void SkGpuDevice::drawBitmap(const SkDraw& origDraw,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001031 const SkBitmap& bitmap,
1032 const SkMatrix& m,
1033 const SkPaint& paint) {
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001034 SkMatrix concat;
1035 SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
1036 if (!m.isIdentity()) {
1037 concat.setConcat(*draw->fMatrix, m);
1038 draw.writable()->fMatrix = &concat;
1039 }
1040 this->drawBitmapCommon(*draw, bitmap, NULL, NULL, paint, SkCanvas::kNone_DrawBitmapRectFlag);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001041}
1042
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001043// This method outsets 'iRect' by 'outset' all around and then clamps its extents to
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001044// 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
1045// of 'iRect' for all possible outsets/clamps.
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001046static inline void clamped_outset_with_offset(SkIRect* iRect,
1047 int outset,
1048 SkPoint* offset,
1049 const SkIRect& clamp) {
1050 iRect->outset(outset, outset);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001051
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001052 int leftClampDelta = clamp.fLeft - iRect->fLeft;
1053 if (leftClampDelta > 0) {
1054 offset->fX -= outset - leftClampDelta;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001055 iRect->fLeft = clamp.fLeft;
1056 } else {
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001057 offset->fX -= outset;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001058 }
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001059
1060 int topClampDelta = clamp.fTop - iRect->fTop;
1061 if (topClampDelta > 0) {
1062 offset->fY -= outset - topClampDelta;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001063 iRect->fTop = clamp.fTop;
1064 } else {
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001065 offset->fY -= outset;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001066 }
1067
1068 if (iRect->fRight > clamp.fRight) {
1069 iRect->fRight = clamp.fRight;
1070 }
1071 if (iRect->fBottom > clamp.fBottom) {
1072 iRect->fBottom = clamp.fBottom;
1073 }
1074}
1075
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001076static bool has_aligned_samples(const SkRect& srcRect,
1077 const SkRect& transformedRect) {
1078 // detect pixel disalignment
1079 if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) -
1080 transformedRect.left()) < COLOR_BLEED_TOLERANCE &&
1081 SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) -
1082 transformedRect.top()) < COLOR_BLEED_TOLERANCE &&
1083 SkScalarAbs(transformedRect.width() - srcRect.width()) <
1084 COLOR_BLEED_TOLERANCE &&
1085 SkScalarAbs(transformedRect.height() - srcRect.height()) <
1086 COLOR_BLEED_TOLERANCE) {
1087 return true;
1088 }
1089 return false;
1090}
1091
1092static bool may_color_bleed(const SkRect& srcRect,
1093 const SkRect& transformedRect,
1094 const SkMatrix& m) {
1095 // Only gets called if has_aligned_samples returned false.
1096 // So we can assume that sampling is axis aligned but not texel aligned.
1097 SkASSERT(!has_aligned_samples(srcRect, transformedRect));
1098 SkRect innerSrcRect(srcRect), innerTransformedRect,
1099 outerTransformedRect(transformedRect);
1100 innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
1101 m.mapRect(&innerTransformedRect, innerSrcRect);
1102
1103 // The gap between outerTransformedRect and innerTransformedRect
1104 // represents the projection of the source border area, which is
1105 // problematic for color bleeding. We must check whether any
1106 // destination pixels sample the border area.
1107 outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
1108 innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE);
1109 SkIRect outer, inner;
1110 outerTransformedRect.round(&outer);
1111 innerTransformedRect.round(&inner);
1112 // If the inner and outer rects round to the same result, it means the
1113 // border does not overlap any pixel centers. Yay!
1114 return inner != outer;
1115}
1116
1117static bool needs_texture_domain(const SkBitmap& bitmap,
1118 const SkRect& srcRect,
1119 GrTextureParams &params,
1120 const SkMatrix& contextMatrix,
1121 bool bicubic) {
1122 bool needsTextureDomain = false;
senorblancod0d37ca2015-04-02 04:54:56 -07001123 GrTexture* tex = bitmap.getTexture();
1124 int width = tex ? tex->width() : bitmap.width();
1125 int height = tex ? tex->height() : bitmap.height();
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001126
1127 if (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode) {
1128 // Need texture domain if drawing a sub rect
senorblancod0d37ca2015-04-02 04:54:56 -07001129 needsTextureDomain = srcRect.width() < width ||
1130 srcRect.height() < height;
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001131 if (!bicubic && needsTextureDomain && contextMatrix.rectStaysRect()) {
1132 // sampling is axis-aligned
1133 SkRect transformedRect;
1134 contextMatrix.mapRect(&transformedRect, srcRect);
1135
1136 if (has_aligned_samples(srcRect, transformedRect)) {
1137 params.setFilterMode(GrTextureParams::kNone_FilterMode);
1138 needsTextureDomain = false;
1139 } else {
1140 needsTextureDomain = may_color_bleed(srcRect, transformedRect, contextMatrix);
1141 }
1142 }
1143 }
1144 return needsTextureDomain;
1145}
1146
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001147void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
1148 const SkBitmap& bitmap,
1149 const SkRect* srcRectPtr,
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001150 const SkSize* dstSizePtr,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001151 const SkPaint& paint,
1152 SkCanvas::DrawBitmapRectFlags flags) {
joshualitt5531d512014-12-17 15:50:11 -08001153 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001154
1155 SkRect srcRect;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001156 SkSize dstSize;
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001157 // If there is no src rect, or the src rect contains the entire bitmap then we're effectively
1158 // in the (easier) bleed case, so update flags.
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001159 if (NULL == srcRectPtr) {
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001160 SkScalar w = SkIntToScalar(bitmap.width());
1161 SkScalar h = SkIntToScalar(bitmap.height());
1162 dstSize.fWidth = w;
1163 dstSize.fHeight = h;
1164 srcRect.set(0, 0, w, h);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001165 } else {
bsalomon49f085d2014-09-05 13:34:00 -07001166 SkASSERT(dstSizePtr);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001167 srcRect = *srcRectPtr;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001168 dstSize = *dstSizePtr;
senorblancod0d37ca2015-04-02 04:54:56 -07001169 }
1170 GrTexture* tex = bitmap.getTexture();
1171 int width = tex ? tex->width() : bitmap.width();
1172 int height = tex ? tex->height() : bitmap.height();
1173 if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 &&
1174 srcRect.fRight >= width && srcRect.fBottom >= height) {
1175 flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001176 }
1177
derekf367e1862014-12-02 11:02:06 -08001178 // If the render target is not msaa and draw is antialiased, we call
1179 // drawRect instead of drawing on the render target directly.
1180 // FIXME: the tiled bitmap code path doesn't currently support
1181 // anti-aliased edges, we work around that for now by drawing directly
1182 // if the image size exceeds maximum texture size.
1183 int maxTextureSize = fContext->getMaxTextureSize();
1184 bool directDraw = fRenderTarget->isMultisampled() ||
1185 !paint.isAntiAlias() ||
1186 bitmap.width() > maxTextureSize ||
1187 bitmap.height() > maxTextureSize;
1188
1189 // we check whether dst rect are pixel aligned
1190 if (!directDraw) {
joshualitt5531d512014-12-17 15:50:11 -08001191 bool staysRect = draw.fMatrix->rectStaysRect();
derekf367e1862014-12-02 11:02:06 -08001192
1193 if (staysRect) {
1194 SkRect rect;
1195 SkRect dstRect = SkRect::MakeXYWH(0, 0, dstSize.fWidth, dstSize.fHeight);
joshualitt5531d512014-12-17 15:50:11 -08001196 draw.fMatrix->mapRect(&rect, dstRect);
derekf367e1862014-12-02 11:02:06 -08001197 const SkScalar *scalars = rect.asScalars();
1198 bool isDstPixelAligned = true;
1199 for (int i = 0; i < 4; i++) {
1200 if (!SkScalarIsInt(scalars[i])) {
1201 isDstPixelAligned = false;
1202 break;
1203 }
1204 }
1205
1206 if (isDstPixelAligned)
1207 directDraw = true;
1208 }
1209 }
1210
1211 if (paint.getMaskFilter() || !directDraw) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001212 // Convert the bitmap to a shader so that the rect can be drawn
1213 // through drawRect, which supports mask filters.
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001214 SkBitmap tmp; // subset of bitmap, if necessary
1215 const SkBitmap* bitmapPtr = &bitmap;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001216 SkMatrix localM;
bsalomon49f085d2014-09-05 13:34:00 -07001217 if (srcRectPtr) {
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001218 localM.setTranslate(-srcRectPtr->fLeft, -srcRectPtr->fTop);
1219 localM.postScale(dstSize.fWidth / srcRectPtr->width(),
1220 dstSize.fHeight / srcRectPtr->height());
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +00001221 // In bleed mode we position and trim the bitmap based on the src rect which is
1222 // already accounted for in 'm' and 'srcRect'. In clamp mode we need to chop out
1223 // the desired portion of the bitmap and then update 'm' and 'srcRect' to
1224 // compensate.
1225 if (!(SkCanvas::kBleed_DrawBitmapRectFlag & flags)) {
1226 SkIRect iSrc;
1227 srcRect.roundOut(&iSrc);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001228
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +00001229 SkPoint offset = SkPoint::Make(SkIntToScalar(iSrc.fLeft),
1230 SkIntToScalar(iSrc.fTop));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001231
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +00001232 if (!bitmap.extractSubset(&tmp, iSrc)) {
1233 return; // extraction failed
1234 }
1235 bitmapPtr = &tmp;
1236 srcRect.offset(-offset.fX, -offset.fY);
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001237
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +00001238 // The source rect has changed so update the matrix
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001239 localM.preTranslate(offset.fX, offset.fY);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001240 }
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001241 } else {
1242 localM.reset();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001243 }
1244
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001245 SkPaint paintWithShader(paint);
1246 paintWithShader.setShader(SkShader::CreateBitmapShader(*bitmapPtr,
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +00001247 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &localM))->unref();
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001248 SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight};
1249 this->drawRect(draw, dstRect, paintWithShader);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001250
1251 return;
1252 }
1253
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001254 // If there is no mask filter than it is OK to handle the src rect -> dst rect scaling using
1255 // the view matrix rather than a local matrix.
1256 SkMatrix m;
1257 m.setScale(dstSize.fWidth / srcRect.width(),
1258 dstSize.fHeight / srcRect.height());
joshualitt5531d512014-12-17 15:50:11 -08001259 SkMatrix viewM = *draw.fMatrix;
1260 viewM.preConcat(m);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001261
1262 GrTextureParams params;
reed93a12152015-03-16 10:08:34 -07001263 SkFilterQuality paintFilterQuality = paint.getFilterQuality();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001264 GrTextureParams::FilterMode textureFilterMode;
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001265
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001266 bool doBicubic = false;
1267
reed93a12152015-03-16 10:08:34 -07001268 switch(paintFilterQuality) {
1269 case kNone_SkFilterQuality:
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001270 textureFilterMode = GrTextureParams::kNone_FilterMode;
1271 break;
reed93a12152015-03-16 10:08:34 -07001272 case kLow_SkFilterQuality:
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001273 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
1274 break;
reed93a12152015-03-16 10:08:34 -07001275 case kMedium_SkFilterQuality:
joshualitt5531d512014-12-17 15:50:11 -08001276 if (viewM.getMinScale() < SK_Scalar1) {
commit-bot@chromium.org79b7eee2013-12-16 21:02:29 +00001277 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
1278 } else {
1279 // Don't trigger MIP level generation unnecessarily.
1280 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
1281 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001282 break;
reed93a12152015-03-16 10:08:34 -07001283 case kHigh_SkFilterQuality:
commit-bot@chromium.orgcea9abb2013-12-09 19:15:37 +00001284 // Minification can look bad with the bicubic effect.
commit-bot@chromium.org9927bd32014-05-20 17:51:13 +00001285 doBicubic =
joshualitt5531d512014-12-17 15:50:11 -08001286 GrBicubicEffect::ShouldUseBicubic(viewM, &textureFilterMode);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001287 break;
1288 default:
1289 SkErrorInternals::SetError( kInvalidPaint_SkError,
1290 "Sorry, I don't understand the filtering "
1291 "mode you asked for. Falling back to "
1292 "MIPMaps.");
1293 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
1294 break;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001295 }
1296
commit-bot@chromium.org9927bd32014-05-20 17:51:13 +00001297 int tileFilterPad;
1298 if (doBicubic) {
1299 tileFilterPad = GrBicubicEffect::kFilterTexelPad;
1300 } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) {
1301 tileFilterPad = 0;
1302 } else {
1303 tileFilterPad = 1;
1304 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001305 params.setFilterMode(textureFilterMode);
1306
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001307 int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001308 int tileSize;
1309
1310 SkIRect clippedSrcRect;
joshualitt5531d512014-12-17 15:50:11 -08001311 if (this->shouldTileBitmap(bitmap, viewM, params, srcRectPtr, maxTileSize, &tileSize,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001312 &clippedSrcRect)) {
joshualitt5531d512014-12-17 15:50:11 -08001313 this->drawTiledBitmap(bitmap, viewM, srcRect, clippedSrcRect, params, paint, flags,
1314 tileSize, doBicubic);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001315 } else {
1316 // take the simple case
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001317 bool needsTextureDomain = needs_texture_domain(bitmap,
1318 srcRect,
1319 params,
joshualitt5531d512014-12-17 15:50:11 -08001320 viewM,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001321 doBicubic);
1322 this->internalDrawBitmap(bitmap,
joshualitt5531d512014-12-17 15:50:11 -08001323 viewM,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001324 srcRect,
1325 params,
1326 paint,
1327 flags,
1328 doBicubic,
1329 needsTextureDomain);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001330 }
1331}
1332
1333// Break 'bitmap' into several tiles to draw it since it has already
1334// been determined to be too large to fit in VRAM
1335void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap,
joshualitt5531d512014-12-17 15:50:11 -08001336 const SkMatrix& viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001337 const SkRect& srcRect,
1338 const SkIRect& clippedSrcIRect,
1339 const GrTextureParams& params,
1340 const SkPaint& paint,
1341 SkCanvas::DrawBitmapRectFlags flags,
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001342 int tileSize,
1343 bool bicubic) {
commit-bot@chromium.org9d5e3f12014-05-01 21:23:19 +00001344 // The following pixel lock is technically redundant, but it is desirable
1345 // to lock outside of the tile loop to prevent redecoding the whole image
1346 // at each tile in cases where 'bitmap' holds an SkDiscardablePixelRef that
1347 // is larger than the limit of the discardable memory pool.
1348 SkAutoLockPixels alp(bitmap);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001349 SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
1350
1351 int nx = bitmap.width() / tileSize;
1352 int ny = bitmap.height() / tileSize;
1353 for (int x = 0; x <= nx; x++) {
1354 for (int y = 0; y <= ny; y++) {
1355 SkRect tileR;
1356 tileR.set(SkIntToScalar(x * tileSize),
1357 SkIntToScalar(y * tileSize),
1358 SkIntToScalar((x + 1) * tileSize),
1359 SkIntToScalar((y + 1) * tileSize));
1360
1361 if (!SkRect::Intersects(tileR, clippedSrcRect)) {
1362 continue;
1363 }
1364
1365 if (!tileR.intersect(srcRect)) {
1366 continue;
1367 }
1368
1369 SkBitmap tmpB;
1370 SkIRect iTileR;
1371 tileR.roundOut(&iTileR);
1372 SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
1373 SkIntToScalar(iTileR.fTop));
1374
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001375 // Adjust the context matrix to draw at the right x,y in device space
joshualitt5531d512014-12-17 15:50:11 -08001376 SkMatrix viewM = viewMatrix;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001377 SkMatrix tmpM;
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001378 tmpM.setTranslate(offset.fX - srcRect.fLeft, offset.fY - srcRect.fTop);
joshualitt5531d512014-12-17 15:50:11 -08001379 viewM.preConcat(tmpM);
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001380
robertphillipsec8bb942014-11-21 10:16:25 -08001381 if (GrTextureParams::kNone_FilterMode != params.filterMode() || bicubic) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001382 SkIRect iClampRect;
1383
1384 if (SkCanvas::kBleed_DrawBitmapRectFlag & flags) {
1385 // In bleed mode we want to always expand the tile on all edges
1386 // but stay within the bitmap bounds
1387 iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1388 } else {
1389 // In texture-domain/clamp mode we only want to expand the
1390 // tile on edges interior to "srcRect" (i.e., we want to
1391 // not bleed across the original clamped edges)
1392 srcRect.roundOut(&iClampRect);
1393 }
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001394 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1;
1395 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001396 }
1397
1398 if (bitmap.extractSubset(&tmpB, iTileR)) {
1399 // now offset it to make it "local" to our tmp bitmap
1400 tileR.offset(-offset.fX, -offset.fY);
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001401 GrTextureParams paramsTemp = params;
1402 bool needsTextureDomain = needs_texture_domain(bitmap,
1403 srcRect,
1404 paramsTemp,
joshualitt5531d512014-12-17 15:50:11 -08001405 viewM,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001406 bicubic);
1407 this->internalDrawBitmap(tmpB,
joshualitt5531d512014-12-17 15:50:11 -08001408 viewM,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001409 tileR,
1410 paramsTemp,
1411 paint,
1412 flags,
1413 bicubic,
1414 needsTextureDomain);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001415 }
1416 }
1417 }
1418}
1419
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001420
1421/*
1422 * This is called by drawBitmap(), which has to handle images that may be too
1423 * large to be represented by a single texture.
1424 *
1425 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1426 * and that non-texture portion of the GrPaint has already been setup.
1427 */
1428void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap,
joshualitt5531d512014-12-17 15:50:11 -08001429 const SkMatrix& viewMatrix,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001430 const SkRect& srcRect,
1431 const GrTextureParams& params,
1432 const SkPaint& paint,
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001433 SkCanvas::DrawBitmapRectFlags flags,
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001434 bool bicubic,
1435 bool needsTextureDomain) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001436 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1437 bitmap.height() <= fContext->getMaxTextureSize());
1438
1439 GrTexture* texture;
bsalomonbcf0a522014-10-08 08:40:09 -07001440 AutoBitmapTexture abt(fContext, bitmap, &params, &texture);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001441 if (NULL == texture) {
1442 return;
1443 }
1444
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001445 SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() };
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001446 SkRect paintRect;
1447 SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width()));
1448 SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height()));
1449 paintRect.setLTRB(SkScalarMul(srcRect.fLeft, wInv),
1450 SkScalarMul(srcRect.fTop, hInv),
1451 SkScalarMul(srcRect.fRight, wInv),
1452 SkScalarMul(srcRect.fBottom, hInv));
1453
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001454 SkRect textureDomain = SkRect::MakeEmpty();
joshualittb0a8a372014-09-23 09:50:21 -07001455 SkAutoTUnref<GrFragmentProcessor> fp;
commit-bot@chromium.orga17773f2014-05-09 13:53:38 +00001456 if (needsTextureDomain && !(flags & SkCanvas::kBleed_DrawBitmapRectFlag)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001457 // Use a constrained texture domain to avoid color bleeding
1458 SkScalar left, top, right, bottom;
1459 if (srcRect.width() > SK_Scalar1) {
1460 SkScalar border = SK_ScalarHalf / texture->width();
1461 left = paintRect.left() + border;
1462 right = paintRect.right() - border;
1463 } else {
1464 left = right = SkScalarHalf(paintRect.left() + paintRect.right());
1465 }
1466 if (srcRect.height() > SK_Scalar1) {
1467 SkScalar border = SK_ScalarHalf / texture->height();
1468 top = paintRect.top() + border;
1469 bottom = paintRect.bottom() - border;
1470 } else {
1471 top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom());
1472 }
1473 textureDomain.setLTRB(left, top, right, bottom);
commit-bot@chromium.org7d7f3142013-12-16 15:18:11 +00001474 if (bicubic) {
joshualittb0a8a372014-09-23 09:50:21 -07001475 fp.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), textureDomain));
commit-bot@chromium.org7d7f3142013-12-16 15:18:11 +00001476 } else {
joshualittb0a8a372014-09-23 09:50:21 -07001477 fp.reset(GrTextureDomainEffect::Create(texture,
joshualitt5531d512014-12-17 15:50:11 -08001478 SkMatrix::I(),
1479 textureDomain,
1480 GrTextureDomain::kClamp_Mode,
1481 params.filterMode()));
commit-bot@chromium.org7d7f3142013-12-16 15:18:11 +00001482 }
commit-bot@chromium.orgdec61502013-12-02 22:22:35 +00001483 } else if (bicubic) {
commit-bot@chromium.orgbc91fd72013-12-10 12:53:39 +00001484 SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode());
1485 SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
joshualittb0a8a372014-09-23 09:50:21 -07001486 fp.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), tileModes));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001487 } else {
joshualittb0a8a372014-09-23 09:50:21 -07001488 fp.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001489 }
1490
1491 // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring
1492 // the rest from the SkPaint.
1493 GrPaint grPaint;
joshualittb0a8a372014-09-23 09:50:21 -07001494 grPaint.addColorProcessor(fp);
reed0689d7b2014-06-14 05:30:20 -07001495 bool alphaOnly = !(kAlpha_8_SkColorType == bitmap.colorType());
bsalomon83d081a2014-07-08 09:56:10 -07001496 GrColor paintColor = (alphaOnly) ? SkColor2GrColorJustAlpha(paint.getColor()) :
1497 SkColor2GrColor(paint.getColor());
bsalomonbed83a62015-04-15 14:18:34 -07001498 if (!SkPaint2GrPaintNoShader(this->context(), fRenderTarget, paint, paintColor, false,
1499 &grPaint)) {
1500 return;
1501 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001502
joshualitt570d2f82015-02-25 13:19:48 -08001503 fContext->drawNonAARectToRect(fRenderTarget, fClip, grPaint, viewMatrix, dstRect,
1504 paintRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001505}
1506
fmalita2d97bc12014-11-20 10:44:58 -08001507bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture,
senorblancod0d37ca2015-04-02 04:54:56 -07001508 int width, int height,
fmalita2d97bc12014-11-20 10:44:58 -08001509 const SkImageFilter* filter,
1510 const SkImageFilter::Context& ctx,
1511 SkBitmap* result, SkIPoint* offset) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001512 SkASSERT(filter);
fmalita2d97bc12014-11-20 10:44:58 -08001513
1514 // FIXME: plumb actual surface props such that we don't have to lie about the flags here
1515 // (https://code.google.com/p/skia/issues/detail?id=3148).
1516 SkDeviceImageFilterProxy proxy(this, SkSurfaceProps(0, getLeakyProperties().pixelGeometry()));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001517
1518 if (filter->canFilterImageGPU()) {
senorblancod0d37ca2015-04-02 04:54:56 -07001519 return filter->filterImageGPU(&proxy, wrap_texture(texture, width, height),
1520 ctx, result, offset);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001521 } else {
1522 return false;
1523 }
1524}
1525
1526void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1527 int left, int top, const SkPaint& paint) {
1528 // drawSprite is defined to be in device coords.
joshualitt5531d512014-12-17 15:50:11 -08001529 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001530
1531 SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
1532 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1533 return;
1534 }
1535
1536 int w = bitmap.width();
1537 int h = bitmap.height();
1538
1539 GrTexture* texture;
1540 // draw sprite uses the default texture params
bsalomonbcf0a522014-10-08 08:40:09 -07001541 AutoBitmapTexture abt(fContext, bitmap, NULL, &texture);
joshualitt5f5a8d72015-02-25 14:09:45 -08001542 if (!texture) {
1543 return;
1544 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001545
1546 SkImageFilter* filter = paint.getImageFilter();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001547 // This bitmap will own the filtered result as a texture.
1548 SkBitmap filteredBitmap;
1549
bsalomon49f085d2014-09-05 13:34:00 -07001550 if (filter) {
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001551 SkIPoint offset = SkIPoint::Make(0, 0);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001552 SkMatrix matrix(*draw.fMatrix);
1553 matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001554 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height());
senorblancobe129b22014-08-08 07:14:35 -07001555 SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
senorblanco55b6d8b2014-07-30 11:26:46 -07001556 // This cache is transient, and is freed (along with all its contained
1557 // textures) when it goes out of scope.
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +00001558 SkImageFilter::Context ctx(matrix, clipBounds, cache);
senorblancod0d37ca2015-04-02 04:54:56 -07001559 if (this->filterTexture(fContext, texture, w, h, filter, ctx, &filteredBitmap,
fmalita2d97bc12014-11-20 10:44:58 -08001560 &offset)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001561 texture = (GrTexture*) filteredBitmap.getTexture();
1562 w = filteredBitmap.width();
1563 h = filteredBitmap.height();
senorblanco@chromium.org6776b822014-01-03 21:48:22 +00001564 left += offset.x();
1565 top += offset.y();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001566 } else {
1567 return;
1568 }
1569 }
1570
1571 GrPaint grPaint;
joshualittb0a8a372014-09-23 09:50:21 -07001572 grPaint.addColorTextureProcessor(texture, SkMatrix::I());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001573
bsalomonbed83a62015-04-15 14:18:34 -07001574 if (!SkPaint2GrPaintNoShader(this->context(), fRenderTarget, paint,
1575 SkColor2GrColorJustAlpha(paint.getColor()), false, &grPaint)) {
1576 return;
1577 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001578
joshualitt25d9c152015-02-18 12:29:52 -08001579 fContext->drawNonAARectToRect(fRenderTarget,
joshualitt570d2f82015-02-25 13:19:48 -08001580 fClip,
joshualitt25d9c152015-02-18 12:29:52 -08001581 grPaint,
joshualitt16b27892014-12-18 07:47:16 -08001582 SkMatrix::I(),
1583 SkRect::MakeXYWH(SkIntToScalar(left),
1584 SkIntToScalar(top),
1585 SkIntToScalar(w),
1586 SkIntToScalar(h)),
1587 SkRect::MakeXYWH(0,
1588 0,
1589 SK_Scalar1 * w / texture->width(),
1590 SK_Scalar1 * h / texture->height()));
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001591}
1592
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001593void SkGpuDevice::drawBitmapRect(const SkDraw& origDraw, const SkBitmap& bitmap,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001594 const SkRect* src, const SkRect& dst,
1595 const SkPaint& paint,
1596 SkCanvas::DrawBitmapRectFlags flags) {
1597 SkMatrix matrix;
1598 SkRect bitmapBounds, tmpSrc;
1599
1600 bitmapBounds.set(0, 0,
1601 SkIntToScalar(bitmap.width()),
1602 SkIntToScalar(bitmap.height()));
1603
1604 // Compute matrix from the two rectangles
bsalomon49f085d2014-09-05 13:34:00 -07001605 if (src) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001606 tmpSrc = *src;
1607 } else {
1608 tmpSrc = bitmapBounds;
1609 }
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001610
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001611 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
1612
1613 // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null.
bsalomon49f085d2014-09-05 13:34:00 -07001614 if (src) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001615 if (!bitmapBounds.contains(tmpSrc)) {
1616 if (!tmpSrc.intersect(bitmapBounds)) {
1617 return; // nothing to draw
1618 }
1619 }
1620 }
1621
commit-bot@chromium.orga7d89c82014-01-13 14:47:00 +00001622 SkRect tmpDst;
1623 matrix.mapRect(&tmpDst, tmpSrc);
1624
1625 SkTCopyOnFirstWrite<SkDraw> draw(origDraw);
1626 if (0 != tmpDst.fLeft || 0 != tmpDst.fTop) {
1627 // Translate so that tempDst's top left is at the origin.
1628 matrix = *origDraw.fMatrix;
1629 matrix.preTranslate(tmpDst.fLeft, tmpDst.fTop);
1630 draw.writable()->fMatrix = &matrix;
1631 }
1632 SkSize dstSize;
1633 dstSize.fWidth = tmpDst.width();
1634 dstSize.fHeight = tmpDst.height();
1635
1636 this->drawBitmapCommon(*draw, bitmap, &tmpSrc, &dstSize, paint, flags);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001637}
1638
1639void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device,
1640 int x, int y, const SkPaint& paint) {
1641 // clear of the source device must occur before CHECK_SHOULD_DRAW
egdanield78a1682014-07-09 10:41:26 -07001642 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawDevice", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001643 SkGpuDevice* dev = static_cast<SkGpuDevice*>(device);
kkinnunen2e4414e2015-02-19 07:20:40 -08001644
1645 // TODO: If the source device covers the whole of this device, we could
1646 // omit fNeedsClear -related flushing.
1647 // TODO: if source needs clear, we could maybe omit the draw fully.
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001648
1649 // drawDevice is defined to be in device coords.
joshualitt5531d512014-12-17 15:50:11 -08001650 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001651
1652 GrRenderTarget* devRT = dev->accessRenderTarget();
1653 GrTexture* devTex;
1654 if (NULL == (devTex = devRT->asTexture())) {
1655 return;
1656 }
1657
robertphillips7b9e8a42014-12-11 08:20:31 -08001658 const SkImageInfo ii = dev->imageInfo();
1659 int w = ii.width();
1660 int h = ii.height();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001661
1662 SkImageFilter* filter = paint.getImageFilter();
1663 // This bitmap will own the filtered result as a texture.
1664 SkBitmap filteredBitmap;
1665
bsalomon49f085d2014-09-05 13:34:00 -07001666 if (filter) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001667 SkIPoint offset = SkIPoint::Make(0, 0);
1668 SkMatrix matrix(*draw.fMatrix);
1669 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001670 SkIRect clipBounds = SkIRect::MakeWH(devTex->width(), devTex->height());
senorblanco55b6d8b2014-07-30 11:26:46 -07001671 // This cache is transient, and is freed (along with all its contained
1672 // textures) when it goes out of scope.
senorblancobe129b22014-08-08 07:14:35 -07001673 SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache());
commit-bot@chromium.orgf7efa502014-04-11 18:57:00 +00001674 SkImageFilter::Context ctx(matrix, clipBounds, cache);
senorblancod0d37ca2015-04-02 04:54:56 -07001675 if (this->filterTexture(fContext, devTex, device->width(), device->height(),
1676 filter, ctx, &filteredBitmap, &offset)) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001677 devTex = filteredBitmap.getTexture();
1678 w = filteredBitmap.width();
1679 h = filteredBitmap.height();
1680 x += offset.fX;
1681 y += offset.fY;
1682 } else {
1683 return;
1684 }
1685 }
1686
1687 GrPaint grPaint;
joshualittb0a8a372014-09-23 09:50:21 -07001688 grPaint.addColorTextureProcessor(devTex, SkMatrix::I());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001689
bsalomonbed83a62015-04-15 14:18:34 -07001690 if (!SkPaint2GrPaintNoShader(this->context(), fRenderTarget, paint,
1691 SkColor2GrColorJustAlpha(paint.getColor()), false, &grPaint)) {
1692 return;
1693 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001694
1695 SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x),
1696 SkIntToScalar(y),
1697 SkIntToScalar(w),
1698 SkIntToScalar(h));
1699
1700 // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate
1701 // scratch texture).
1702 SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(),
1703 SK_Scalar1 * h / devTex->height());
1704
joshualitt570d2f82015-02-25 13:19:48 -08001705 fContext->drawNonAARectToRect(fRenderTarget, fClip, grPaint, SkMatrix::I(), dstRect,
1706 srcRect);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001707}
1708
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001709bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001710 return filter->canFilterImageGPU();
1711}
1712
commit-bot@chromium.orgae761f72014-02-05 22:32:02 +00001713bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src,
senorblanco@chromium.org4cb543d2014-03-14 15:44:01 +00001714 const SkImageFilter::Context& ctx,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001715 SkBitmap* result, SkIPoint* offset) {
1716 // want explicitly our impl, so guard against a subclass of us overriding it
1717 if (!this->SkGpuDevice::canHandleImageFilter(filter)) {
1718 return false;
1719 }
1720
1721 SkAutoLockPixels alp(src, !src.getTexture());
1722 if (!src.getTexture() && !src.readyToDraw()) {
1723 return false;
1724 }
1725
1726 GrTexture* texture;
1727 // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup
1728 // must be pushed upstack.
bsalomonbcf0a522014-10-08 08:40:09 -07001729 AutoBitmapTexture abt(fContext, src, NULL, &texture);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001730
senorblancod0d37ca2015-04-02 04:54:56 -07001731 return this->filterTexture(fContext, texture, src.width(), src.height(),
1732 filter, ctx, result, offset);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001733}
1734
1735///////////////////////////////////////////////////////////////////////////////
1736
1737// must be in SkCanvas::VertexMode order
1738static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1739 kTriangles_GrPrimitiveType,
1740 kTriangleStrip_GrPrimitiveType,
1741 kTriangleFan_GrPrimitiveType,
1742};
1743
1744void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1745 int vertexCount, const SkPoint vertices[],
1746 const SkPoint texs[], const SkColor colors[],
1747 SkXfermode* xmode,
1748 const uint16_t indices[], int indexCount,
1749 const SkPaint& paint) {
joshualitt5531d512014-12-17 15:50:11 -08001750 CHECK_SHOULD_DRAW(draw);
egdanield78a1682014-07-09 10:41:26 -07001751 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawVertices", fContext);
mtklein533eb782014-08-27 10:39:42 -07001752
dandov32a311b2014-07-15 19:46:26 -07001753 const uint16_t* outIndices;
1754 SkAutoTDeleteArray<uint16_t> outAlloc(NULL);
1755 GrPrimitiveType primType;
1756 GrPaint grPaint;
bsalomona098dd42014-08-06 11:01:44 -07001757
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001758 // If both textures and vertex-colors are NULL, strokes hairlines with the paint's color.
1759 if ((NULL == texs || NULL == paint.getShader()) && NULL == colors) {
mtklein533eb782014-08-27 10:39:42 -07001760
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001761 texs = NULL;
mtklein533eb782014-08-27 10:39:42 -07001762
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001763 SkPaint copy(paint);
1764 copy.setStyle(SkPaint::kStroke_Style);
1765 copy.setStrokeWidth(0);
mtklein533eb782014-08-27 10:39:42 -07001766
dandov32a311b2014-07-15 19:46:26 -07001767 // we ignore the shader if texs is null.
bsalomonbed83a62015-04-15 14:18:34 -07001768 if (!SkPaint2GrPaintNoShader(this->context(), fRenderTarget, copy,
1769 SkColor2GrColor(copy.getColor()), NULL == colors, &grPaint)) {
1770 return;
1771 }
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001772
dandov32a311b2014-07-15 19:46:26 -07001773 primType = kLines_GrPrimitiveType;
1774 int triangleCount = 0;
bsalomona098dd42014-08-06 11:01:44 -07001775 int n = (NULL == indices) ? vertexCount : indexCount;
dandov32a311b2014-07-15 19:46:26 -07001776 switch (vmode) {
1777 case SkCanvas::kTriangles_VertexMode:
bsalomona098dd42014-08-06 11:01:44 -07001778 triangleCount = n / 3;
dandov32a311b2014-07-15 19:46:26 -07001779 break;
1780 case SkCanvas::kTriangleStrip_VertexMode:
1781 case SkCanvas::kTriangleFan_VertexMode:
bsalomona098dd42014-08-06 11:01:44 -07001782 triangleCount = n - 2;
dandov32a311b2014-07-15 19:46:26 -07001783 break;
1784 }
mtklein533eb782014-08-27 10:39:42 -07001785
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001786 VertState state(vertexCount, indices, indexCount);
1787 VertState::Proc vertProc = state.chooseProc(vmode);
mtklein533eb782014-08-27 10:39:42 -07001788
dandov32a311b2014-07-15 19:46:26 -07001789 //number of indices for lines per triangle with kLines
1790 indexCount = triangleCount * 6;
mtklein533eb782014-08-27 10:39:42 -07001791
dandov32a311b2014-07-15 19:46:26 -07001792 outAlloc.reset(SkNEW_ARRAY(uint16_t, indexCount));
1793 outIndices = outAlloc.get();
1794 uint16_t* auxIndices = outAlloc.get();
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001795 int i = 0;
1796 while (vertProc(&state)) {
dandov32a311b2014-07-15 19:46:26 -07001797 auxIndices[i] = state.f0;
1798 auxIndices[i + 1] = state.f1;
1799 auxIndices[i + 2] = state.f1;
1800 auxIndices[i + 3] = state.f2;
1801 auxIndices[i + 4] = state.f2;
1802 auxIndices[i + 5] = state.f0;
commit-bot@chromium.org559a8832014-05-30 10:08:22 +00001803 i += 6;
1804 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001805 } else {
dandov32a311b2014-07-15 19:46:26 -07001806 outIndices = indices;
1807 primType = gVertexMode2PrimitiveType[vmode];
mtklein533eb782014-08-27 10:39:42 -07001808
dandov32a311b2014-07-15 19:46:26 -07001809 if (NULL == texs || NULL == paint.getShader()) {
bsalomonbed83a62015-04-15 14:18:34 -07001810 if (!SkPaint2GrPaintNoShader(this->context(), fRenderTarget, paint,
1811 SkColor2GrColor(paint.getColor()),
1812 NULL == colors, &grPaint)) {
1813 return;
1814 }
dandov32a311b2014-07-15 19:46:26 -07001815 } else {
bsalomonbed83a62015-04-15 14:18:34 -07001816 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix,
1817 NULL == colors, &grPaint)) {
1818 return;
1819 }
dandov32a311b2014-07-15 19:46:26 -07001820 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001821 }
1822
mtklein2583b622014-06-04 08:20:41 -07001823#if 0
bsalomon49f085d2014-09-05 13:34:00 -07001824 if (xmode && texs && colors) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001825 if (!SkXfermode::IsMode(xmode, SkXfermode::kModulate_Mode)) {
1826 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
mtklein2583b622014-06-04 08:20:41 -07001827 return;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001828 }
1829 }
mtklein2583b622014-06-04 08:20:41 -07001830#endif
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001831
1832 SkAutoSTMalloc<128, GrColor> convertedColors(0);
bsalomon49f085d2014-09-05 13:34:00 -07001833 if (colors) {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001834 // need to convert byte order and from non-PM to PM
1835 convertedColors.reset(vertexCount);
commit-bot@chromium.orgc93e6812014-05-23 08:09:26 +00001836 SkColor color;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001837 for (int i = 0; i < vertexCount; ++i) {
commit-bot@chromium.orgc93e6812014-05-23 08:09:26 +00001838 color = colors[i];
1839 if (paint.getAlpha() != 255) {
1840 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paint.getAlpha()));
1841 }
1842 convertedColors[i] = SkColor2GrColor(color);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001843 }
1844 colors = convertedColors.get();
1845 }
joshualitt25d9c152015-02-18 12:29:52 -08001846 fContext->drawVertices(fRenderTarget,
joshualitt570d2f82015-02-25 13:19:48 -08001847 fClip,
joshualitt25d9c152015-02-18 12:29:52 -08001848 grPaint,
joshualitt5531d512014-12-17 15:50:11 -08001849 *draw.fMatrix,
dandov32a311b2014-07-15 19:46:26 -07001850 primType,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001851 vertexCount,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +00001852 vertices,
1853 texs,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001854 colors,
dandov32a311b2014-07-15 19:46:26 -07001855 outIndices,
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001856 indexCount);
1857}
1858
1859///////////////////////////////////////////////////////////////////////////////
1860
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001861void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
joshualitt5531d512014-12-17 15:50:11 -08001862 size_t byteLength, SkScalar x, SkScalar y,
1863 const SkPaint& paint) {
1864 CHECK_SHOULD_DRAW(draw);
egdanield78a1682014-07-09 10:41:26 -07001865 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawText", fContext);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001866
jvanverth8c27a182014-10-14 08:45:50 -07001867 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -07001868 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint)) {
1869 return;
1870 }
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +00001871
jvanverth8c27a182014-10-14 08:45:50 -07001872 SkDEBUGCODE(this->validate();)
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +00001873
joshualitt6e8cd962015-03-20 10:30:14 -07001874 fTextContext->drawText(fRenderTarget, fClip, grPaint, paint, *draw.fMatrix,
1875 (const char *)text, byteLength, x, y, draw.fClip->getBounds());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001876}
1877
fmalita05c4a432014-09-29 06:29:53 -07001878void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, size_t byteLength,
1879 const SkScalar pos[], int scalarsPerPos,
1880 const SkPoint& offset, const SkPaint& paint) {
egdanielbbcb38d2014-06-19 10:19:29 -07001881 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPosText", fContext);
joshualitt5531d512014-12-17 15:50:11 -08001882 CHECK_SHOULD_DRAW(draw);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001883
jvanverth8c27a182014-10-14 08:45:50 -07001884 GrPaint grPaint;
bsalomonbed83a62015-04-15 14:18:34 -07001885 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, *draw.fMatrix, true, &grPaint)) {
1886 return;
1887 }
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +00001888
jvanverth8c27a182014-10-14 08:45:50 -07001889 SkDEBUGCODE(this->validate();)
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +00001890
joshualitt6e8cd962015-03-20 10:30:14 -07001891 fTextContext->drawPosText(fRenderTarget, fClip, grPaint, paint, *draw.fMatrix,
1892 (const char *)text, byteLength, pos, scalarsPerPos, offset,
1893 draw.fClip->getBounds());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001894}
1895
joshualitt9c328182015-03-23 08:13:04 -07001896void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y,
1897 const SkPaint& paint, SkDrawFilter* drawFilter) {
1898 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawTextBlob", fContext);
1899 CHECK_SHOULD_DRAW(draw);
1900
1901 SkDEBUGCODE(this->validate();)
1902
1903 fTextContext->drawTextBlob(fRenderTarget, fClip, paint, *draw.fMatrix, blob, x, y, drawFilter,
1904 draw.fClip->getBounds());
1905}
1906
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001907///////////////////////////////////////////////////////////////////////////////
1908
reedb2db8982014-11-13 12:41:02 -08001909bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001910 if (paint.getShader() ||
reedb2db8982014-11-13 12:41:02 -08001911 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode) ||
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001912 paint.getMaskFilter() ||
1913 paint.getRasterizer() ||
1914 paint.getColorFilter() ||
1915 paint.getPathEffect() ||
1916 paint.isFakeBoldText() ||
reedb2db8982014-11-13 12:41:02 -08001917 paint.getStyle() != SkPaint::kFill_Style)
1918 {
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001919 return true;
1920 }
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001921 return false;
1922}
1923
1924void SkGpuDevice::flush() {
1925 DO_DEFERRED_CLEAR();
bsalomon87a94eb2014-11-03 14:28:32 -08001926 fRenderTarget->prepareForExternalRead();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001927}
1928
1929///////////////////////////////////////////////////////////////////////////////
1930
reed76033be2015-03-14 10:54:31 -07001931SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) {
bsalomonf2703d82014-10-28 14:33:06 -07001932 GrSurfaceDesc desc;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001933 desc.fConfig = fRenderTarget->config();
bsalomonf2703d82014-10-28 14:33:06 -07001934 desc.fFlags = kRenderTarget_GrSurfaceFlag;
fmalita6987dca2014-11-13 08:33:37 -08001935 desc.fWidth = cinfo.fInfo.width();
1936 desc.fHeight = cinfo.fInfo.height();
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001937 desc.fSampleCnt = fRenderTarget->numSamples();
1938
1939 SkAutoTUnref<GrTexture> texture;
1940 // Skia's convention is to only clear a device if it is non-opaque.
fmalita6987dca2014-11-13 08:33:37 -08001941 unsigned flags = cinfo.fInfo.isOpaque() ? 0 : kNeedClear_Flag;
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001942
hcm4396fa52014-10-27 21:43:30 -07001943 // layers are never draw in repeat modes, so we can request an approx
1944 // match and ignore any padding.
reed76033be2015-03-14 10:54:31 -07001945 const GrContext::ScratchTexMatch match = (kNever_TileUsage == cinfo.fTileUsage) ?
hcm4396fa52014-10-27 21:43:30 -07001946 GrContext::kApprox_ScratchTexMatch :
1947 GrContext::kExact_ScratchTexMatch;
bsalomone3059732014-10-14 11:47:22 -07001948 texture.reset(fContext->refScratchTexture(desc, match));
bsalomonafe30052015-01-16 07:32:33 -08001949
1950 if (texture) {
1951 SkSurfaceProps props(fSurfaceProps.flags(), cinfo.fPixelGeometry);
senorblancod0d37ca2015-04-02 04:54:56 -07001952 return SkGpuDevice::Create(
1953 texture->asRenderTarget(), cinfo.fInfo.width(), cinfo.fInfo.height(), &props, flags);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001954 } else {
joshualitt5f5a8d72015-02-25 14:09:45 -08001955 SkErrorInternals::SetError( kInternalError_SkError,
1956 "---- failed to create compatible device texture [%d %d]\n",
1957 cinfo.fInfo.width(), cinfo.fInfo.height());
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +00001958 return NULL;
1959 }
1960}
1961
reed4a8126e2014-09-22 07:29:03 -07001962SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
bsalomonafe30052015-01-16 07:32:33 -08001963 // TODO: Change the signature of newSurface to take a budgeted parameter.
1964 static const SkSurface::Budgeted kBudgeted = SkSurface::kNo_Budgeted;
1965 return SkSurface::NewRenderTarget(fContext, kBudgeted, info, fRenderTarget->numSamples(),
1966 &props);
reed@google.com76f10a32014-02-05 15:32:21 +00001967}
1968
robertphillips30d2cc62014-09-24 08:52:18 -07001969bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* mainPicture,
reedd5fa1a42014-08-09 11:08:05 -07001970 const SkMatrix* matrix, const SkPaint* paint) {
robertphillips63242d72014-12-04 08:31:02 -08001971#ifndef SK_IGNORE_GPU_LAYER_HOISTING
robertphillips30d78412014-11-24 09:49:17 -08001972 // todo: should handle this natively
1973 if (paint) {
reedd5fa1a42014-08-09 11:08:05 -07001974 return false;
1975 }
1976
robertphillips82365912014-11-12 09:32:34 -08001977 SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
robertphillips81f71b62014-11-11 04:54:49 -08001978
1979 const SkPicture::AccelData* data = mainPicture->EXPERIMENTAL_getAccelData(key);
1980 if (!data) {
1981 return false;
1982 }
1983
robertphillipse5524cd2015-02-20 12:30:26 -08001984 const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data);
1985 if (0 == gpuData->numBlocks()) {
1986 return false;
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +00001987 }
1988
robertphillipsfd61ed02014-10-28 07:21:44 -07001989 SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled;
robertphillips1c4c5282014-09-18 12:03:15 -07001990
robertphillipse5524cd2015-02-20 12:30:26 -08001991 SkIRect iBounds;
1992 if (!mainCanvas->getClipDeviceBounds(&iBounds)) {
1993 return false;
1994 }
1995
1996 SkRect clipBounds = SkRect::Make(iBounds);
1997
1998 SkMatrix initialMatrix = mainCanvas->getTotalMatrix();
1999
robertphillipsfd61ed02014-10-28 07:21:44 -07002000 GrLayerHoister::FindLayersToAtlas(fContext, mainPicture,
robertphillips30d78412014-11-24 09:49:17 -08002001 initialMatrix,
robertphillipsfd61ed02014-10-28 07:21:44 -07002002 clipBounds,
robertphillipsa63f32e2014-11-10 08:10:42 -08002003 &atlasedNeedRendering, &atlasedRecycled,
2004 fRenderTarget->numSamples());
robertphillipsfd61ed02014-10-28 07:21:44 -07002005
2006 GrLayerHoister::DrawLayersToAtlas(fContext, atlasedNeedRendering);
2007
2008 SkTDArray<GrHoistedLayer> needRendering, recycled;
2009
robertphillipse5524cd2015-02-20 12:30:26 -08002010 SkAutoCanvasMatrixPaint acmp(mainCanvas, matrix, paint, mainPicture->cullRect());
2011
robertphillipsfd61ed02014-10-28 07:21:44 -07002012 GrLayerHoister::FindLayersToHoist(fContext, mainPicture,
robertphillips30d78412014-11-24 09:49:17 -08002013 initialMatrix,
robertphillipsfd61ed02014-10-28 07:21:44 -07002014 clipBounds,
robertphillipsa63f32e2014-11-10 08:10:42 -08002015 &needRendering, &recycled,
2016 fRenderTarget->numSamples());
robertphillipsfd61ed02014-10-28 07:21:44 -07002017
2018 GrLayerHoister::DrawLayers(fContext, needRendering);
robertphillips@google.combeb1af22014-05-07 21:31:09 +00002019
robertphillips64bf7672014-08-21 13:07:35 -07002020 // Render the entire picture using new layers
robertphillipse99d4992014-12-03 07:33:57 -08002021 GrRecordReplaceDraw(mainPicture, mainCanvas, fContext->getLayerCache(),
2022 initialMatrix, NULL);
robertphillips64bf7672014-08-21 13:07:35 -07002023
robertphillipsfd61ed02014-10-28 07:21:44 -07002024 GrLayerHoister::UnlockLayers(fContext, needRendering);
2025 GrLayerHoister::UnlockLayers(fContext, recycled);
2026 GrLayerHoister::UnlockLayers(fContext, atlasedNeedRendering);
2027 GrLayerHoister::UnlockLayers(fContext, atlasedRecycled);
robertphillips64bf7672014-08-21 13:07:35 -07002028
2029 return true;
robertphillips63242d72014-12-04 08:31:02 -08002030#else
2031 return false;
2032#endif
robertphillips64bf7672014-08-21 13:07:35 -07002033}
2034
senorblancobe129b22014-08-08 07:14:35 -07002035SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() {
senorblanco55b6d8b2014-07-30 11:26:46 -07002036 // We always return a transient cache, so it is freed after each
2037 // filter traversal.
senorblancobe129b22014-08-08 07:14:35 -07002038 return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize);
senorblanco55b6d8b2014-07-30 11:26:46 -07002039}
reedf037e0b2014-10-30 11:34:15 -07002040
2041#endif