blob: af31ee57b2ee958e180635640a7b1df82a3f9bdb [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
reed@google.comac10a2d2010-12-22 21:39:39 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#include "GrContext.h"
19#include "GrTextContext.h"
20
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "SkGpuDevice.h"
reed@google.com7b201d22011-01-11 18:59:23 +000022#include "SkGpuDeviceFactory.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000023#include "SkGrTexturePixelRef.h"
24
Scroggo97c88c22011-05-11 14:05:25 +000025#include "SkColorFilter.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000026#include "SkDrawProcs.h"
27#include "SkGlyphCache.h"
reed@google.comc9aa5872011-04-05 21:05:37 +000028#include "SkUtils.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000029
30#define CACHE_LAYER_TEXTURES 1
31
32#if 0
33 extern bool (*gShouldDrawProc)();
34 #define CHECK_SHOULD_DRAW(draw) \
35 do { \
36 if (gShouldDrawProc && !gShouldDrawProc()) return; \
37 this->prepareRenderTarget(draw); \
38 } while (0)
39#else
40 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
41#endif
42
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +000043// we use the same texture slot on GrPaint for bitmaps and shaders
44// (since drawBitmap, drawSprite, and drawDevice ignore skia's shader)
45enum {
46 kBitmapTextureIdx = 0,
47 kShaderTextureIdx = 0
48};
49
reed@google.comac10a2d2010-12-22 21:39:39 +000050///////////////////////////////////////////////////////////////////////////////
51
52SkGpuDevice::SkAutoCachedTexture::
53 SkAutoCachedTexture(SkGpuDevice* device,
54 const SkBitmap& bitmap,
55 const GrSamplerState& sampler,
56 GrTexture** texture) {
57 GrAssert(texture);
58 fTex = NULL;
59 *texture = this->set(device, bitmap, sampler);
60}
61
62SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
63 fTex = NULL;
64}
65
66GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
67 const SkBitmap& bitmap,
68 const GrSamplerState& sampler) {
69 if (fTex) {
70 fDevice->unlockCachedTexture(fTex);
71 }
72 fDevice = device;
73 GrTexture* texture = (GrTexture*)bitmap.getTexture();
74 if (texture) {
75 // return the native texture
76 fTex = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000077 } else {
78 // look it up in our cache
bsalomon@google.come97f0852011-06-17 13:10:25 +000079 fTex = device->lockCachedTexture(bitmap, sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +000080 }
81 return texture;
82}
83
84SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
85 if (fTex) {
86 fDevice->unlockCachedTexture(fTex);
87 }
88}
89
90///////////////////////////////////////////////////////////////////////////////
91
92bool gDoTraceDraw;
93
94struct GrSkDrawProcs : public SkDrawProcs {
95public:
96 GrContext* fContext;
97 GrTextContext* fTextContext;
98 GrFontScaler* fFontScaler; // cached in the skia glyphcache
99};
100
101///////////////////////////////////////////////////////////////////////////////
102
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000103GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
104 return (GrRenderTarget*) -1;
105}
106
reed@google.comaf951c92011-06-16 19:10:39 +0000107static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
108 switch (config) {
109 case kAlpha_8_GrPixelConfig:
110 *isOpaque = false;
111 return SkBitmap::kA8_Config;
112 case kRGB_565_GrPixelConfig:
113 *isOpaque = true;
114 return SkBitmap::kRGB_565_Config;
115 case kRGBA_4444_GrPixelConfig:
116 *isOpaque = false;
117 return SkBitmap::kARGB_4444_Config;
118 case kRGBA_8888_GrPixelConfig:
119 case kRGBX_8888_GrPixelConfig:
120 *isOpaque = (kRGBX_8888_GrPixelConfig == config);
121 return SkBitmap::kARGB_8888_Config;
122 default:
123 *isOpaque = false;
124 return SkBitmap::kNo_Config;
125 }
126}
reed@google.comac10a2d2010-12-22 21:39:39 +0000127
reed@google.comaf951c92011-06-16 19:10:39 +0000128static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
129 if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
130 renderTarget = context->createRenderTargetFrom3DApiState();
131 }
132 GrTexture* texture = renderTarget->asTexture();
133 GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
134
135 bool isOpaque;
136 SkBitmap bitmap;
137 bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
138 renderTarget->width(), renderTarget->height());
139 bitmap.setIsOpaque(isOpaque);
140 return bitmap;
141}
142
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000143SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
144: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
145 this->initFromRenderTarget(context, texture->asRenderTarget());
146}
147
reed@google.comaf951c92011-06-16 19:10:39 +0000148SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
149: SkDevice(make_bitmap(context, renderTarget)) {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000150 this->initFromRenderTarget(context, renderTarget);
151}
152
153void SkGpuDevice::initFromRenderTarget(GrContext* context,
154 GrRenderTarget* renderTarget) {
reed@google.comaf951c92011-06-16 19:10:39 +0000155 fNeedPrepareRenderTarget = false;
156 fDrawProcs = NULL;
157
158 fContext = context;
159 fContext->ref();
160
161 fCache = NULL;
162 fTexture = NULL;
163 fRenderTarget = NULL;
164 fNeedClear = false;
165
166 if (Current3DApiRenderTarget() == renderTarget) {
167 fRenderTarget = fContext->createRenderTargetFrom3DApiState();
168 } else {
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000169 GrAssert(NULL != renderTarget);
reed@google.comaf951c92011-06-16 19:10:39 +0000170 fRenderTarget = renderTarget;
171 fRenderTarget->ref();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000172 // if this RT is also a texture, hold a ref on it
173 fTexture = fRenderTarget->asTexture();
174 SkSafeRef(fTexture);
reed@google.comaf951c92011-06-16 19:10:39 +0000175 }
176
177 SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
178 this->setPixelRef(pr, 0)->unref();
179}
180
181SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
bsalomon@google.come97f0852011-06-17 13:10:25 +0000182 int height, Usage usage)
reed@google.comaf951c92011-06-16 19:10:39 +0000183: SkDevice(config, width, height, false /*isOpaque*/) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 fNeedPrepareRenderTarget = false;
185 fDrawProcs = NULL;
186
reed@google.com7b201d22011-01-11 18:59:23 +0000187 fContext = context;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000188 fContext->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000189
190 fCache = NULL;
191 fTexture = NULL;
192 fRenderTarget = NULL;
193 fNeedClear = false;
194
reed@google.comaf951c92011-06-16 19:10:39 +0000195 if (config != SkBitmap::kRGB_565_Config) {
196 config = SkBitmap::kARGB_8888_Config;
197 }
198 SkBitmap bm;
199 bm.setConfig(config, width, height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000200
201#if CACHE_LAYER_TEXTURES
bsalomon@google.come97f0852011-06-17 13:10:25 +0000202 TexType type = (kSaveLayer_Usage == usage) ?
203 kSaveLayerDeviceRenderTarget_TexType :
204 kDeviceRenderTarget_TexType;
reed@google.comaf951c92011-06-16 19:10:39 +0000205 fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
bsalomon@google.come97f0852011-06-17 13:10:25 +0000206 &fTexture, type);
reed@google.comaf951c92011-06-16 19:10:39 +0000207 if (fCache) {
208 SkASSERT(NULL != fTexture);
209 SkASSERT(NULL != fTexture->asRenderTarget());
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000210 // hold a ref directly on fTexture (even though fCache has one) to match
211 // other constructor paths. Simplifies cleanup.
212 fTexture->ref();
reed@google.comaf951c92011-06-16 19:10:39 +0000213 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000214#else
reed@google.comaf951c92011-06-16 19:10:39 +0000215 const GrTextureDesc desc = {
216 kRenderTarget_GrTextureFlagBit,
217 kNone_GrAALevel,
218 width,
219 height,
220 SkGr::Bitmap2PixelConfig(bm)
221 };
reed@google.comac10a2d2010-12-22 21:39:39 +0000222
reed@google.comaf951c92011-06-16 19:10:39 +0000223 fTexture = fContext->createUncachedTexture(desc, NULL, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000224#endif
reed@google.comaf951c92011-06-16 19:10:39 +0000225 if (NULL != fTexture) {
226 fRenderTarget = fTexture->asRenderTarget();
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000227 fRenderTarget->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000228
reed@google.comaf951c92011-06-16 19:10:39 +0000229 GrAssert(NULL != fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000230
reed@google.comaf951c92011-06-16 19:10:39 +0000231 // we defer the actual clear until our gainFocus()
232 fNeedClear = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000233
reed@google.comaf951c92011-06-16 19:10:39 +0000234 // wrap the bitmap with a pixelref to expose our texture
235 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000236 this->setPixelRef(pr, 0)->unref();
reed@google.comaf951c92011-06-16 19:10:39 +0000237 } else {
238 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
239 width, height);
240 GrAssert(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000241 }
242}
243
244SkGpuDevice::~SkGpuDevice() {
245 if (fDrawProcs) {
246 delete fDrawProcs;
247 }
248
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000249 SkSafeUnref(fTexture);
250 SkSafeUnref(fRenderTarget);
reed@google.comac10a2d2010-12-22 21:39:39 +0000251 if (fCache) {
252 GrAssert(NULL != fTexture);
253 GrAssert(fRenderTarget == fTexture->asRenderTarget());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000254 fContext->unlockTexture((GrTextureEntry*)fCache);
bsalomon@google.comf9046fe2011-06-17 15:10:21 +0000255 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000256 fContext->unref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000257}
258
reed@google.comac10a2d2010-12-22 21:39:39 +0000259intptr_t SkGpuDevice::getLayerTextureHandle() const {
260 if (fTexture) {
261 return fTexture->getTextureHandle();
262 } else {
263 return 0;
264 }
265}
mike@reedtribe.orgea4ac972011-04-26 11:48:33 +0000266
reed@google.comac10a2d2010-12-22 21:39:39 +0000267///////////////////////////////////////////////////////////////////////////////
268
269void SkGpuDevice::makeRenderTargetCurrent() {
270 fContext->setRenderTarget(fRenderTarget);
271 fContext->flush(true);
272 fNeedPrepareRenderTarget = true;
273}
274
275///////////////////////////////////////////////////////////////////////////////
276
277bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
278 SkIRect bounds;
279 bounds.set(0, 0, this->width(), this->height());
280 if (!bounds.intersect(srcRect)) {
281 return false;
282 }
283
284 const int w = bounds.width();
285 const int h = bounds.height();
286 SkBitmap tmp;
287 // note we explicitly specify our rowBytes to be snug (no gap between rows)
288 tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
289 if (!tmp.allocPixels()) {
290 return false;
291 }
292
Scroggo813c33c2011-04-07 20:56:21 +0000293 tmp.lockPixels();
reed@google.comac10a2d2010-12-22 21:39:39 +0000294
Scroggoeb176032011-04-07 21:11:49 +0000295 bool read = fContext->readRenderTargetPixels(fRenderTarget,
296 bounds.fLeft, bounds.fTop,
297 bounds.width(), bounds.height(),
298 kRGBA_8888_GrPixelConfig,
299 tmp.getPixels());
Scroggo813c33c2011-04-07 20:56:21 +0000300 tmp.unlockPixels();
301 if (!read) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 return false;
303 }
304
305 tmp.swap(*bitmap);
306 return true;
307}
308
309void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
310 SkAutoLockPixels alp(bitmap);
311 if (!bitmap.readyToDraw()) {
312 return;
313 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000314 GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
315 bitmap.isOpaque());
reed@google.comac10a2d2010-12-22 21:39:39 +0000316 fContext->setRenderTarget(fRenderTarget);
317 // we aren't setting the clip or matrix, so mark as dirty
318 // we don't need to set them for this call and don't have them anyway
319 fNeedPrepareRenderTarget = true;
320
321 fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
322 config, bitmap.getPixels(), bitmap.rowBytes());
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
327static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000328 const SkClipStack& clipStack,
reed@google.com6f8f2922011-03-04 22:27:10 +0000329 const SkRegion& clipRegion,
330 const SkIPoint& origin) {
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000331 context->setMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000332
333 SkGrClipIterator iter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000334 iter.reset(clipStack);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000335 const SkIRect& skBounds = clipRegion.getBounds();
336 GrRect bounds;
337 bounds.setLTRB(GrIntToScalar(skBounds.fLeft),
338 GrIntToScalar(skBounds.fTop),
339 GrIntToScalar(skBounds.fRight),
340 GrIntToScalar(skBounds.fBottom));
reed@google.com6f8f2922011-03-04 22:27:10 +0000341 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()),
342 &bounds);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000343 context->setClip(grc);
reed@google.comac10a2d2010-12-22 21:39:39 +0000344}
345
346// call this ever each draw call, to ensure that the context reflects our state,
347// and not the state from some other canvas/device
348void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
349 if (fNeedPrepareRenderTarget ||
bsalomon@google.com5782d712011-01-21 21:03:59 +0000350 fContext->getRenderTarget() != fRenderTarget) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000351
352 fContext->setRenderTarget(fRenderTarget);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000353 SkASSERT(draw.fClipStack);
354 convert_matrixclip(fContext, *draw.fMatrix,
reed@google.com6f8f2922011-03-04 22:27:10 +0000355 *draw.fClipStack, *draw.fClip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000356 fNeedPrepareRenderTarget = false;
357 }
358}
359
reed@google.com46799cd2011-02-22 20:56:26 +0000360void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
361 const SkClipStack& clipStack) {
362 this->INHERITED::setMatrixClip(matrix, clip, clipStack);
bsalomon@google.coma7bf6e22011-04-11 19:20:46 +0000363 // We don't need to set them now because the context may not reflect this device.
364 fNeedPrepareRenderTarget = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000365}
366
367void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
bsalomon@google.comd302f142011-03-03 13:54:13 +0000368 const SkRegion& clip, const SkClipStack& clipStack) {
369
reed@google.comac10a2d2010-12-22 21:39:39 +0000370 fContext->setRenderTarget(fRenderTarget);
371
bsalomon@google.comd302f142011-03-03 13:54:13 +0000372 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack);
reed@google.comac10a2d2010-12-22 21:39:39 +0000373
reed@google.com6f8f2922011-03-04 22:27:10 +0000374 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin());
reed@google.comac10a2d2010-12-22 21:39:39 +0000375
376 if (fNeedClear) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000377 fContext->clear(NULL, 0x0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000378 fNeedClear = false;
379 }
380}
381
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000382bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000383 if (NULL != fTexture) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000384 paint->setTexture(kBitmapTextureIdx, fTexture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 return true;
386 }
387 return false;
388}
389
390///////////////////////////////////////////////////////////////////////////////
391
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000392SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch);
393SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch);
394SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch);
395SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch);
396SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4,
397 shader_type_mismatch);
398SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch);
reed@google.comac10a2d2010-12-22 21:39:39 +0000399
bsalomon@google.com5782d712011-01-21 21:03:59 +0000400static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = {
401 (GrSamplerState::SampleMode) -1, // kNone_BitmapType
402 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType
403 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType
404 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType
405 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType
406};
407
408bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
409 bool justAlpha,
Scroggod757df22011-05-16 13:11:16 +0000410 GrPaint* grPaint,
411 bool constantColor) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000412
413 grPaint->fDither = skPaint.isDither();
414 grPaint->fAntiAlias = skPaint.isAntiAlias();
415
416 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
417 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
418
419 SkXfermode* mode = skPaint.getXfermode();
420 if (mode) {
421 if (!mode->asCoeff(&sm, &dm)) {
reed@google.com1a2e8d22011-01-21 22:08:29 +0000422 SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423#if 0
424 return false;
425#endif
426 }
427 }
428 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
429 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
430
431 if (justAlpha) {
432 uint8_t alpha = skPaint.getAlpha();
433 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
Scroggod757df22011-05-16 13:11:16 +0000434 // justAlpha is currently set to true only if there is a texture,
435 // so constantColor should not also be true.
436 GrAssert(!constantColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000437 } else {
438 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor());
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000439 grPaint->setTexture(kShaderTextureIdx, NULL);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000440 }
Scroggo97c88c22011-05-11 14:05:25 +0000441 SkColorFilter* colorFilter = skPaint.getColorFilter();
442 SkColor color;
443 SkXfermode::Mode filterMode;
444 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
Scroggod757df22011-05-16 13:11:16 +0000445 if (!constantColor) {
446 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
447 grPaint->fColorFilterXfermode = filterMode;
448 return true;
449 }
450 SkColor filtered = colorFilter->filterColor(skPaint.getColor());
451 grPaint->fColor = SkGr::SkColor2GrColor(filtered);
Scroggo97c88c22011-05-11 14:05:25 +0000452 }
Scroggod757df22011-05-16 13:11:16 +0000453 grPaint->resetColorFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000454 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000455}
456
bsalomon@google.com5782d712011-01-21 21:03:59 +0000457bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
458 SkAutoCachedTexture* act,
459 const SkMatrix& ctm,
Scroggod757df22011-05-16 13:11:16 +0000460 GrPaint* grPaint,
461 bool constantColor) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000462
bsalomon@google.com5782d712011-01-21 21:03:59 +0000463 SkASSERT(NULL != act);
reed@google.comac10a2d2010-12-22 21:39:39 +0000464
bsalomon@google.com5782d712011-01-21 21:03:59 +0000465 SkShader* shader = skPaint.getShader();
reed@google.comac10a2d2010-12-22 21:39:39 +0000466 if (NULL == shader) {
Scroggod757df22011-05-16 13:11:16 +0000467 return this->skPaint2GrPaintNoShader(skPaint,
468 false,
469 grPaint,
470 constantColor);
471 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000472 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000473 }
474
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475 SkPaint noAlphaPaint(skPaint);
476 noAlphaPaint.setAlpha(255);
477 shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
reed@google.comac10a2d2010-12-22 21:39:39 +0000478
reed@google.comac10a2d2010-12-22 21:39:39 +0000479 SkBitmap bitmap;
480 SkMatrix matrix;
481 SkShader::TileMode tileModes[2];
482 SkScalar twoPointParams[3];
483 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
484 tileModes, twoPointParams);
485
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
487 if (-1 == sampleMode) {
488 SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
489 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000490 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000491 GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
492 sampler->setSampleMode(sampleMode);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000493 if (skPaint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000494 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000495 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000496 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000497 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000498 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
499 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
reed@google.comac10a2d2010-12-22 21:39:39 +0000500 if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000501 sampler->setRadial2Params(twoPointParams[0],
502 twoPointParams[1],
503 twoPointParams[2] < 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000504 }
505
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000506 GrTexture* texture = act->set(this, bitmap, *sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000507 if (NULL == texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000508 SkDebugf("Couldn't convert bitmap to texture.\n");
509 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000510 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000511 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.comac10a2d2010-12-22 21:39:39 +0000512
513 // since our texture coords will be in local space, we wack the texture
514 // matrix to map them back into 0...1 before we load it
515 SkMatrix localM;
516 if (shader->getLocalMatrix(&localM)) {
517 SkMatrix inverse;
518 if (localM.invert(&inverse)) {
519 matrix.preConcat(inverse);
520 }
521 }
522 if (SkShader::kDefault_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000523 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
524 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +0000525 matrix.postScale(sx, sy);
reed@google.comac10a2d2010-12-22 21:39:39 +0000526 } else if (SkShader::kRadial_BitmapType == bmptype) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000527 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
reed@google.comac10a2d2010-12-22 21:39:39 +0000528 matrix.postScale(s, s);
529 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000530 sampler->setMatrix(matrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000531
532 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000533}
534
535///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com5782d712011-01-21 21:03:59 +0000536
537class SkPositionSource {
538public:
539 SkPositionSource(const SkPoint* points, int count)
540 : fPoints(points), fCount(count) {}
541
542 int count() const { return fCount; }
543
544 void writeValue(int i, GrPoint* dstPosition) const {
545 SkASSERT(i < fCount);
546 dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
547 dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
548 }
549private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000550 const SkPoint* fPoints;
bsalomon@google.com19628322011-02-03 21:30:17 +0000551 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000552};
553
554class SkTexCoordSource {
555public:
556 SkTexCoordSource(const SkPoint* coords)
557 : fCoords(coords) {}
558
559 void writeValue(int i, GrPoint* dstCoord) const {
560 dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
561 dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
562 }
563private:
564 const SkPoint* fCoords;
565};
566
567class SkColorSource {
568public:
569 SkColorSource(const SkColor* colors) : fColors(colors) {}
570
571 void writeValue(int i, GrColor* dstColor) const {
572 *dstColor = SkGr::SkColor2GrColor(fColors[i]);
573 }
574private:
575 const SkColor* fColors;
576};
577
578class SkIndexSource {
579public:
580 SkIndexSource(const uint16_t* indices, int count)
581 : fIndices(indices), fCount(count) {
582 }
583
584 int count() const { return fCount; }
585
586 void writeValue(int i, uint16_t* dstIndex) const {
587 *dstIndex = fIndices[i];
588 }
589
590private:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000591 const uint16_t* fIndices;
bsalomon@google.com19628322011-02-03 21:30:17 +0000592 int fCount;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000593};
594
595///////////////////////////////////////////////////////////////////////////////
596
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000597#if 0 // not currently being used so don't compile,
598
bsalomon@google.com5782d712011-01-21 21:03:59 +0000599// can be used for positions or texture coordinates
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000600
bsalomon@google.com5782d712011-01-21 21:03:59 +0000601class SkRectFanSource {
602public:
603 SkRectFanSource(const SkRect& rect) : fRect(rect) {}
604
605 int count() const { return 4; }
606
607 void writeValue(int i, GrPoint* dstPoint) const {
608 SkASSERT(i < 4);
609 dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
610 fRect.fLeft);
611 dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
612 fRect.fBottom);
613 }
614private:
615 const SkRect& fRect;
616};
617
618class SkIRectFanSource {
619public:
620 SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
621
622 int count() const { return 4; }
623
624 void writeValue(int i, GrPoint* dstPoint) const {
625 SkASSERT(i < 4);
626 dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
627 GrIntToScalar(fRect.fLeft);
628 dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
629 GrIntToScalar(fRect.fBottom);
630 }
631private:
632 const SkIRect& fRect;
633};
634
635class SkMatRectFanSource {
636public:
637 SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
638 : fRect(rect), fMatrix(matrix) {}
639
640 int count() const { return 4; }
641
642 void writeValue(int i, GrPoint* dstPoint) const {
643 SkASSERT(i < 4);
644
645#if SK_SCALAR_IS_GR_SCALAR
646 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
647 (i < 2) ? fRect.fTop : fRect.fBottom,
648 (SkPoint*)dstPoint);
649#else
650 SkPoint dst;
651 fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
652 (i < 2) ? fRect.fTop : fRect.fBottom,
653 &dst);
654 dstPoint->fX = SkScalarToGrScalar(dst.fX);
655 dstPoint->fY = SkScalarToGrScalar(dst.fY);
656#endif
657 }
658private:
659 const SkRect& fRect;
660 const SkMatrix& fMatrix;
661};
662
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000663#endif
664
reed@google.comac10a2d2010-12-22 21:39:39 +0000665///////////////////////////////////////////////////////////////////////////////
666
bsalomon@google.com398109c2011-04-14 18:40:27 +0000667void SkGpuDevice::clear(SkColor color) {
bsalomon@google.com31a58402011-04-27 21:00:02 +0000668 fContext->clear(NULL, color);
bsalomon@google.com398109c2011-04-14 18:40:27 +0000669}
670
reed@google.comac10a2d2010-12-22 21:39:39 +0000671void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
672 CHECK_SHOULD_DRAW(draw);
673
bsalomon@google.com5782d712011-01-21 21:03:59 +0000674 GrPaint grPaint;
675 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000676 if (!this->skPaint2GrPaintShader(paint,
677 &act,
678 *draw.fMatrix,
679 &grPaint,
680 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000681 return;
682 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000683
684 fContext->drawPaint(grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000685}
686
687// must be in SkCanvas::PointMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +0000688static const GrPrimitiveType gPointMode2PrimtiveType[] = {
689 kPoints_PrimitiveType,
690 kLines_PrimitiveType,
691 kLineStrip_PrimitiveType
reed@google.comac10a2d2010-12-22 21:39:39 +0000692};
693
694void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000695 size_t count, const SkPoint pts[], const SkPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000696 CHECK_SHOULD_DRAW(draw);
697
698 SkScalar width = paint.getStrokeWidth();
699 if (width < 0) {
700 return;
701 }
702
703 // we only handle hairlines here, else we let the SkDraw call our drawPath()
704 if (width > 0) {
705 draw.drawPoints(mode, count, pts, paint, true);
706 return;
707 }
708
bsalomon@google.com5782d712011-01-21 21:03:59 +0000709 GrPaint grPaint;
710 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000711 if (!this->skPaint2GrPaintShader(paint,
712 &act,
713 *draw.fMatrix,
714 &grPaint,
715 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000716 return;
717 }
718
reed@google.comac10a2d2010-12-22 21:39:39 +0000719#if SK_SCALAR_IS_GR_SCALAR
bsalomon@google.com5782d712011-01-21 21:03:59 +0000720 fContext->drawVertices(grPaint,
721 gPointMode2PrimtiveType[mode],
722 count,
723 (GrPoint*)pts,
724 NULL,
725 NULL,
726 NULL,
727 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000728#else
bsalomon@google.com5782d712011-01-21 21:03:59 +0000729 fContext->drawCustomVertices(grPaint,
730 gPointMode2PrimtiveType[mode],
731 SkPositionSource(pts, count));
reed@google.comac10a2d2010-12-22 21:39:39 +0000732#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000733}
734
reed@google.comc9aa5872011-04-05 21:05:37 +0000735///////////////////////////////////////////////////////////////////////////////
736
reed@google.comac10a2d2010-12-22 21:39:39 +0000737void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
738 const SkPaint& paint) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000739 CHECK_SHOULD_DRAW(draw);
740
741 bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
742 SkScalar width = paint.getStrokeWidth();
743
744 /*
745 We have special code for hairline strokes, miter-strokes, and fills.
746 Anything else we just call our path code.
747 */
748 bool usePath = doStroke && width > 0 &&
749 paint.getStrokeJoin() != SkPaint::kMiter_Join;
750 // another reason we might need to call drawPath...
751 if (paint.getMaskFilter()) {
752 usePath = true;
753 }
reed@google.com67db6642011-05-26 11:46:35 +0000754 // until we aa rotated rects...
755 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
756 usePath = true;
757 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000758
759 if (usePath) {
760 SkPath path;
761 path.addRect(rect);
762 this->drawPath(draw, path, paint, NULL, true);
763 return;
764 }
765
766 GrPaint grPaint;
767 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000768 if (!this->skPaint2GrPaintShader(paint,
769 &act,
770 *draw.fMatrix,
771 &grPaint,
772 true)) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000773 return;
774 }
reed@google.com20efde72011-05-09 17:00:02 +0000775 fContext->drawRect(grPaint, rect, doStroke ? width : -1);
reed@google.comac10a2d2010-12-22 21:39:39 +0000776}
777
reed@google.com69302852011-02-16 18:08:07 +0000778#include "SkMaskFilter.h"
779#include "SkBounder.h"
780
reed@google.com69302852011-02-16 18:08:07 +0000781static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
782 SkMaskFilter* filter, const SkMatrix& matrix,
783 const SkRegion& clip, SkBounder* bounder,
784 GrPaint* grp) {
785 SkMask srcM, dstM;
786
787 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM,
788 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
789 return false;
790 }
791
792 SkAutoMaskImage autoSrc(&srcM, false);
793
794 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
795 return false;
796 }
797 // this will free-up dstM when we're done (allocated in filterMask())
798 SkAutoMaskImage autoDst(&dstM, false);
799
800 if (clip.quickReject(dstM.fBounds)) {
801 return false;
802 }
803 if (bounder && !bounder->doIRect(dstM.fBounds)) {
804 return false;
805 }
806
807 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
808 // the current clip (and identity matrix) and grpaint settings
809
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000810 // used to compute inverse view, if necessary
811 GrMatrix ivm = context->getMatrix();
812
reed@google.com0c219b62011-02-16 21:31:18 +0000813 GrAutoMatrix avm(context, GrMatrix::I());
reed@google.com69302852011-02-16 18:08:07 +0000814
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000815 const GrTextureDesc desc = {
816 kNone_GrTextureFlags,
817 kNone_GrAALevel,
reed@google.com69302852011-02-16 18:08:07 +0000818 dstM.fBounds.width(),
819 dstM.fBounds.height(),
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000820 kAlpha_8_GrPixelConfig
reed@google.com69302852011-02-16 18:08:07 +0000821 };
822
823 GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
824 dstM.fRowBytes);
825 if (NULL == texture) {
826 return false;
827 }
828
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000829 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
830 grp->preConcatActiveSamplerMatrices(ivm);
831 }
832
833 static const int MASK_IDX = GrPaint::kMaxMasks - 1;
834 // we assume the last mask index is available for use
835 GrAssert(NULL == grp->getMask(MASK_IDX));
836 grp->setMask(MASK_IDX, texture);
reed@google.com0c219b62011-02-16 21:31:18 +0000837 texture->unref();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000838 grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
reed@google.com69302852011-02-16 18:08:07 +0000839
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000840 GrRect d;
841 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
reed@google.com0c219b62011-02-16 21:31:18 +0000842 GrIntToScalar(dstM.fBounds.fTop),
843 GrIntToScalar(dstM.fBounds.fRight),
844 GrIntToScalar(dstM.fBounds.fBottom));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000845
846 GrMatrix m;
847 m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
848 m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
849 grp->getMaskSampler(MASK_IDX)->setMatrix(m);
850
851 context->drawRect(*grp, d);
reed@google.com69302852011-02-16 18:08:07 +0000852 return true;
853}
reed@google.com69302852011-02-16 18:08:07 +0000854
reed@google.com0c219b62011-02-16 21:31:18 +0000855void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
reed@google.comac10a2d2010-12-22 21:39:39 +0000856 const SkPaint& paint, const SkMatrix* prePathMatrix,
857 bool pathIsMutable) {
858 CHECK_SHOULD_DRAW(draw);
859
bsalomon@google.com5782d712011-01-21 21:03:59 +0000860 GrPaint grPaint;
861 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +0000862 if (!this->skPaint2GrPaintShader(paint,
863 &act,
864 *draw.fMatrix,
865 &grPaint,
866 true)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000867 return;
868 }
869
reed@google.com0c219b62011-02-16 21:31:18 +0000870 // BEGIN lift from SkDraw::drawPath()
871
872 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
873 bool doFill = true;
874 SkPath tmpPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000875
876 if (prePathMatrix) {
reed@google.come3445642011-02-16 23:20:39 +0000877 SkPath* result = pathPtr;
reed@google.com0c219b62011-02-16 21:31:18 +0000878
reed@google.come3445642011-02-16 23:20:39 +0000879 if (!pathIsMutable) {
880 result = &tmpPath;
881 pathIsMutable = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000882 }
reed@google.come3445642011-02-16 23:20:39 +0000883 // should I push prePathMatrix on our MV stack temporarily, instead
884 // of applying it here? See SkDraw.cpp
885 pathPtr->transform(*prePathMatrix, result);
886 pathPtr = result;
reed@google.comac10a2d2010-12-22 21:39:39 +0000887 }
reed@google.com0c219b62011-02-16 21:31:18 +0000888 // at this point we're done with prePathMatrix
889 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
reed@google.comac10a2d2010-12-22 21:39:39 +0000890
bsalomon@google.com04de7822011-03-25 18:04:43 +0000891 // This "if" is not part of the SkDraw::drawPath() lift.
892 // When we get a 1.0 wide stroke we hairline stroke it instead of creating
893 // a new stroked-path. This is motivated by canvas2D sites that draw
894 // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
895 // hairline for width < 1.0 when AA is enabled.
896 static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
897 SkMatrix::kTranslate_Mask);
898 if (!paint.getPathEffect() &&
899 SkPaint::kStroke_Style == paint.getStyle() &&
900 !(draw.fMatrix->getType() & gMatrixMask) &&
901 SK_Scalar1 == paint.getStrokeWidth()) {
902 doFill = false;
903 }
904
905 if (doFill && (paint.getPathEffect() ||
906 paint.getStyle() != SkPaint::kFill_Style)) {
reed@google.com0c219b62011-02-16 21:31:18 +0000907 doFill = paint.getFillPath(*pathPtr, &tmpPath);
908 pathPtr = &tmpPath;
909 }
910
911 // END lift from SkDraw::drawPath()
912
reed@google.com69302852011-02-16 18:08:07 +0000913 if (paint.getMaskFilter()) {
reed@google.com0c219b62011-02-16 21:31:18 +0000914 // avoid possibly allocating a new path in transform if we can
915 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
916
917 // transform the path into device space
reed@google.come3445642011-02-16 23:20:39 +0000918 pathPtr->transform(*draw.fMatrix, devPathPtr);
reed@google.com0c219b62011-02-16 21:31:18 +0000919
920 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
reed@google.com69302852011-02-16 18:08:07 +0000921 *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
922 return;
923 }
reed@google.com69302852011-02-16 18:08:07 +0000924
bsalomon@google.comffca4002011-02-22 20:34:01 +0000925 GrPathFill fill = kHairLine_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000926
reed@google.com0c219b62011-02-16 21:31:18 +0000927 if (doFill) {
928 switch (pathPtr->getFillType()) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000929 case SkPath::kWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000930 fill = kWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000931 break;
932 case SkPath::kEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000933 fill = kEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000934 break;
935 case SkPath::kInverseWinding_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000936 fill = kInverseWinding_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000937 break;
938 case SkPath::kInverseEvenOdd_FillType:
bsalomon@google.comffca4002011-02-22 20:34:01 +0000939 fill = kInverseEvenOdd_PathFill;
reed@google.comac10a2d2010-12-22 21:39:39 +0000940 break;
941 default:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000942 SkDebugf("Unsupported path fill type\n");
reed@google.comac10a2d2010-12-22 21:39:39 +0000943 return;
944 }
945 }
946
reed@google.com07f3ee12011-05-16 17:21:57 +0000947 fContext->drawPath(grPaint, *pathPtr, fill);
reed@google.comac10a2d2010-12-22 21:39:39 +0000948}
949
reed@google.comac10a2d2010-12-22 21:39:39 +0000950void SkGpuDevice::drawBitmap(const SkDraw& draw,
951 const SkBitmap& bitmap,
952 const SkIRect* srcRectPtr,
953 const SkMatrix& m,
954 const SkPaint& paint) {
955 CHECK_SHOULD_DRAW(draw);
956
957 SkIRect srcRect;
958 if (NULL == srcRectPtr) {
959 srcRect.set(0, 0, bitmap.width(), bitmap.height());
960 } else {
961 srcRect = *srcRectPtr;
962 }
963
junov@google.comd935cfb2011-06-27 20:48:23 +0000964 if (paint.getMaskFilter()){
junov@google.com22c8bb82011-06-30 22:16:06 +0000965 SkBitmap tmpBitmap; // local copy of bitmap
junov@google.comd935cfb2011-06-27 20:48:23 +0000966 const SkBitmap* bitmapPtr = &bitmap;
junov@google.com22c8bb82011-06-30 22:16:06 +0000967
968 // FIXME : texture-backed bitmaps not yet supported
969 SkAutoLockPixels alp(bitmap);
970 if (!bitmap.getPixels())
971 return;
972
973 // A temporary copy of the bitmap may be necessary
974 // to prevent color bleeding if a sub rect is used
975 if (NULL != srcRectPtr) {
976 tmpBitmap.setConfig(bitmap.config(), srcRect.width(),
977 srcRect.height());
978
979 size_t pixelOffset = srcRect.fTop * bitmap.rowBytes()
980 + srcRect.fLeft * bitmap.bytesPerPixel();
981 tmpBitmap.copyPixelsFrom(
982 (uint8_t*)bitmap.getPixels() + pixelOffset,
983 bitmap.getSafeSize() - pixelOffset,
984 bitmap.rowBytes());
985
986 bitmapPtr = &tmpBitmap;
junov@google.comd935cfb2011-06-27 20:48:23 +0000987 }
junov@google.com22c8bb82011-06-30 22:16:06 +0000988
junov@google.comd935cfb2011-06-27 20:48:23 +0000989 SkPaint paintWithTexture(paint);
990 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
991 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
992 paintWithTexture.getShader()->setLocalMatrix(m);
993
994 SkRect ScalarRect;
junov@google.com22c8bb82011-06-30 22:16:06 +0000995 ScalarRect.setXYWH(0, 0, srcRect.width(), srcRect.height());
junov@google.comd935cfb2011-06-27 20:48:23 +0000996
junov@google.com22c8bb82011-06-30 22:16:06 +0000997 // Transform 'm' must be applied globally so that it will
998 // affect the blur radius.
999 SkMatrix matrix = *draw.fMatrix;
1000 matrix.preConcat(m);
1001 SkDraw myDraw(draw);
1002 myDraw.fMatrix = &matrix;
1003
1004 this->drawRect(myDraw, ScalarRect, paintWithTexture);
junov@google.comd935cfb2011-06-27 20:48:23 +00001005 return;
1006 }
1007
bsalomon@google.com5782d712011-01-21 21:03:59 +00001008 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001009 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001010 return;
1011 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001012 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001013 if (paint.isFilterBitmap()) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001014 sampler->setFilter(GrSamplerState::kBilinear_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001015 } else {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001016 sampler->setFilter(GrSamplerState::kNearest_Filter);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +00001017 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001018
bsalomon@google.com91958362011-06-13 17:58:13 +00001019 const int maxTextureSize = fContext->getMaxTextureSize();
1020 if (bitmap.getTexture() || (bitmap.width() <= maxTextureSize &&
1021 bitmap.height() <= maxTextureSize)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001022 // take the fast case
bsalomon@google.com5782d712011-01-21 21:03:59 +00001023 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001024 return;
1025 }
1026
1027 // undo the translate done by SkCanvas
1028 int DX = SkMax32(0, srcRect.fLeft);
1029 int DY = SkMax32(0, srcRect.fTop);
1030 // compute clip bounds in local coordinates
1031 SkIRect clipRect;
1032 {
1033 SkRect r;
1034 r.set(draw.fClip->getBounds());
1035 SkMatrix matrix, inverse;
1036 matrix.setConcat(*draw.fMatrix, m);
1037 if (!matrix.invert(&inverse)) {
1038 return;
1039 }
1040 inverse.mapRect(&r);
1041 r.roundOut(&clipRect);
1042 // apply the canvas' translate to our local clip
1043 clipRect.offset(DX, DY);
1044 }
1045
bsalomon@google.com91958362011-06-13 17:58:13 +00001046 int nx = bitmap.width() / maxTextureSize;
1047 int ny = bitmap.height() / maxTextureSize;
reed@google.comac10a2d2010-12-22 21:39:39 +00001048 for (int x = 0; x <= nx; x++) {
1049 for (int y = 0; y <= ny; y++) {
1050 SkIRect tileR;
bsalomon@google.com91958362011-06-13 17:58:13 +00001051 tileR.set(x * maxTextureSize, y * maxTextureSize,
1052 (x + 1) * maxTextureSize, (y + 1) * maxTextureSize);
reed@google.comac10a2d2010-12-22 21:39:39 +00001053 if (!SkIRect::Intersects(tileR, clipRect)) {
1054 continue;
1055 }
1056
1057 SkIRect srcR = tileR;
1058 if (!srcR.intersect(srcRect)) {
1059 continue;
1060 }
1061
1062 SkBitmap tmpB;
1063 if (bitmap.extractSubset(&tmpB, tileR)) {
1064 // now offset it to make it "local" to our tmp bitmap
1065 srcR.offset(-tileR.fLeft, -tileR.fTop);
1066
1067 SkMatrix tmpM(m);
1068 {
1069 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
1070 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
1071 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
1072 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001073 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +00001074 }
1075 }
1076 }
1077}
1078
1079/*
1080 * This is called by drawBitmap(), which has to handle images that may be too
1081 * large to be represented by a single texture.
1082 *
bsalomon@google.com5782d712011-01-21 21:03:59 +00001083 * internalDrawBitmap assumes that the specified bitmap will fit in a texture
1084 * and that non-texture portion of the GrPaint has already been setup.
reed@google.comac10a2d2010-12-22 21:39:39 +00001085 */
1086void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
1087 const SkBitmap& bitmap,
1088 const SkIRect& srcRect,
1089 const SkMatrix& m,
bsalomon@google.com5782d712011-01-21 21:03:59 +00001090 GrPaint* grPaint) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001091 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
1092 bitmap.height() <= fContext->getMaxTextureSize());
reed@google.comac10a2d2010-12-22 21:39:39 +00001093
1094 SkAutoLockPixels alp(bitmap);
1095 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1096 return;
1097 }
1098
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001099 GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
1100
1101 sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
1102 sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
1103 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
1104 sampler->setMatrix(GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +00001105
1106 GrTexture* texture;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001107 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
reed@google.comac10a2d2010-12-22 21:39:39 +00001108 if (NULL == texture) {
1109 return;
1110 }
1111
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001112 grPaint->setTexture(kShaderTextureIdx, texture);
reed@google.com46799cd2011-02-22 20:56:26 +00001113
reed@google.com20efde72011-05-09 17:00:02 +00001114 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
1115 GrIntToScalar(srcRect.height()));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001116 GrRect paintRect;
junov@google.com6acc9b32011-05-16 18:32:07 +00001117 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()),
1118 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()),
1119 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()),
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001120 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height()));
reed@google.comac10a2d2010-12-22 21:39:39 +00001121
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001122 if (GrSamplerState::kNearest_Filter != sampler->getFilter() &&
junov@google.com6acc9b32011-05-16 18:32:07 +00001123 (srcRect.width() < bitmap.width() ||
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001124 srcRect.height() < bitmap.height())) {
junov@google.com6acc9b32011-05-16 18:32:07 +00001125 // If drawing a subrect of the bitmap and filtering is enabled,
1126 // use a constrained texture domain to avoid color bleeding
1127 GrScalar left, top, right, bottom;
1128 if (srcRect.width() > 1) {
1129 GrScalar border = GR_ScalarHalf / bitmap.width();
1130 left = paintRect.left() + border;
1131 right = paintRect.right() - border;
1132 } else {
1133 left = right = GrScalarHalf(paintRect.left() + paintRect.right());
1134 }
1135 if (srcRect.height() > 1) {
1136 GrScalar border = GR_ScalarHalf / bitmap.height();
1137 top = paintRect.top() + border;
1138 bottom = paintRect.bottom() - border;
1139 } else {
1140 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
1141 }
1142 GrRect textureDomain;
1143 textureDomain.setLTRB(left, top, right, bottom);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001144 sampler->setTextureDomain(textureDomain);
junov@google.com6acc9b32011-05-16 18:32:07 +00001145 }
1146
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001147 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001148}
1149
1150void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
1151 int left, int top, const SkPaint& paint) {
1152 CHECK_SHOULD_DRAW(draw);
1153
1154 SkAutoLockPixels alp(bitmap);
1155 if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
1156 return;
1157 }
1158
bsalomon@google.com5782d712011-01-21 21:03:59 +00001159 GrPaint grPaint;
Scroggod757df22011-05-16 13:11:16 +00001160 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001161 return;
1162 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001163
bsalomon@google.com5782d712011-01-21 21:03:59 +00001164 GrAutoMatrix avm(fContext, GrMatrix::I());
1165
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001166 GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001167
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001168 GrTexture* texture;
1169 sampler->setClampNoFilter();
1170 SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
1171
1172 grPaint.setTexture(kBitmapTextureIdx, texture);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001173
bsalomon@google.com5782d712011-01-21 21:03:59 +00001174 fContext->drawRectToRect(grPaint,
reed@google.com20efde72011-05-09 17:00:02 +00001175 GrRect::MakeXYWH(GrIntToScalar(left),
1176 GrIntToScalar(top),
1177 GrIntToScalar(bitmap.width()),
1178 GrIntToScalar(bitmap.height())),
1179 GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
reed@google.comac10a2d2010-12-22 21:39:39 +00001180}
1181
1182void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
1183 int x, int y, const SkPaint& paint) {
1184 CHECK_SHOULD_DRAW(draw);
1185
bsalomon@google.com5782d712011-01-21 21:03:59 +00001186 GrPaint grPaint;
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001187 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) ||
Scroggod757df22011-05-16 13:11:16 +00001188 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001189 return;
reed@google.comac10a2d2010-12-22 21:39:39 +00001190 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001191
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001192 GrTexture* devTex = grPaint.getTexture(0);
1193 SkASSERT(NULL != devTex);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001194
1195 const SkBitmap& bm = dev->accessBitmap(false);
1196 int w = bm.width();
1197 int h = bm.height();
1198
1199 GrAutoMatrix avm(fContext, GrMatrix::I());
1200
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001201 grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
bsalomon@google.com5782d712011-01-21 21:03:59 +00001202
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001203 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
1204 GrIntToScalar(y),
1205 GrIntToScalar(w),
1206 GrIntToScalar(h));
1207 // The device being drawn may not fill up its texture (saveLayer uses
1208 // the approximate ).
1209 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
1210 GR_Scalar1 * h / devTex->height());
1211
1212 fContext->drawRectToRect(grPaint, dstRect, srcRect);
reed@google.comac10a2d2010-12-22 21:39:39 +00001213}
1214
1215///////////////////////////////////////////////////////////////////////////////
1216
1217// must be in SkCanvas::VertexMode order
bsalomon@google.comffca4002011-02-22 20:34:01 +00001218static const GrPrimitiveType gVertexMode2PrimitiveType[] = {
1219 kTriangles_PrimitiveType,
1220 kTriangleStrip_PrimitiveType,
1221 kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +00001222};
1223
1224void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
1225 int vertexCount, const SkPoint vertices[],
1226 const SkPoint texs[], const SkColor colors[],
1227 SkXfermode* xmode,
1228 const uint16_t indices[], int indexCount,
1229 const SkPaint& paint) {
1230 CHECK_SHOULD_DRAW(draw);
1231
bsalomon@google.com5782d712011-01-21 21:03:59 +00001232 GrPaint grPaint;
1233 SkAutoCachedTexture act;
1234 // we ignore the shader if texs is null.
1235 if (NULL == texs) {
Scroggod757df22011-05-16 13:11:16 +00001236 if (!this->skPaint2GrPaintNoShader(paint,
1237 false,
1238 &grPaint,
1239 NULL == colors)) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001240 return;
1241 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001242 } else {
reed@google.com1a2e8d22011-01-21 22:08:29 +00001243 if (!this->skPaint2GrPaintShader(paint, &act,
1244 *draw.fMatrix,
Scroggod757df22011-05-16 13:11:16 +00001245 &grPaint,
1246 NULL == colors)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001247 return;
1248 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001249 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001250
1251 if (NULL != xmode && NULL != texs && NULL != colors) {
1252 SkXfermode::Mode mode;
1253 if (!SkXfermode::IsMode(xmode, &mode) ||
1254 SkXfermode::kMultiply_Mode != mode) {
1255 SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
1256#if 0
1257 return
1258#endif
1259 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001260 }
bsalomon@google.com5782d712011-01-21 21:03:59 +00001261
1262#if SK_SCALAR_IS_GR_SCALAR
1263 // even if GrColor and SkColor byte offsets match we need
1264 // to perform pre-multiply.
1265 if (NULL == colors) {
1266 fContext->drawVertices(grPaint,
1267 gVertexMode2PrimitiveType[vmode],
1268 vertexCount,
1269 (GrPoint*) vertices,
1270 (GrPoint*) texs,
1271 NULL,
1272 indices,
1273 indexCount);
1274 } else
1275#endif
1276 {
1277 SkTexCoordSource texSrc(texs);
1278 SkColorSource colSrc(colors);
1279 SkIndexSource idxSrc(indices, indexCount);
1280
1281 fContext->drawCustomVertices(grPaint,
1282 gVertexMode2PrimitiveType[vmode],
1283 SkPositionSource(vertices, vertexCount),
1284 (NULL == texs) ? NULL : &texSrc,
1285 (NULL == colors) ? NULL : &colSrc,
1286 (NULL == indices) ? NULL : &idxSrc);
reed@google.comac10a2d2010-12-22 21:39:39 +00001287 }
1288}
1289
1290///////////////////////////////////////////////////////////////////////////////
1291
1292static void GlyphCacheAuxProc(void* data) {
1293 delete (GrFontScaler*)data;
1294}
1295
1296static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
1297 void* auxData;
1298 GrFontScaler* scaler = NULL;
1299 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
1300 scaler = (GrFontScaler*)auxData;
1301 }
1302 if (NULL == scaler) {
1303 scaler = new SkGrFontScaler(cache);
1304 cache->setAuxProc(GlyphCacheAuxProc, scaler);
1305 }
1306 return scaler;
1307}
1308
1309static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
1310 SkFixed fx, SkFixed fy,
1311 const SkGlyph& glyph) {
1312 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1313
1314 GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
1315
1316 if (NULL == procs->fFontScaler) {
1317 procs->fFontScaler = get_gr_font_scaler(state.fCache);
1318 }
reed@google.com39ce0ac2011-04-08 15:42:19 +00001319
1320 /*
reed@google.com3b139f52011-06-07 17:56:25 +00001321 * What should we do with fy? (assuming horizontal/latin text)
reed@google.com39ce0ac2011-04-08 15:42:19 +00001322 *
reed@google.com3b139f52011-06-07 17:56:25 +00001323 * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
1324 * It calls that rather than round, because our caller has already added
1325 * SK_FixedHalf, so that calling floor gives us the rounded integer.
1326 *
1327 * Test code between raster and gpu (they should draw the same)
1328 *
1329 * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
1330 *
1331 * Perhaps we should only perform this integralization if there is no
1332 * fExtMatrix...
reed@google.com39ce0ac2011-04-08 15:42:19 +00001333 */
reed@google.com3b139f52011-06-07 17:56:25 +00001334 fy = SkFixedFloorToFixed(fy);
1335
reed@google.comac10a2d2010-12-22 21:39:39 +00001336 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
reed@google.com3b139f52011-06-07 17:56:25 +00001337 SkFixedFloorToFixed(fx), fy,
reed@google.comac10a2d2010-12-22 21:39:39 +00001338 procs->fFontScaler);
1339}
1340
bsalomon@google.com5782d712011-01-21 21:03:59 +00001341SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001342
1343 // deferred allocation
1344 if (NULL == fDrawProcs) {
1345 fDrawProcs = new GrSkDrawProcs;
1346 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
1347 fDrawProcs->fContext = fContext;
1348 }
1349
1350 // init our (and GL's) state
1351 fDrawProcs->fTextContext = context;
1352 fDrawProcs->fFontScaler = NULL;
1353 return fDrawProcs;
1354}
1355
1356void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
1357 size_t byteLength, SkScalar x, SkScalar y,
1358 const SkPaint& paint) {
1359 CHECK_SHOULD_DRAW(draw);
1360
1361 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1362 // this guy will just call our drawPath()
1363 draw.drawText((const char*)text, byteLength, x, y, paint);
1364 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001365 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001366
1367 GrPaint grPaint;
1368 SkAutoCachedTexture act;
1369
Scroggod757df22011-05-16 13:11:16 +00001370 if (!this->skPaint2GrPaintShader(paint,
1371 &act,
1372 *draw.fMatrix,
1373 &grPaint,
1374 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001375 return;
1376 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001377 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001378 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001379 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
1380 }
1381}
1382
1383void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
1384 size_t byteLength, const SkScalar pos[],
1385 SkScalar constY, int scalarsPerPos,
1386 const SkPaint& paint) {
1387 CHECK_SHOULD_DRAW(draw);
1388
1389 if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
1390 // this guy will just call our drawPath()
1391 draw.drawPosText((const char*)text, byteLength, pos, constY,
1392 scalarsPerPos, paint);
1393 } else {
reed@google.comac10a2d2010-12-22 21:39:39 +00001394 SkDraw myDraw(draw);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001395
1396 GrPaint grPaint;
1397 SkAutoCachedTexture act;
Scroggod757df22011-05-16 13:11:16 +00001398 if (!this->skPaint2GrPaintShader(paint,
1399 &act,
1400 *draw.fMatrix,
1401 &grPaint,
1402 true)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001403 return;
1404 }
1405
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001406 GrTextContext context(fContext, grPaint, draw.fExtMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001407 myDraw.fProcs = this->initDrawForText(&context);
reed@google.comac10a2d2010-12-22 21:39:39 +00001408 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
1409 scalarsPerPos, paint);
1410 }
1411}
1412
1413void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
1414 size_t len, const SkPath& path,
1415 const SkMatrix* m, const SkPaint& paint) {
1416 CHECK_SHOULD_DRAW(draw);
1417
1418 SkASSERT(draw.fDevice == this);
1419 draw.drawTextOnPath((const char*)text, len, path, m, paint);
1420}
1421
1422///////////////////////////////////////////////////////////////////////////////
1423
reed@google.comf67e4cf2011-03-15 20:56:58 +00001424bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
1425 if (!paint.isLCDRenderText()) {
1426 // we're cool with the paint as is
1427 return false;
1428 }
1429
1430 if (paint.getShader() ||
1431 paint.getXfermode() || // unless its srcover
1432 paint.getMaskFilter() ||
1433 paint.getRasterizer() ||
1434 paint.getColorFilter() ||
1435 paint.getPathEffect() ||
1436 paint.isFakeBoldText() ||
1437 paint.getStyle() != SkPaint::kFill_Style) {
1438 // turn off lcd
1439 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
1440 flags->fHinting = paint.getHinting();
1441 return true;
1442 }
1443 // we're cool with the paint as is
1444 return false;
1445}
1446
1447///////////////////////////////////////////////////////////////////////////////
1448
reed@google.comac10a2d2010-12-22 21:39:39 +00001449SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001450 const GrSamplerState& sampler,
1451 GrTexture** texture,
bsalomon@google.come97f0852011-06-17 13:10:25 +00001452 TexType type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001453 GrTexture* newTexture = NULL;
1454 GrTextureEntry* entry = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +00001455 GrContext* ctx = this->context();
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001456
bsalomon@google.come97f0852011-06-17 13:10:25 +00001457 if (kBitmap_TexType != type) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001458 const GrTextureDesc desc = {
1459 kRenderTarget_GrTextureFlagBit,
1460 kNone_GrAALevel,
1461 bitmap.width(),
1462 bitmap.height(),
1463 SkGr::Bitmap2PixelConfig(bitmap)
1464 };
bsalomon@google.come97f0852011-06-17 13:10:25 +00001465 if (kSaveLayerDeviceRenderTarget_TexType == type) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001466 // we know layers will only be drawn through drawDevice.
1467 // drawDevice has been made to work with content embedded in a
1468 // larger texture so its okay to use the approximate version.
1469 entry = ctx->findApproximateKeylessTexture(desc);
1470 } else {
bsalomon@google.come97f0852011-06-17 13:10:25 +00001471 SkASSERT(kDeviceRenderTarget_TexType == type);
bsalomon@google.comb5b31682011-06-16 18:05:35 +00001472 entry = ctx->lockKeylessTexture(desc);
1473 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001474 } else {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001475 if (!bitmap.isVolatile()) {
1476 uint32_t p0, p1;
1477 p0 = bitmap.getGenerationID();
1478 p1 = bitmap.pixelRefOffset();
1479 GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
1480
1481 entry = ctx->findAndLockTexture(&key, sampler);
1482 if (NULL == entry)
1483 entry = sk_gr_create_bitmap_texture(ctx, &key, sampler,
1484 bitmap);
1485 } else {
1486 entry = sk_gr_create_bitmap_texture(ctx, NULL, sampler, bitmap);
1487 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001488 if (NULL == entry) {
junov@google.com4ee7ae52011-06-30 17:30:49 +00001489 GrPrintf("---- failed to create texture for cache [%d %d]\n",
1490 bitmap.width(), bitmap.height());
reed@google.comac10a2d2010-12-22 21:39:39 +00001491 }
1492 }
1493
1494 if (NULL != entry) {
1495 newTexture = entry->texture();
reed@google.comac10a2d2010-12-22 21:39:39 +00001496 if (texture) {
1497 *texture = newTexture;
1498 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001499 }
1500 return (TexCache*)entry;
1501}
1502
1503void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
1504 this->context()->unlockTexture((GrTextureEntry*)cache);
1505}
1506
bsalomon@google.come97f0852011-06-17 13:10:25 +00001507SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
1508 int width, int height,
1509 bool isOpaque,
1510 Usage usage) {
1511 return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
1512 width, height, usage));
1513}
1514
1515
reed@google.com7b201d22011-01-11 18:59:23 +00001516///////////////////////////////////////////////////////////////////////////////
1517
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001518SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001519 GrRenderTarget* rootRenderTarget) {
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001520 GrAssert(NULL != context);
1521 GrAssert(NULL != rootRenderTarget);
1522
1523 // check this now rather than passing this value to SkGpuDevice cons.
1524 // we want the rt that is bound *now* in the 3D API, not the one
1525 // at the time of newDevice.
1526 if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
1527 fRootRenderTarget = context->createRenderTargetFrom3DApiState();
1528 } else {
1529 fRootRenderTarget = rootRenderTarget;
1530 rootRenderTarget->ref();
1531 }
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001532
1533 fContext = context;
reed@google.com7b201d22011-01-11 18:59:23 +00001534 context->ref();
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001535
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001536 fRootTexture = NULL;
1537}
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001538
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001539SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
1540 GrAssert(NULL != context);
1541 GrAssert(NULL != rootRenderTargetTexture);
1542 GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
1543
1544 fRootTexture = rootRenderTargetTexture;
1545 rootRenderTargetTexture->ref();
1546
1547 fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
1548 fRootRenderTarget->ref();
1549
bsalomon@google.comea2ee8a2011-04-12 17:58:39 +00001550 fContext = context;
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001551 context->ref();
reed@google.com7b201d22011-01-11 18:59:23 +00001552}
1553
1554SkGpuDeviceFactory::~SkGpuDeviceFactory() {
1555 fContext->unref();
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +00001556 fRootRenderTarget->unref();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +00001557 GrSafeUnref(fRootTexture);
reed@google.com7b201d22011-01-11 18:59:23 +00001558}
1559
1560SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
1561 int width, int height,
1562 bool isOpaque, bool isLayer) {
reed@google.comaf951c92011-06-16 19:10:39 +00001563 if (isLayer) {
1564 return SkNEW_ARGS(SkGpuDevice, (fContext, config, width, height));
1565 } else {
1566 return SkNEW_ARGS(SkGpuDevice, (fContext, fRootRenderTarget));
1567 }
reed@google.com7b201d22011-01-11 18:59:23 +00001568}
bsalomon@google.come97f0852011-06-17 13:10:25 +00001569