blob: aaf2ae462bed18d6be8e8ea3732841dad5df2bef [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000014#include "effects/GrConvolutionEffect.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000015#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrIndexBuffer.h"
17#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000018#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000019#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000020#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000021#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000022#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000023#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000024#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000025
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000026#define DEFER_TEXT_RENDERING 1
bsalomon@google.com27847de2011-02-22 20:59:41 +000027
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000028#define DEFER_PATHS 1
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000029
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000030#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
bsalomon@google.com27847de2011-02-22 20:59:41 +000031
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000032#define MAX_BLUR_SIGMA 4.0f
33
bsalomon@google.comd46e2422011-09-23 17:40:07 +000034// When we're using coverage AA but the blend is incompatible (given gpu
35// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000036#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000037
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000038static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
39static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000040
bsalomon@google.com60361492012-03-15 17:47:06 +000041static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000042static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
43
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000044// path rendering is the only thing we defer today that uses non-static indices
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000047
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000073 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com30085192011-08-19 15:42:31 +000086 // a path renderer may be holding onto resources that
87 // are now unusable
88 GrSafeSetNull(fPathRendererChain);
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 delete fDrawBuffer;
91 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000092
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 delete fDrawBufferVBAllocPool;
94 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000095
bsalomon@google.com8fe72472011-03-30 21:26:44 +000096 delete fDrawBufferIBAllocPool;
97 fDrawBufferIBAllocPool = NULL;
98
bsalomon@google.com205d4602011-04-25 12:43:45 +000099 GrSafeSetNull(fAAFillRectIndexBuffer);
100 GrSafeSetNull(fAAStrokeRectIndexBuffer);
101
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102 fTextureCache->removeAll();
103 fFontCache->freeAll();
104 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105}
106
107void GrContext::resetContext() {
108 fGpu->markContextDirty();
109}
110
111void GrContext::freeGpuResources() {
112 this->flush();
robertphillips@google.comff175842012-05-14 19:31:39 +0000113
114 fGpu->purgeResources();
115
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000116 fTextureCache->removeAll();
117 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000118 // a path renderer may be holding onto resources
119 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000120}
121
twiz@google.com05e70242012-01-27 19:12:00 +0000122size_t GrContext::getGpuTextureCacheBytes() const {
123 return fTextureCache->getCachedResourceBytes();
124}
125
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000126////////////////////////////////////////////////////////////////////////////////
127
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000128int GrContext::PaintStageVertexLayoutBits(
129 const GrPaint& paint,
130 const bool hasTexCoords[GrPaint::kTotalStages]) {
131 int stageMask = paint.getActiveStageMask();
132 int layout = 0;
133 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
134 if ((1 << i) & stageMask) {
135 if (NULL != hasTexCoords && hasTexCoords[i]) {
136 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
137 } else {
138 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
139 }
140 }
141 }
142 return layout;
143}
144
145
146////////////////////////////////////////////////////////////////////////////////
147
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000148enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000149 // flags for textures
150 kNPOTBit = 0x1,
151 kFilterBit = 0x2,
152 kScratchBit = 0x4,
153
154 // resource type
155 kTextureBit = 0x8,
156 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000157};
158
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000159GrTexture* GrContext::TextureCacheEntry::texture() const {
160 if (NULL == fEntry) {
161 return NULL;
162 } else {
163 return (GrTexture*) fEntry->resource();
164 }
165}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000166
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000167namespace {
168// returns true if this is a "special" texture because of gpu NPOT limitations
169bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000170 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000171 GrContext::TextureKey clientKey,
172 int width,
173 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000174 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000175 bool scratch,
176 uint32_t v[4]) {
177 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
178 // we assume we only need 16 bits of width and height
179 // assert that texture creation will fail anyway if this assumption
180 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000181 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000182 v[0] = clientKey & 0xffffffffUL;
183 v[1] = (clientKey >> 32) & 0xffffffffUL;
184 v[2] = width | (height << 16);
185
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000186 v[3] = (sampleCnt << 24);
187 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
188
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000189 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000190 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
191
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000192 bool tiled = NULL != sampler &&
193 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
194 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195
196 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000197 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000198 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000200 }
201 }
202 }
203
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000204 if (scratch) {
205 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000206 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000207
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000208 v[3] |= kTextureBit;
209
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000210 return v[3] & kNPOTBit;
211}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000212
213// we should never have more than one stencil buffer with same combo of
214// (width,height,samplecount)
215void gen_stencil_key_values(int width, int height,
216 int sampleCnt, uint32_t v[4]) {
217 v[0] = width;
218 v[1] = height;
219 v[2] = sampleCnt;
220 v[3] = kStencilBufferBit;
221}
222
223void gen_stencil_key_values(const GrStencilBuffer* sb,
224 uint32_t v[4]) {
225 gen_stencil_key_values(sb->width(), sb->height(),
226 sb->numSamples(), v);
227}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000228
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000229void build_kernel(float sigma, float* kernel, int kernelWidth) {
230 int halfWidth = (kernelWidth - 1) / 2;
231 float sum = 0.0f;
232 float denom = 1.0f / (2.0f * sigma * sigma);
233 for (int i = 0; i < kernelWidth; ++i) {
234 float x = static_cast<float>(i - halfWidth);
235 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
236 // is dropped here, since we renormalize the kernel below.
237 kernel[i] = sk_float_exp(- x * x * denom);
238 sum += kernel[i];
239 }
240 // Normalize the kernel
241 float scale = 1.0f / sum;
242 for (int i = 0; i < kernelWidth; ++i)
243 kernel[i] *= scale;
244}
245
246void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000247 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
248 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
249 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
250 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000251}
252
253float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
254 int *kernelWidth) {
255 *scaleFactor = 1;
256 while (sigma > MAX_BLUR_SIGMA) {
257 *scaleFactor *= 2;
258 sigma *= 0.5f;
259 }
260 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
261 *kernelWidth = *halfWidth * 2 + 1;
262 return sigma;
263}
264
265void apply_morphology(GrGpu* gpu,
266 GrTexture* texture,
267 const SkRect& rect,
268 int radius,
269 GrSamplerState::Filter filter,
270 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000271 GrAssert(filter == GrSamplerState::kErode_Filter ||
272 filter == GrSamplerState::kDilate_Filter);
273
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000274 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
275 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000276 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000277 drawState->setRenderTarget(target);
278 GrMatrix sampleM;
279 sampleM.setIDiv(texture->width(), texture->height());
280 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
281 sampleM);
282 drawState->sampler(0)->setMorphologyRadius(radius);
283 drawState->sampler(0)->setFilterDirection(direction);
284 drawState->setTexture(0, texture);
285 gpu->drawSimpleRect(rect, NULL, 1 << 0);
286}
287
288void convolve(GrGpu* gpu,
289 GrTexture* texture,
290 const SkRect& rect,
291 const float* kernel,
292 int kernelWidth,
293 GrSamplerState::FilterDirection direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000294 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
295 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000296 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000297 drawState->setRenderTarget(target);
298 GrMatrix sampleM;
299 sampleM.setIDiv(texture->width(), texture->height());
300 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
301 GrSamplerState::kConvolution_Filter,
302 sampleM);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000303 drawState->sampler(0)->setCustomStage(
304 new GrConvolutionEffect(direction, kernelWidth, kernel));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000305 drawState->setTexture(0, texture);
306 gpu->drawSimpleRect(rect, NULL, 1 << 0);
307}
308
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000309}
310
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000311GrContext::TextureCacheEntry GrContext::findAndLockTexture(
312 TextureKey key,
313 int width,
314 int height,
315 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000316 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000317 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000318 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000319 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
320 GrResourceCache::kNested_LockType));
321}
322
bsalomon@google.comfb309512011-11-30 14:13:48 +0000323bool GrContext::isTextureInCache(TextureKey key,
324 int width,
325 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000326 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000327 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000328 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000329 GrResourceKey resourceKey(v);
330 return fTextureCache->hasKey(resourceKey);
331}
332
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000333GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000334 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000335 uint32_t v[4];
336 gen_stencil_key_values(sb, v);
337 GrResourceKey resourceKey(v);
338 return fTextureCache->createAndLock(resourceKey, sb);
339}
340
341GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
342 int sampleCnt) {
343 uint32_t v[4];
344 gen_stencil_key_values(width, height, sampleCnt, v);
345 GrResourceKey resourceKey(v);
346 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
347 GrResourceCache::kSingle_LockType);
348 if (NULL != entry) {
349 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
350 return sb;
351 } else {
352 return NULL;
353 }
354}
355
356void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000357 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000358 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000359}
360
361static void stretchImage(void* dst,
362 int dstW,
363 int dstH,
364 void* src,
365 int srcW,
366 int srcH,
367 int bpp) {
368 GrFixed dx = (srcW << 16) / dstW;
369 GrFixed dy = (srcH << 16) / dstH;
370
371 GrFixed y = dy >> 1;
372
373 int dstXLimit = dstW*bpp;
374 for (int j = 0; j < dstH; ++j) {
375 GrFixed x = dx >> 1;
376 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
377 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
378 for (int i = 0; i < dstXLimit; i += bpp) {
379 memcpy((uint8_t*) dstRow + i,
380 (uint8_t*) srcRow + (x>>16)*bpp,
381 bpp);
382 x += dx;
383 }
384 y += dy;
385 }
386}
387
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000388GrContext::TextureCacheEntry GrContext::createAndLockTexture(
389 TextureKey key,
390 const GrSamplerState* sampler,
391 const GrTextureDesc& desc,
392 void* srcData,
393 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000394 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000395
396#if GR_DUMP_TEXTURE_UPLOAD
397 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
398#endif
399
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000400 TextureCacheEntry entry;
401 uint32_t v[4];
402 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000403 desc.fWidth, desc.fHeight,
404 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000405 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000406
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000407 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000408 GrAssert(NULL != sampler);
409 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
410 desc.fWidth,
411 desc.fHeight,
412 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000413
414 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000415 clampEntry = this->createAndLockTexture(key, NULL, desc,
416 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000417 GrAssert(NULL != clampEntry.texture());
418 if (NULL == clampEntry.texture()) {
419 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000420 }
421 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000422 GrTextureDesc rtDesc = desc;
423 rtDesc.fFlags = rtDesc.fFlags |
424 kRenderTarget_GrTextureFlagBit |
425 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000426 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
427 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000428
429 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
430
431 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000432 GrDrawTarget::AutoStateRestore asr(fGpu,
433 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000434 GrDrawState* drawState = fGpu->drawState();
435 drawState->setRenderTarget(texture->asRenderTarget());
436 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000437
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000438 GrSamplerState::Filter filter;
439 // if filtering is not desired then we want to ensure all
440 // texels in the resampled image are copies of texels from
441 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000442 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000443 filter = GrSamplerState::kNearest_Filter;
444 } else {
445 filter = GrSamplerState::kBilinear_Filter;
446 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000447 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
448 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000449
450 static const GrVertexLayout layout =
451 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
452 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
453
454 if (arg.succeeded()) {
455 GrPoint* verts = (GrPoint*) arg.vertices();
456 verts[0].setIRectFan(0, 0,
457 texture->width(),
458 texture->height(),
459 2*sizeof(GrPoint));
460 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
461 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
462 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000463 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000464 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000465 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000466 } else {
467 // TODO: Our CPU stretch doesn't filter. But we create separate
468 // stretched textures when the sampler state is either filtered or
469 // not. Either implement filtered stretch blit on CPU or just create
470 // one when FBO case fails.
471
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000472 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000473 // no longer need to clamp at min RT size.
474 rtDesc.fWidth = GrNextPow2(desc.fWidth);
475 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000476 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000477 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000478 rtDesc.fWidth *
479 rtDesc.fHeight);
480 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
481 srcData, desc.fWidth, desc.fHeight, bpp);
482
483 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
484
485 GrTexture* texture = fGpu->createTexture(rtDesc,
486 stretchedPixels.get(),
487 stretchedRowBytes);
488 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000489 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000490 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000491 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000492
493 } else {
494 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
495 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000496 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000497 }
498 }
499 return entry;
500}
501
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000502namespace {
503inline void gen_scratch_tex_key_values(const GrGpu* gpu,
504 const GrTextureDesc& desc,
505 uint32_t v[4]) {
506 // Instead of a client-provided key of the texture contents
507 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000508 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000509 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000510 // this code path isn't friendly to tiling with NPOT restricitons
511 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000512 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000513 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000514}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000515}
516
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000517GrContext::TextureCacheEntry GrContext::lockScratchTexture(
518 const GrTextureDesc& inDesc,
519 ScratchTexMatch match) {
520
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000521 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000522 if (kExact_ScratchTexMatch != match) {
523 // bin by pow2 with a reasonable min
524 static const int MIN_SIZE = 256;
525 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
526 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
527 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000528
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000529 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000530 int origWidth = desc.fWidth;
531 int origHeight = desc.fHeight;
532 bool doubledW = false;
533 bool doubledH = false;
534
535 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000536 uint32_t v[4];
537 gen_scratch_tex_key_values(fGpu, desc, v);
538 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000539 entry = fTextureCache->findAndLock(key,
540 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000541 // if we miss, relax the fit of the flags...
542 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000543 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000544 break;
545 }
546 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
547 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
548 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
549 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
550 } else if (!doubledW) {
551 desc.fFlags = inDesc.fFlags;
552 desc.fWidth *= 2;
553 doubledW = true;
554 } else if (!doubledH) {
555 desc.fFlags = inDesc.fFlags;
556 desc.fWidth = origWidth;
557 desc.fHeight *= 2;
558 doubledH = true;
559 } else {
560 break;
561 }
562
563 } while (true);
564
565 if (NULL == entry) {
566 desc.fFlags = inDesc.fFlags;
567 desc.fWidth = origWidth;
568 desc.fHeight = origHeight;
569 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
570 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000571 uint32_t v[4];
572 gen_scratch_tex_key_values(fGpu, desc, v);
573 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000574 entry = fTextureCache->createAndLock(key, texture);
575 }
576 }
577
578 // If the caller gives us the same desc/sampler twice we don't want
579 // to return the same texture the second time (unless it was previously
580 // released). So we detach the entry from the cache and reattach at release.
581 if (NULL != entry) {
582 fTextureCache->detach(entry);
583 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000584 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000585}
586
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000587void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000588 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000589 // If this is a scratch texture we detached it from the cache
590 // while it was locked (to avoid two callers simultaneously getting
591 // the same texture).
592 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
593 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000594 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000595 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000596 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000597}
598
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000599GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000600 void* srcData,
601 size_t rowBytes) {
602 return fGpu->createTexture(desc, srcData, rowBytes);
603}
604
605void GrContext::getTextureCacheLimits(int* maxTextures,
606 size_t* maxTextureBytes) const {
607 fTextureCache->getLimits(maxTextures, maxTextureBytes);
608}
609
610void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
611 fTextureCache->setLimits(maxTextures, maxTextureBytes);
612}
613
bsalomon@google.com91958362011-06-13 17:58:13 +0000614int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000615 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000616}
617
618int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000619 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000620}
621
622///////////////////////////////////////////////////////////////////////////////
623
bsalomon@google.come269f212011-11-07 13:29:52 +0000624GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
625 return fGpu->createPlatformTexture(desc);
626}
627
628GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
629 return fGpu->createPlatformRenderTarget(desc);
630}
631
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000632///////////////////////////////////////////////////////////////////////////////
633
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000634bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000635 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000636 const GrDrawTarget::Caps& caps = fGpu->getCaps();
637 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000638 return false;
639 }
640
bsalomon@google.com27847de2011-02-22 20:59:41 +0000641 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
642
643 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000644 bool tiled = NULL != sampler &&
645 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
646 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000647 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000648 return false;
649 }
650 }
651 return true;
652}
653
654////////////////////////////////////////////////////////////////////////////////
655
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000656const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
657
bsalomon@google.com27847de2011-02-22 20:59:41 +0000658void GrContext::setClip(const GrClip& clip) {
659 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000660 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000661}
662
663void GrContext::setClip(const GrIRect& rect) {
664 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000665 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000666 fGpu->setClip(clip);
667}
668
669////////////////////////////////////////////////////////////////////////////////
670
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000671void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000672 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000673 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000674}
675
676void GrContext::drawPaint(const GrPaint& paint) {
677 // set rect to be big enough to fill the space, but not super-huge, so we
678 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000679 GrRect r;
680 r.setLTRB(0, 0,
681 GrIntToScalar(getRenderTarget()->width()),
682 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000683 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000684 SkTLazy<GrPaint> tmpPaint;
685 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000686 GrAutoMatrix am;
687
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000688 // We attempt to map r by the inverse matrix and draw that. mapRect will
689 // map the four corners and bound them with a new rect. This will not
690 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000691 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000692 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000693 GrPrintf("Could not invert matrix");
694 return;
695 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000696 inverse.mapRect(&r);
697 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000698 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000699 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000700 GrPrintf("Could not invert matrix");
701 return;
702 }
703 tmpPaint.set(paint);
704 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
705 p = tmpPaint.get();
706 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000707 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000708 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000709 // by definition this fills the entire clip, no need for AA
710 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000711 if (!tmpPaint.isValid()) {
712 tmpPaint.set(paint);
713 p = tmpPaint.get();
714 }
715 GrAssert(p == tmpPaint.get());
716 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000717 }
718 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000719}
720
bsalomon@google.com205d4602011-04-25 12:43:45 +0000721////////////////////////////////////////////////////////////////////////////////
722
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000723namespace {
724inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
725 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
726}
727}
728
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729////////////////////////////////////////////////////////////////////////////////
730
bsalomon@google.com27847de2011-02-22 20:59:41 +0000731/* create a triangle strip that strokes the specified triangle. There are 8
732 unique vertices, but we repreat the last 2 to close up. Alternatively we
733 could use an indices array, and then only send 8 verts, but not sure that
734 would be faster.
735 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000736static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000737 GrScalar width) {
738 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000739 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000740
741 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
742 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
743 verts[2].set(rect.fRight - rad, rect.fTop + rad);
744 verts[3].set(rect.fRight + rad, rect.fTop - rad);
745 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
746 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
747 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
748 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
749 verts[8] = verts[0];
750 verts[9] = verts[1];
751}
752
bsalomon@google.com205d4602011-04-25 12:43:45 +0000753static void setInsetFan(GrPoint* pts, size_t stride,
754 const GrRect& r, GrScalar dx, GrScalar dy) {
755 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
756}
757
758static const uint16_t gFillAARectIdx[] = {
759 0, 1, 5, 5, 4, 0,
760 1, 2, 6, 6, 5, 1,
761 2, 3, 7, 7, 6, 2,
762 3, 0, 4, 4, 7, 3,
763 4, 5, 6, 6, 7, 4,
764};
765
766int GrContext::aaFillRectIndexCount() const {
767 return GR_ARRAY_COUNT(gFillAARectIdx);
768}
769
770GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
771 if (NULL == fAAFillRectIndexBuffer) {
772 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
773 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000774 if (NULL != fAAFillRectIndexBuffer) {
775 #if GR_DEBUG
776 bool updated =
777 #endif
778 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
779 sizeof(gFillAARectIdx));
780 GR_DEBUGASSERT(updated);
781 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000782 }
783 return fAAFillRectIndexBuffer;
784}
785
786static const uint16_t gStrokeAARectIdx[] = {
787 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
788 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
789 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
790 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
791
792 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
793 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
794 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
795 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
796
797 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
798 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
799 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
800 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
801};
802
803int GrContext::aaStrokeRectIndexCount() const {
804 return GR_ARRAY_COUNT(gStrokeAARectIdx);
805}
806
807GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
808 if (NULL == fAAStrokeRectIndexBuffer) {
809 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
810 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000811 if (NULL != fAAStrokeRectIndexBuffer) {
812 #if GR_DEBUG
813 bool updated =
814 #endif
815 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
816 sizeof(gStrokeAARectIdx));
817 GR_DEBUGASSERT(updated);
818 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000819 }
820 return fAAStrokeRectIndexBuffer;
821}
822
bsalomon@google.coma3108262011-10-10 14:08:47 +0000823static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
824 bool useCoverage) {
825 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000826 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000827 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000828 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
829 }
830 }
831 if (useCoverage) {
832 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
833 } else {
834 layout |= GrDrawTarget::kColor_VertexLayoutBit;
835 }
836 return layout;
837}
838
bsalomon@google.com205d4602011-04-25 12:43:45 +0000839void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000840 const GrRect& devRect,
841 bool useVertexCoverage) {
842 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000843
844 size_t vsize = GrDrawTarget::VertexSize(layout);
845
846 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000847 if (!geo.succeeded()) {
848 GrPrintf("Failed to get space for vertices!\n");
849 return;
850 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000851 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
852 if (NULL == indexBuffer) {
853 GrPrintf("Failed to create index buffer!\n");
854 return;
855 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000856
857 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
858
859 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
860 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
861
862 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
863 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
864
865 verts += sizeof(GrPoint);
866 for (int i = 0; i < 4; ++i) {
867 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
868 }
869
bsalomon@google.coma3108262011-10-10 14:08:47 +0000870 GrColor innerColor;
871 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000872 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000873 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000874 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000875 }
876
bsalomon@google.com205d4602011-04-25 12:43:45 +0000877 verts += 4 * vsize;
878 for (int i = 0; i < 4; ++i) {
879 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
880 }
881
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000882 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000883
884 target->drawIndexed(kTriangles_PrimitiveType, 0,
885 0, 8, this->aaFillRectIndexCount());
886}
887
bsalomon@google.coma3108262011-10-10 14:08:47 +0000888void GrContext::strokeAARect(GrDrawTarget* target,
889 const GrRect& devRect,
890 const GrVec& devStrokeSize,
891 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000892 const GrScalar& dx = devStrokeSize.fX;
893 const GrScalar& dy = devStrokeSize.fY;
894 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
895 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
896
bsalomon@google.com205d4602011-04-25 12:43:45 +0000897 GrScalar spare;
898 {
899 GrScalar w = devRect.width() - dx;
900 GrScalar h = devRect.height() - dy;
901 spare = GrMin(w, h);
902 }
903
904 if (spare <= 0) {
905 GrRect r(devRect);
906 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000907 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 return;
909 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000910 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000911 size_t vsize = GrDrawTarget::VertexSize(layout);
912
913 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000914 if (!geo.succeeded()) {
915 GrPrintf("Failed to get space for vertices!\n");
916 return;
917 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000918 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
919 if (NULL == indexBuffer) {
920 GrPrintf("Failed to create index buffer!\n");
921 return;
922 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000923
924 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
925
926 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
927 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
928 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
929 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
930
931 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
932 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
933 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
934 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
935
936 verts += sizeof(GrPoint);
937 for (int i = 0; i < 4; ++i) {
938 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
939 }
940
bsalomon@google.coma3108262011-10-10 14:08:47 +0000941 GrColor innerColor;
942 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000943 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000944 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000945 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000946 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000947 verts += 4 * vsize;
948 for (int i = 0; i < 8; ++i) {
949 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
950 }
951
952 verts += 8 * vsize;
953 for (int i = 0; i < 8; ++i) {
954 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
955 }
956
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000957 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000958 target->drawIndexed(kTriangles_PrimitiveType,
959 0, 0, 16, aaStrokeRectIndexCount());
960}
961
reed@google.com20efde72011-05-09 17:00:02 +0000962/**
963 * Returns true if the rects edges are integer-aligned.
964 */
965static bool isIRect(const GrRect& r) {
966 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
967 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
968}
969
bsalomon@google.com205d4602011-04-25 12:43:45 +0000970static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000971 const GrRect& rect,
972 GrScalar width,
973 const GrMatrix* matrix,
974 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000975 GrRect* devRect,
976 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000977 // we use a simple coverage ramp to do aa on axis-aligned rects
978 // we check if the rect will be axis-aligned, and the rect won't land on
979 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000980
bsalomon@google.coma3108262011-10-10 14:08:47 +0000981 // we are keeping around the "tweak the alpha" trick because
982 // it is our only hope for the fixed-pipe implementation.
983 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000984 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000985 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000986 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000987 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000988#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000989 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000990#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000991 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000992 } else {
993 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000994 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000995 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000996 const GrDrawState& drawState = target->getDrawState();
997 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000998 return false;
999 }
1000
bsalomon@google.com471d4712011-08-23 15:45:25 +00001001 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002 return false;
1003 }
1004
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001005 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001006 return false;
1007 }
1008
1009 if (NULL != matrix &&
1010 !matrix->preservesAxisAlignment()) {
1011 return false;
1012 }
1013
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001014 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001015 if (NULL != matrix) {
1016 combinedMatrix->preConcat(*matrix);
1017 GrAssert(combinedMatrix->preservesAxisAlignment());
1018 }
1019
1020 combinedMatrix->mapRect(devRect, rect);
1021 devRect->sort();
1022
1023 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001024 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001025 } else {
1026 return true;
1027 }
1028}
1029
bsalomon@google.com27847de2011-02-22 20:59:41 +00001030void GrContext::drawRect(const GrPaint& paint,
1031 const GrRect& rect,
1032 GrScalar width,
1033 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001034 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001035
1036 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001037 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001038
bsalomon@google.com205d4602011-04-25 12:43:45 +00001039 GrRect devRect = rect;
1040 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001041 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001042 bool needAA = paint.fAntiAlias &&
1043 !this->getRenderTarget()->isMultisampled();
1044 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1045 &combinedMatrix, &devRect,
1046 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001047
1048 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001049 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001050 if (width >= 0) {
1051 GrVec strokeSize;;
1052 if (width > 0) {
1053 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001054 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001055 strokeSize.setAbs(strokeSize);
1056 } else {
1057 strokeSize.set(GR_Scalar1, GR_Scalar1);
1058 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001059 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001061 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001062 }
1063 return;
1064 }
1065
bsalomon@google.com27847de2011-02-22 20:59:41 +00001066 if (width >= 0) {
1067 // TODO: consider making static vertex buffers for these cases.
1068 // Hairline could be done by just adding closing vertex to
1069 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001070 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1071
bsalomon@google.com27847de2011-02-22 20:59:41 +00001072 static const int worstCaseVertCount = 10;
1073 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1074
1075 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001076 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001077 return;
1078 }
1079
1080 GrPrimitiveType primType;
1081 int vertCount;
1082 GrPoint* vertex = geo.positions();
1083
1084 if (width > 0) {
1085 vertCount = 10;
1086 primType = kTriangleStrip_PrimitiveType;
1087 setStrokeRectStrip(vertex, rect, width);
1088 } else {
1089 // hairline
1090 vertCount = 5;
1091 primType = kLineStrip_PrimitiveType;
1092 vertex[0].set(rect.fLeft, rect.fTop);
1093 vertex[1].set(rect.fRight, rect.fTop);
1094 vertex[2].set(rect.fRight, rect.fBottom);
1095 vertex[3].set(rect.fLeft, rect.fBottom);
1096 vertex[4].set(rect.fLeft, rect.fTop);
1097 }
1098
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001099 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001100 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001101 GrDrawState* drawState = target->drawState();
1102 avmr.set(drawState);
1103 drawState->preConcatViewMatrix(*matrix);
1104 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001105 }
1106
1107 target->drawNonIndexed(primType, 0, vertCount);
1108 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001109#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001110 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001111 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1112 if (NULL == sqVB) {
1113 GrPrintf("Failed to create static rect vb.\n");
1114 return;
1115 }
1116 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001117 GrDrawState* drawState = target->drawState();
1118 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001120 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001121 0, rect.height(), rect.fTop,
1122 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001123
1124 if (NULL != matrix) {
1125 m.postConcat(*matrix);
1126 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001127 drawState->preConcatViewMatrix(m);
1128 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001129
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001131#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001132 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001133#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001134 }
1135}
1136
1137void GrContext::drawRectToRect(const GrPaint& paint,
1138 const GrRect& dstRect,
1139 const GrRect& srcRect,
1140 const GrMatrix* dstMatrix,
1141 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001142 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001143
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001144 // srcRect refers to paint's first texture
1145 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 drawRect(paint, dstRect, -1, dstMatrix);
1147 return;
1148 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001149
bsalomon@google.com27847de2011-02-22 20:59:41 +00001150 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1151
1152#if GR_STATIC_RECT_VB
1153 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001154 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001155 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001156 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001157
1158 GrMatrix m;
1159
1160 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1161 0, dstRect.height(), dstRect.fTop,
1162 0, 0, GrMatrix::I()[8]);
1163 if (NULL != dstMatrix) {
1164 m.postConcat(*dstMatrix);
1165 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001166 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001168 // srcRect refers to first stage
1169 int otherStageMask = paint.getActiveStageMask() &
1170 (~(1 << GrPaint::kFirstTextureStage));
1171 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001172 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001173 }
1174
bsalomon@google.com27847de2011-02-22 20:59:41 +00001175 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1176 0, srcRect.height(), srcRect.fTop,
1177 0, 0, GrMatrix::I()[8]);
1178 if (NULL != srcMatrix) {
1179 m.postConcat(*srcMatrix);
1180 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001181 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001182
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001183 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1184 if (NULL == sqVB) {
1185 GrPrintf("Failed to create static rect vb.\n");
1186 return;
1187 }
1188 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001189 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1190#else
1191
1192 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001193#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001194 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001195#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1197#endif
1198
tomhudson@google.com93813632011-10-27 20:21:16 +00001199 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1200 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001201 srcRects[0] = &srcRect;
1202 srcMatrices[0] = srcMatrix;
1203
1204 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1205#endif
1206}
1207
1208void GrContext::drawVertices(const GrPaint& paint,
1209 GrPrimitiveType primitiveType,
1210 int vertexCount,
1211 const GrPoint positions[],
1212 const GrPoint texCoords[],
1213 const GrColor colors[],
1214 const uint16_t indices[],
1215 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001216 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001217
1218 GrDrawTarget::AutoReleaseGeometry geo;
1219
1220 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1221
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001222 bool hasTexCoords[GrPaint::kTotalStages] = {
1223 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1224 0 // remaining stages use positions
1225 };
1226
1227 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001228
1229 if (NULL != colors) {
1230 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001231 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001232 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233
1234 if (sizeof(GrPoint) != vertexSize) {
1235 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001236 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001237 return;
1238 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001239 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001241 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1242 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001243 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001244 NULL,
1245 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246 void* curVertex = geo.vertices();
1247
1248 for (int i = 0; i < vertexCount; ++i) {
1249 *((GrPoint*)curVertex) = positions[i];
1250
1251 if (texOffsets[0] > 0) {
1252 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1253 }
1254 if (colorOffset > 0) {
1255 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1256 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001257 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258 }
1259 } else {
1260 target->setVertexSourceToArray(layout, positions, vertexCount);
1261 }
1262
bsalomon@google.com91958362011-06-13 17:58:13 +00001263 // we don't currently apply offscreen AA to this path. Need improved
1264 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001265
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001266 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001267 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001268 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001270 target->drawNonIndexed(primitiveType, 0, vertexCount);
1271 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001272}
1273
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001274///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001275namespace {
1276
bsalomon@google.com93c96602012-04-27 13:05:21 +00001277struct CircleVertex {
1278 GrPoint fPos;
1279 GrPoint fCenter;
1280 GrScalar fOuterRadius;
1281 GrScalar fInnerRadius;
1282};
1283
1284/* Returns true if will map a circle to another circle. This can be true
1285 * if the matrix only includes square-scale, rotation, translation.
1286 */
1287inline bool isSimilarityTransformation(const SkMatrix& matrix,
1288 SkScalar tol = SK_ScalarNearlyZero) {
1289 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1290 return true;
1291 }
1292 if (matrix.hasPerspective()) {
1293 return false;
1294 }
1295
1296 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1297 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1298 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1299 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1300
1301 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1302 return false;
1303 }
1304
1305 // it has scales or skews, but it could also be rotation, check it out.
1306 SkVector vec[2];
1307 vec[0].set(mx, sx);
1308 vec[1].set(sy, my);
1309
1310 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1311 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1312 SkScalarSquare(tol));
1313}
1314
1315}
1316
1317// TODO: strokeWidth can't be larger than zero right now.
1318// It will be fixed when drawPath() can handle strokes.
1319void GrContext::drawOval(const GrPaint& paint,
1320 const GrRect& rect,
1321 SkScalar strokeWidth) {
1322 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1323 kUnbuffered_DrawCategory;
1324 GrDrawTarget* target = this->prepareToDraw(paint, category);
1325 GrDrawState* drawState = target->drawState();
1326 GrMatrix vm = drawState->getViewMatrix();
1327
1328 if (!isSimilarityTransformation(vm) ||
1329 !paint.fAntiAlias ||
1330 rect.height() != rect.width()) {
1331 SkPath path;
1332 path.addOval(rect);
1333 GrPathFill fill = (strokeWidth == 0) ?
1334 kHairLine_PathFill : kWinding_PathFill;
1335 this->internalDrawPath(paint, path, fill, NULL);
1336 return;
1337 }
1338
1339 const GrRenderTarget* rt = drawState->getRenderTarget();
1340 if (NULL == rt) {
1341 return;
1342 }
1343
1344 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1345
1346 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1347 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1348 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1349
1350 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1351 GrScalar radius = SkScalarHalf(rect.width());
1352
1353 vm.mapPoints(&center, 1);
1354 radius = vm.mapRadius(radius);
1355
1356 GrScalar outerRadius = radius;
1357 GrScalar innerRadius = 0;
1358 SkScalar halfWidth = 0;
1359 if (strokeWidth == 0) {
1360 halfWidth = SkScalarHalf(SK_Scalar1);
1361
1362 outerRadius += halfWidth;
1363 innerRadius = SkMaxScalar(0, radius - halfWidth);
1364 }
1365
1366 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1367 if (!geo.succeeded()) {
1368 GrPrintf("Failed to get space for vertices!\n");
1369 return;
1370 }
1371
1372 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1373
1374 SkScalar L = center.fX - outerRadius;
1375 SkScalar R = center.fX + outerRadius;
1376 SkScalar T = center.fY - outerRadius;
1377 SkScalar B = center.fY + outerRadius;
1378
1379 verts[0].fPos = SkPoint::Make(L, T);
1380 verts[1].fPos = SkPoint::Make(R, T);
1381 verts[2].fPos = SkPoint::Make(L, B);
1382 verts[3].fPos = SkPoint::Make(R, B);
1383
1384 for (int i = 0; i < 4; ++i) {
1385 // this goes to fragment shader, it should be in y-points-up space.
1386 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1387
1388 verts[i].fOuterRadius = outerRadius;
1389 verts[i].fInnerRadius = innerRadius;
1390 }
1391
1392 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1393 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001394}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001396void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001397 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001399 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001400 if (GrIsFillInverted(fill)) {
1401 this->drawPaint(paint);
1402 }
1403 return;
1404 }
1405
bsalomon@google.com93c96602012-04-27 13:05:21 +00001406 SkRect ovalRect;
1407 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1408 if (translate) {
1409 ovalRect.offset(*translate);
1410 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001411 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001412 this->drawOval(paint, ovalRect, width);
1413 return;
1414 }
1415
1416 internalDrawPath(paint, path, fill, translate);
1417}
1418
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001419void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001420 GrPathFill fill, const GrPoint* translate) {
1421
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001422 // Note that below we may sw-rasterize the path into a scratch texture.
1423 // Scratch textures can be recycled after they are returned to the texture
1424 // cache. This presents a potential hazard for buffered drawing. However,
1425 // the writePixels that uploads to the scratch will perform a flush so we're
1426 // OK.
1427 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1428 kUnbuffered_DrawCategory;
1429 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001430 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001431
bsalomon@google.com289533a2011-10-27 12:34:25 +00001432 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1433
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001434 // An Assumption here is that path renderer would use some form of tweaking
1435 // the src color (either the input alpha or in the frag shader) to implement
1436 // aa. If we have some future driver-mojo path AA that can do the right
1437 // thing WRT to the blend then we'll need some query on the PR.
1438 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001439#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001440 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001441#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001442 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001443 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001444
robertphillips@google.comed4155d2012-05-01 14:30:24 +00001445 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA);
bsalomon@google.com30085192011-08-19 15:42:31 +00001446 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001447#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001448 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001449#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001450 return;
1451 }
1452
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001453 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001455
bsalomon@google.com27847de2011-02-22 20:59:41 +00001456////////////////////////////////////////////////////////////////////////////////
1457
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001458void GrContext::flush(int flagsBitfield) {
1459 if (kDiscard_FlushBit & flagsBitfield) {
1460 fDrawBuffer->reset();
1461 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001462 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001463 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001464 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465 fGpu->forceRenderTargetFlush();
1466 }
1467}
1468
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001470 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001471 // With addition of the AA clip path, flushing the draw buffer can
1472 // result in the generation of an AA clip mask. During this
1473 // process the SW path renderer may be invoked which recusively
1474 // calls this method (via internalWriteTexturePixels) creating
1475 // infinite recursion
1476 GrInOrderDrawBuffer* temp = fDrawBuffer;
1477 fDrawBuffer = NULL;
1478
1479 temp->flushTo(fGpu);
1480
1481 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001482 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001483}
1484
bsalomon@google.com6f379512011-11-16 20:36:03 +00001485void GrContext::internalWriteTexturePixels(GrTexture* texture,
1486 int left, int top,
1487 int width, int height,
1488 GrPixelConfig config,
1489 const void* buffer,
1490 size_t rowBytes,
1491 uint32_t flags) {
1492 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001493 ASSERT_OWNED_RESOURCE(texture);
1494
bsalomon@google.com6f379512011-11-16 20:36:03 +00001495 if (!(kDontFlush_PixelOpsFlag & flags)) {
1496 this->flush();
1497 }
1498 // TODO: use scratch texture to perform conversion
1499 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1500 GrPixelConfigIsUnpremultiplied(config)) {
1501 return;
1502 }
1503
1504 fGpu->writeTexturePixels(texture, left, top, width, height,
1505 config, buffer, rowBytes);
1506}
1507
1508bool GrContext::internalReadTexturePixels(GrTexture* texture,
1509 int left, int top,
1510 int width, int height,
1511 GrPixelConfig config,
1512 void* buffer,
1513 size_t rowBytes,
1514 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001515 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001516 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001517
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001518 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001519 GrRenderTarget* target = texture->asRenderTarget();
1520 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001521 return this->internalReadRenderTargetPixels(target,
1522 left, top, width, height,
1523 config, buffer, rowBytes,
1524 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001525 } else {
1526 return false;
1527 }
1528}
1529
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001530#include "SkConfig8888.h"
1531
1532namespace {
1533/**
1534 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1535 * formats are representable as Config8888 and so the function returns false
1536 * if the GrPixelConfig has no equivalent Config8888.
1537 */
1538bool grconfig_to_config8888(GrPixelConfig config,
1539 SkCanvas::Config8888* config8888) {
1540 switch (config) {
1541 case kRGBA_8888_PM_GrPixelConfig:
1542 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1543 return true;
1544 case kRGBA_8888_UPM_GrPixelConfig:
1545 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1546 return true;
1547 case kBGRA_8888_PM_GrPixelConfig:
1548 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1549 return true;
1550 case kBGRA_8888_UPM_GrPixelConfig:
1551 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1552 return true;
1553 default:
1554 return false;
1555 }
1556}
1557}
1558
bsalomon@google.com6f379512011-11-16 20:36:03 +00001559bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1560 int left, int top,
1561 int width, int height,
1562 GrPixelConfig config,
1563 void* buffer,
1564 size_t rowBytes,
1565 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001566 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001567 ASSERT_OWNED_RESOURCE(target);
1568
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001569 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001570 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001571 if (NULL == target) {
1572 return false;
1573 }
1574 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001575
bsalomon@google.com6f379512011-11-16 20:36:03 +00001576 if (!(kDontFlush_PixelOpsFlag & flags)) {
1577 this->flush();
1578 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001579
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001580 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1581 GrPixelConfigIsUnpremultiplied(config) &&
1582 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1583 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1584 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1585 !grconfig_to_config8888(config, &dstConfig8888)) {
1586 return false;
1587 }
1588 // do read back using target's own config
1589 this->internalReadRenderTargetPixels(target,
1590 left, top,
1591 width, height,
1592 target->config(),
1593 buffer, rowBytes,
1594 kDontFlush_PixelOpsFlag);
1595 // sw convert the pixels to unpremul config
1596 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1597 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1598 pixels, rowBytes, srcConfig8888,
1599 width, height);
1600 return true;
1601 }
1602
bsalomon@google.comc4364992011-11-07 15:54:49 +00001603 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001604 bool swapRAndB = NULL != src &&
1605 fGpu->preferredReadPixelsConfig(config) ==
1606 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001607
1608 bool flipY = NULL != src &&
1609 fGpu->readPixelsWillPayForYFlip(target, left, top,
1610 width, height, config,
1611 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001612 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1613 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001614
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001615 if (NULL == src && alphaConversion) {
1616 // we should fallback to cpu conversion here. This could happen when
1617 // we were given an external render target by the client that is not
1618 // also a texture (e.g. FBO 0 in GL)
1619 return false;
1620 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001621 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001622 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001623 if (flipY || swapRAndB || alphaConversion) {
1624 GrAssert(NULL != src);
1625 if (swapRAndB) {
1626 config = GrPixelConfigSwapRAndB(config);
1627 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001628 }
1629 // Make the scratch a render target because we don't have a robust
1630 // readTexturePixels as of yet (it calls this function).
1631 const GrTextureDesc desc = {
1632 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001633 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001634 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001635 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001636 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001637
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001638 // When a full readback is faster than a partial we could always make
1639 // the scratch exactly match the passed rect. However, if we see many
1640 // different size rectangles we will trash our texture cache and pay the
1641 // cost of creating and destroying many textures. So, we only request
1642 // an exact match when the caller is reading an entire RT.
1643 ScratchTexMatch match = kApprox_ScratchTexMatch;
1644 if (0 == left &&
1645 0 == top &&
1646 target->width() == width &&
1647 target->height() == height &&
1648 fGpu->fullReadPixelsIsFasterThanPartial()) {
1649 match = kExact_ScratchTexMatch;
1650 }
1651 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001652 GrTexture* texture = ast.texture();
1653 if (!texture) {
1654 return false;
1655 }
1656 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001657 GrAssert(NULL != target);
1658
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001659 GrDrawTarget::AutoStateRestore asr(fGpu,
1660 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001661 GrDrawState* drawState = fGpu->drawState();
1662 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001663
bsalomon@google.comc4364992011-11-07 15:54:49 +00001664 GrMatrix matrix;
1665 if (flipY) {
1666 matrix.setTranslate(SK_Scalar1 * left,
1667 SK_Scalar1 * (top + height));
1668 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1669 } else {
1670 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1671 }
1672 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001673 drawState->sampler(0)->reset(matrix);
1674 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001675 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001676 GrRect rect;
1677 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1678 fGpu->drawSimpleRect(rect, NULL, 0x1);
1679 left = 0;
1680 top = 0;
1681 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001682 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001683 left, top, width, height,
1684 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001685}
1686
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001687void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1688 GrAssert(target);
1689 ASSERT_OWNED_RESOURCE(target);
1690 // In the future we may track whether there are any pending draws to this
1691 // target. We don't today so we always perform a flush. We don't promise
1692 // this to our clients, though.
1693 this->flush();
1694 fGpu->resolveRenderTarget(target);
1695}
1696
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001697void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1698 if (NULL == src || NULL == dst) {
1699 return;
1700 }
1701 ASSERT_OWNED_RESOURCE(src);
1702
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001703 // Writes pending to the source texture are not tracked, so a flush
1704 // is required to ensure that the copy captures the most recent contents
1705 // of the source texture. See similar behaviour in
1706 // GrContext::resolveRenderTarget.
1707 this->flush();
1708
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001709 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001710 GrDrawState* drawState = fGpu->drawState();
1711 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001712 GrMatrix sampleM;
1713 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001714 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001715 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001716 SkRect rect = SkRect::MakeXYWH(0, 0,
1717 SK_Scalar1 * src->width(),
1718 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001719 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1720}
1721
bsalomon@google.com6f379512011-11-16 20:36:03 +00001722void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1723 int left, int top,
1724 int width, int height,
1725 GrPixelConfig config,
1726 const void* buffer,
1727 size_t rowBytes,
1728 uint32_t flags) {
1729 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001730 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001731
1732 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001733 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001734 if (NULL == target) {
1735 return;
1736 }
1737 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001738
1739 // TODO: when underlying api has a direct way to do this we should use it
1740 // (e.g. glDrawPixels on desktop GL).
1741
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001742 // If the RT is also a texture and we don't have to do PM/UPM conversion
1743 // then take the texture path, which we expect to be at least as fast or
1744 // faster since it doesn't use an intermediate texture as we do below.
1745
1746#if !GR_MAC_BUILD
1747 // At least some drivers on the Mac get confused when glTexImage2D is called
1748 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1749 // determine what OS versions and/or HW is affected.
1750 if (NULL != target->asTexture() &&
1751 GrPixelConfigIsUnpremultiplied(target->config()) ==
1752 GrPixelConfigIsUnpremultiplied(config)) {
1753
1754 this->internalWriteTexturePixels(target->asTexture(),
1755 left, top, width, height,
1756 config, buffer, rowBytes, flags);
1757 return;
1758 }
1759#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001760 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1761 GrPixelConfigIsUnpremultiplied(config) &&
1762 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1763 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1764 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1765 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1766 return;
1767 }
1768 // allocate a tmp buffer and sw convert the pixels to premul
1769 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1770 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1771 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1772 src, rowBytes, srcConfig8888,
1773 width, height);
1774 // upload the already premul pixels
1775 this->internalWriteRenderTargetPixels(target,
1776 left, top,
1777 width, height,
1778 target->config(),
1779 tmpPixels, 4 * width, flags);
1780 return;
1781 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001782
1783 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1784 GrPixelConfigSwapRAndB(config);
1785 if (swapRAndB) {
1786 config = GrPixelConfigSwapRAndB(config);
1787 }
1788
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001789 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001790 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001791 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001792 GrAutoScratchTexture ast(this, desc);
1793 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001794 if (NULL == texture) {
1795 return;
1796 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001797 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1798 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001799
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001800 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001801 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001802
1803 GrMatrix matrix;
1804 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001805 drawState->setViewMatrix(matrix);
1806 drawState->setRenderTarget(target);
1807 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001808
bsalomon@google.com5c638652011-07-18 19:31:59 +00001809 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001810 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1811 GrSamplerState::kNearest_Filter,
1812 matrix);
1813 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001814
1815 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1816 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001817 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001818 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1819 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001820 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001821 return;
1822 }
1823 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1824 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1825}
1826////////////////////////////////////////////////////////////////////////////////
1827
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001828void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001829
1830 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1831 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001832 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001833 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001834 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001835 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001836 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001837 }
1838
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001839 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001840
1841 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1842 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001843 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001844 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001845 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001846 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001847 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001848 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001849
1850 // disable all stages not accessible via the paint
1851 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001852 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001853 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001854
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001855 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001856
1857 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001858 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001859 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001860 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001861 }
1862 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001863 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001864 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001865 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001866 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001867 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001868 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1869 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001870 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001871 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001872 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001873 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1874 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1875 fDrawState->setCoverage(paint.fCoverage);
bsalomon@google.come79c8152012-03-29 19:07:12 +00001876#if GR_DEBUG
1877 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001878 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001879 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1880 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001881#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001882}
1883
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001884GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885 DrawCategory category) {
1886 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001887 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001888 fLastDrawCategory = category;
1889 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001890 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001891 GrDrawTarget* target = fGpu;
1892 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001893 case kUnbuffered_DrawCategory:
1894 target = fGpu;
1895 break;
1896 case kBuffered_DrawCategory:
1897 target = fDrawBuffer;
1898 fDrawBuffer->setClip(fGpu->getClip());
1899 break;
1900 default:
1901 GrCrash("Unexpected DrawCategory.");
1902 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001903 }
1904 return target;
1905}
1906
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001907GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001908 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001909 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001910 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001911 if (NULL == fPathRendererChain) {
1912 fPathRendererChain =
1913 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1914 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001915 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001916}
1917
bsalomon@google.com27847de2011-02-22 20:59:41 +00001918////////////////////////////////////////////////////////////////////////////////
1919
bsalomon@google.com27847de2011-02-22 20:59:41 +00001920void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001921 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001922 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001923 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001924 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001925 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001926}
1927
1928GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001929 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001930}
1931
1932const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001933 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001934}
1935
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001936bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1937 return fGpu->isConfigRenderable(config);
1938}
1939
bsalomon@google.com27847de2011-02-22 20:59:41 +00001940const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001941 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001942}
1943
1944void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001945 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946}
1947
1948void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001949 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001950}
1951
1952static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1953 intptr_t mask = 1 << shift;
1954 if (pred) {
1955 bits |= mask;
1956 } else {
1957 bits &= ~mask;
1958 }
1959 return bits;
1960}
1961
1962void GrContext::resetStats() {
1963 fGpu->resetStats();
1964}
1965
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001966const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001967 return fGpu->getStats();
1968}
1969
1970void GrContext::printStats() const {
1971 fGpu->printStats();
1972}
1973
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001974GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001975 fGpu = gpu;
1976 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001977 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001978
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001979 fDrawState = new GrDrawState();
1980 fGpu->setDrawState(fDrawState);
1981
bsalomon@google.com30085192011-08-19 15:42:31 +00001982 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001983
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001984 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1985 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001986 fFontCache = new GrFontCache(fGpu);
1987
1988 fLastDrawCategory = kUnbuffered_DrawCategory;
1989
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001990 fDrawBuffer = NULL;
1991 fDrawBufferVBAllocPool = NULL;
1992 fDrawBufferIBAllocPool = NULL;
1993
bsalomon@google.com205d4602011-04-25 12:43:45 +00001994 fAAFillRectIndexBuffer = NULL;
1995 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001996
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001997 this->setupDrawBuffer();
1998}
1999
2000void GrContext::setupDrawBuffer() {
2001
2002 GrAssert(NULL == fDrawBuffer);
2003 GrAssert(NULL == fDrawBufferVBAllocPool);
2004 GrAssert(NULL == fDrawBufferIBAllocPool);
2005
bsalomon@google.com92edd312012-04-04 21:40:21 +00002006#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002007 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002008 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002009 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2010 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002011 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002012 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002013 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002014 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2015
bsalomon@google.com471d4712011-08-23 15:45:25 +00002016 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2017 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002018 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002019#endif
2020
2021#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002022 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002023#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002024 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002025 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002026}
2027
bsalomon@google.com27847de2011-02-22 20:59:41 +00002028GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002029#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002030 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002031#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002032 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002033#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002034}
2035
2036const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2037 return fGpu->getQuadIndexBuffer();
2038}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002039
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002040GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2041 GrAutoScratchTexture* temp1,
2042 GrAutoScratchTexture* temp2,
2043 const SkRect& rect,
2044 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002045 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002046 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2047 GrClip oldClip = this->getClip();
2048 GrTexture* origTexture = srcTexture;
2049 GrAutoMatrix avm(this, GrMatrix::I());
2050 SkIRect clearRect;
2051 int scaleFactorX, halfWidthX, kernelWidthX;
2052 int scaleFactorY, halfWidthY, kernelWidthY;
2053 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2054 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002055
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002056 SkRect srcRect(rect);
2057 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2058 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002059 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2060 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002061 this->setClip(srcRect);
2062
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002063 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2064 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2065 kAlpha_8_GrPixelConfig == srcTexture->config());
2066
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002067 const GrTextureDesc desc = {
2068 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002069 SkScalarFloorToInt(srcRect.width()),
2070 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002071 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002072 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002073 };
2074
2075 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002076 if (temp2) {
2077 temp2->set(this, desc);
2078 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002079
2080 GrTexture* dstTexture = temp1->texture();
2081 GrPaint paint;
2082 paint.reset();
2083 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2084
2085 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2086 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2087 srcTexture->height());
2088 this->setRenderTarget(dstTexture->asRenderTarget());
2089 SkRect dstRect(srcRect);
2090 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2091 i < scaleFactorY ? 0.5f : 1.0f);
2092 paint.setTexture(0, srcTexture);
2093 this->drawRectToRect(paint, dstRect, srcRect);
2094 srcRect = dstRect;
2095 SkTSwap(srcTexture, dstTexture);
2096 // If temp2 is non-NULL, don't render back to origTexture
2097 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2098 }
2099
robertphillips@google.com7a396332012-05-10 15:11:27 +00002100 SkIRect srcIRect;
2101 srcRect.roundOut(&srcIRect);
2102
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002103 if (sigmaX > 0.0f) {
2104 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2105 float* kernelX = kernelStorageX.get();
2106 build_kernel(sigmaX, kernelX, kernelWidthX);
2107
2108 if (scaleFactorX > 1) {
2109 // Clear out a halfWidth to the right of the srcRect to prevent the
2110 // X convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002111 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2112 halfWidthX, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002113 this->clear(&clearRect, 0x0);
2114 }
2115
2116 this->setRenderTarget(dstTexture->asRenderTarget());
2117 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2118 GrSamplerState::kX_FilterDirection);
2119 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002120 if (temp2 && dstTexture == origTexture) {
2121 dstTexture = temp2->texture();
2122 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002123 }
2124
2125 if (sigmaY > 0.0f) {
2126 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2127 float* kernelY = kernelStorageY.get();
2128 build_kernel(sigmaY, kernelY, kernelWidthY);
2129
2130 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2131 // Clear out a halfWidth below the srcRect to prevent the Y
2132 // convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002133 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2134 srcIRect.width(), halfWidthY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002135 this->clear(&clearRect, 0x0);
2136 }
2137
2138 this->setRenderTarget(dstTexture->asRenderTarget());
2139 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2140 GrSamplerState::kY_FilterDirection);
2141 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002142 if (temp2 && dstTexture == origTexture) {
2143 dstTexture = temp2->texture();
2144 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002145 }
2146
2147 if (scaleFactorX > 1 || scaleFactorY > 1) {
2148 // Clear one pixel to the right and below, to accommodate bilinear
2149 // upsampling.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002150 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2151 srcIRect.width() + 1, 1);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002152 this->clear(&clearRect, 0x0);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002153 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2154 1, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002155 this->clear(&clearRect, 0x0);
2156 // FIXME: This should be mitchell, not bilinear.
2157 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2158 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2159 srcTexture->height());
2160 this->setRenderTarget(dstTexture->asRenderTarget());
2161 paint.setTexture(0, srcTexture);
2162 SkRect dstRect(srcRect);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002163 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002164 this->drawRectToRect(paint, dstRect, srcRect);
2165 srcRect = dstRect;
2166 SkTSwap(srcTexture, dstTexture);
2167 }
2168 this->setRenderTarget(oldRenderTarget);
2169 this->setClip(oldClip);
2170 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002171}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002172
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002173GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2174 const GrRect& rect,
2175 GrTexture* temp1, GrTexture* temp2,
2176 GrSamplerState::Filter filter,
2177 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002178 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002179 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2180 GrAutoMatrix avm(this, GrMatrix::I());
2181 GrClip oldClip = this->getClip();
robertphillips@google.com7a396332012-05-10 15:11:27 +00002182 this->setClip(GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
2183 SkIntToScalar(srcTexture->height())));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002184 if (radius.fWidth > 0) {
2185 this->setRenderTarget(temp1->asRenderTarget());
2186 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2187 GrSamplerState::kX_FilterDirection);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002188 SkIRect clearRect = SkIRect::MakeXYWH(
2189 SkScalarFloorToInt(rect.fLeft),
2190 SkScalarFloorToInt(rect.fBottom),
2191 SkScalarFloorToInt(rect.width()),
2192 radius.fHeight);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002193 this->clear(&clearRect, 0x0);
2194 srcTexture = temp1;
2195 }
2196 if (radius.fHeight > 0) {
2197 this->setRenderTarget(temp2->asRenderTarget());
2198 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2199 GrSamplerState::kY_FilterDirection);
2200 srcTexture = temp2;
2201 }
2202 this->setRenderTarget(oldRenderTarget);
2203 this->setClip(oldClip);
2204 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002205}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002206
2207///////////////////////////////////////////////////////////////////////////////