blob: bd6d829095efad225f02c4b05a098e7bb64bcacb [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
reed@google.com4b2d3f32012-05-15 18:05:50 +000038#if GR_DEBUG
39 // change this to a 1 to see notifications when partial coverage fails
40 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
41#else
42 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
43#endif
44
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000045static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
46static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000047
bsalomon@google.com60361492012-03-15 17:47:06 +000048static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000049static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
50
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000051// path rendering is the only thing we defer today that uses non-static indices
52static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
53static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000054
bsalomon@google.combc4b6542011-11-19 13:56:11 +000055#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
56
bsalomon@google.com05ef5102011-05-02 21:14:59 +000057GrContext* GrContext::Create(GrEngine engine,
58 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000059 GrContext* ctx = NULL;
60 GrGpu* fGpu = GrGpu::Create(engine, context3D);
61 if (NULL != fGpu) {
62 ctx = new GrContext(fGpu);
63 fGpu->unref();
64 }
65 return ctx;
66}
67
bsalomon@google.com27847de2011-02-22 20:59:41 +000068GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000069 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +000070
71 // Since the gpu can hold scratch textures, give it a chance to let go
72 // of them before freeing the texture cache
73 fGpu->purgeResources();
74
bsalomon@google.com27847de2011-02-22 20:59:41 +000075 delete fTextureCache;
76 delete fFontCache;
77 delete fDrawBuffer;
78 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000079 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000080
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 GrSafeUnref(fAAFillRectIndexBuffer);
82 GrSafeUnref(fAAStrokeRectIndexBuffer);
83 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000084 GrSafeUnref(fPathRendererChain);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000085 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000086}
87
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000089 contextDestroyed();
90 this->setupDrawBuffer();
91}
92
93void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000094 // abandon first to so destructors
95 // don't try to free the resources in the API.
96 fGpu->abandonResources();
97
bsalomon@google.com30085192011-08-19 15:42:31 +000098 // a path renderer may be holding onto resources that
99 // are now unusable
100 GrSafeSetNull(fPathRendererChain);
101
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102 delete fDrawBuffer;
103 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000104
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105 delete fDrawBufferVBAllocPool;
106 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000107
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000108 delete fDrawBufferIBAllocPool;
109 fDrawBufferIBAllocPool = NULL;
110
bsalomon@google.com205d4602011-04-25 12:43:45 +0000111 GrSafeSetNull(fAAFillRectIndexBuffer);
112 GrSafeSetNull(fAAStrokeRectIndexBuffer);
113
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000114 fTextureCache->removeAll();
115 fFontCache->freeAll();
116 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000117}
118
119void GrContext::resetContext() {
120 fGpu->markContextDirty();
121}
122
123void GrContext::freeGpuResources() {
124 this->flush();
robertphillips@google.comff175842012-05-14 19:31:39 +0000125
126 fGpu->purgeResources();
127
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000128 fTextureCache->removeAll();
129 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000130 // a path renderer may be holding onto resources
131 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000132}
133
twiz@google.com05e70242012-01-27 19:12:00 +0000134size_t GrContext::getGpuTextureCacheBytes() const {
135 return fTextureCache->getCachedResourceBytes();
136}
137
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000138////////////////////////////////////////////////////////////////////////////////
139
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000140int GrContext::PaintStageVertexLayoutBits(
141 const GrPaint& paint,
142 const bool hasTexCoords[GrPaint::kTotalStages]) {
143 int stageMask = paint.getActiveStageMask();
144 int layout = 0;
145 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
146 if ((1 << i) & stageMask) {
147 if (NULL != hasTexCoords && hasTexCoords[i]) {
148 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
149 } else {
150 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
151 }
152 }
153 }
154 return layout;
155}
156
157
158////////////////////////////////////////////////////////////////////////////////
159
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000160enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000161 // flags for textures
162 kNPOTBit = 0x1,
163 kFilterBit = 0x2,
164 kScratchBit = 0x4,
165
166 // resource type
167 kTextureBit = 0x8,
168 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000169};
170
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000171GrTexture* GrContext::TextureCacheEntry::texture() const {
172 if (NULL == fEntry) {
173 return NULL;
174 } else {
175 return (GrTexture*) fEntry->resource();
176 }
177}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000179namespace {
180// returns true if this is a "special" texture because of gpu NPOT limitations
181bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000182 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000183 GrContext::TextureKey clientKey,
184 int width,
185 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000186 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000187 bool scratch,
188 uint32_t v[4]) {
189 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
190 // we assume we only need 16 bits of width and height
191 // assert that texture creation will fail anyway if this assumption
192 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000193 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194 v[0] = clientKey & 0xffffffffUL;
195 v[1] = (clientKey >> 32) & 0xffffffffUL;
196 v[2] = width | (height << 16);
197
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000198 v[3] = (sampleCnt << 24);
199 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
200
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000201 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000202 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
203
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000204 bool tiled = NULL != sampler &&
205 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
206 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000207
208 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000209 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000210 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000211 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000212 }
213 }
214 }
215
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000216 if (scratch) {
217 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000218 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000219
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000220 v[3] |= kTextureBit;
221
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000222 return v[3] & kNPOTBit;
223}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000224
225// we should never have more than one stencil buffer with same combo of
226// (width,height,samplecount)
227void gen_stencil_key_values(int width, int height,
228 int sampleCnt, uint32_t v[4]) {
229 v[0] = width;
230 v[1] = height;
231 v[2] = sampleCnt;
232 v[3] = kStencilBufferBit;
233}
234
235void gen_stencil_key_values(const GrStencilBuffer* sb,
236 uint32_t v[4]) {
237 gen_stencil_key_values(sb->width(), sb->height(),
238 sb->numSamples(), v);
239}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000240
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000241void build_kernel(float sigma, float* kernel, int kernelWidth) {
242 int halfWidth = (kernelWidth - 1) / 2;
243 float sum = 0.0f;
244 float denom = 1.0f / (2.0f * sigma * sigma);
245 for (int i = 0; i < kernelWidth; ++i) {
246 float x = static_cast<float>(i - halfWidth);
247 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
248 // is dropped here, since we renormalize the kernel below.
249 kernel[i] = sk_float_exp(- x * x * denom);
250 sum += kernel[i];
251 }
252 // Normalize the kernel
253 float scale = 1.0f / sum;
254 for (int i = 0; i < kernelWidth; ++i)
255 kernel[i] *= scale;
256}
257
258void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000259 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
260 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
261 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
262 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000263}
264
265float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
266 int *kernelWidth) {
267 *scaleFactor = 1;
268 while (sigma > MAX_BLUR_SIGMA) {
269 *scaleFactor *= 2;
270 sigma *= 0.5f;
271 }
272 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
273 *kernelWidth = *halfWidth * 2 + 1;
274 return sigma;
275}
276
277void apply_morphology(GrGpu* gpu,
278 GrTexture* texture,
279 const SkRect& rect,
280 int radius,
281 GrSamplerState::Filter filter,
282 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000283 GrAssert(filter == GrSamplerState::kErode_Filter ||
284 filter == GrSamplerState::kDilate_Filter);
285
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000286 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
287 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000288 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000289 drawState->setRenderTarget(target);
290 GrMatrix sampleM;
291 sampleM.setIDiv(texture->width(), texture->height());
292 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
293 sampleM);
294 drawState->sampler(0)->setMorphologyRadius(radius);
295 drawState->sampler(0)->setFilterDirection(direction);
296 drawState->setTexture(0, texture);
297 gpu->drawSimpleRect(rect, NULL, 1 << 0);
298}
299
300void convolve(GrGpu* gpu,
301 GrTexture* texture,
302 const SkRect& rect,
303 const float* kernel,
304 int kernelWidth,
305 GrSamplerState::FilterDirection direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000306 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
307 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000308 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000309 drawState->setRenderTarget(target);
310 GrMatrix sampleM;
311 sampleM.setIDiv(texture->width(), texture->height());
312 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
313 GrSamplerState::kConvolution_Filter,
314 sampleM);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000315 drawState->sampler(0)->setCustomStage(
316 new GrConvolutionEffect(direction, kernelWidth, kernel));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000317 drawState->setTexture(0, texture);
318 gpu->drawSimpleRect(rect, NULL, 1 << 0);
319}
320
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000321}
322
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000323GrContext::TextureCacheEntry GrContext::findAndLockTexture(
324 TextureKey key,
325 int width,
326 int height,
327 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000328 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000329 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000330 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000331 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
332 GrResourceCache::kNested_LockType));
333}
334
bsalomon@google.comfb309512011-11-30 14:13:48 +0000335bool GrContext::isTextureInCache(TextureKey key,
336 int width,
337 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000338 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000339 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000340 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000341 GrResourceKey resourceKey(v);
342 return fTextureCache->hasKey(resourceKey);
343}
344
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000345GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000346 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000347 uint32_t v[4];
348 gen_stencil_key_values(sb, v);
349 GrResourceKey resourceKey(v);
350 return fTextureCache->createAndLock(resourceKey, sb);
351}
352
353GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
354 int sampleCnt) {
355 uint32_t v[4];
356 gen_stencil_key_values(width, height, sampleCnt, v);
357 GrResourceKey resourceKey(v);
358 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
359 GrResourceCache::kSingle_LockType);
360 if (NULL != entry) {
361 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
362 return sb;
363 } else {
364 return NULL;
365 }
366}
367
368void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000369 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000370 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000371}
372
373static void stretchImage(void* dst,
374 int dstW,
375 int dstH,
376 void* src,
377 int srcW,
378 int srcH,
379 int bpp) {
380 GrFixed dx = (srcW << 16) / dstW;
381 GrFixed dy = (srcH << 16) / dstH;
382
383 GrFixed y = dy >> 1;
384
385 int dstXLimit = dstW*bpp;
386 for (int j = 0; j < dstH; ++j) {
387 GrFixed x = dx >> 1;
388 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
389 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
390 for (int i = 0; i < dstXLimit; i += bpp) {
391 memcpy((uint8_t*) dstRow + i,
392 (uint8_t*) srcRow + (x>>16)*bpp,
393 bpp);
394 x += dx;
395 }
396 y += dy;
397 }
398}
399
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000400GrContext::TextureCacheEntry GrContext::createAndLockTexture(
401 TextureKey key,
402 const GrSamplerState* sampler,
403 const GrTextureDesc& desc,
404 void* srcData,
405 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000406 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000407
408#if GR_DUMP_TEXTURE_UPLOAD
409 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
410#endif
411
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412 TextureCacheEntry entry;
413 uint32_t v[4];
414 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000415 desc.fWidth, desc.fHeight,
416 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000417 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000419 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000420 GrAssert(NULL != sampler);
421 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
422 desc.fWidth,
423 desc.fHeight,
424 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000425
426 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000427 clampEntry = this->createAndLockTexture(key, NULL, desc,
428 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000429 GrAssert(NULL != clampEntry.texture());
430 if (NULL == clampEntry.texture()) {
431 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000432 }
433 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000434 GrTextureDesc rtDesc = desc;
435 rtDesc.fFlags = rtDesc.fFlags |
436 kRenderTarget_GrTextureFlagBit |
437 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000438 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
439 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000440
441 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
442
443 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000444 GrDrawTarget::AutoStateRestore asr(fGpu,
445 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000446 GrDrawState* drawState = fGpu->drawState();
447 drawState->setRenderTarget(texture->asRenderTarget());
448 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000449
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000450 GrSamplerState::Filter filter;
451 // if filtering is not desired then we want to ensure all
452 // texels in the resampled image are copies of texels from
453 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000454 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000455 filter = GrSamplerState::kNearest_Filter;
456 } else {
457 filter = GrSamplerState::kBilinear_Filter;
458 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000459 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
460 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000461
462 static const GrVertexLayout layout =
463 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
464 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
465
466 if (arg.succeeded()) {
467 GrPoint* verts = (GrPoint*) arg.vertices();
468 verts[0].setIRectFan(0, 0,
469 texture->width(),
470 texture->height(),
471 2*sizeof(GrPoint));
472 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
473 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
474 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000475 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000476 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000477 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000478 } else {
479 // TODO: Our CPU stretch doesn't filter. But we create separate
480 // stretched textures when the sampler state is either filtered or
481 // not. Either implement filtered stretch blit on CPU or just create
482 // one when FBO case fails.
483
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000484 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000485 // no longer need to clamp at min RT size.
486 rtDesc.fWidth = GrNextPow2(desc.fWidth);
487 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000488 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000489 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000490 rtDesc.fWidth *
491 rtDesc.fHeight);
492 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
493 srcData, desc.fWidth, desc.fHeight, bpp);
494
495 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
496
497 GrTexture* texture = fGpu->createTexture(rtDesc,
498 stretchedPixels.get(),
499 stretchedRowBytes);
500 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000501 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000502 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000503 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000504
505 } else {
506 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
507 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000508 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000509 }
510 }
511 return entry;
512}
513
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000514namespace {
515inline void gen_scratch_tex_key_values(const GrGpu* gpu,
516 const GrTextureDesc& desc,
517 uint32_t v[4]) {
518 // Instead of a client-provided key of the texture contents
519 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000520 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000521 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000522 // this code path isn't friendly to tiling with NPOT restricitons
523 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000524 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000525 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000526}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000527}
528
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000529GrContext::TextureCacheEntry GrContext::lockScratchTexture(
530 const GrTextureDesc& inDesc,
531 ScratchTexMatch match) {
532
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000533 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000534 if (kExact_ScratchTexMatch != match) {
535 // bin by pow2 with a reasonable min
536 static const int MIN_SIZE = 256;
537 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
538 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
539 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000540
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000541 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000542 int origWidth = desc.fWidth;
543 int origHeight = desc.fHeight;
544 bool doubledW = false;
545 bool doubledH = false;
546
547 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000548 uint32_t v[4];
549 gen_scratch_tex_key_values(fGpu, desc, v);
550 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000551 entry = fTextureCache->findAndLock(key,
552 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000553 // if we miss, relax the fit of the flags...
554 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000555 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000556 break;
557 }
558 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
559 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
560 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
561 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
562 } else if (!doubledW) {
563 desc.fFlags = inDesc.fFlags;
564 desc.fWidth *= 2;
565 doubledW = true;
566 } else if (!doubledH) {
567 desc.fFlags = inDesc.fFlags;
568 desc.fWidth = origWidth;
569 desc.fHeight *= 2;
570 doubledH = true;
571 } else {
572 break;
573 }
574
575 } while (true);
576
577 if (NULL == entry) {
578 desc.fFlags = inDesc.fFlags;
579 desc.fWidth = origWidth;
580 desc.fHeight = origHeight;
581 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
582 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000583 uint32_t v[4];
584 gen_scratch_tex_key_values(fGpu, desc, v);
585 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000586 entry = fTextureCache->createAndLock(key, texture);
587 }
588 }
589
590 // If the caller gives us the same desc/sampler twice we don't want
591 // to return the same texture the second time (unless it was previously
592 // released). So we detach the entry from the cache and reattach at release.
593 if (NULL != entry) {
594 fTextureCache->detach(entry);
595 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000596 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000597}
598
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000599void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000600 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000601 // If this is a scratch texture we detached it from the cache
602 // while it was locked (to avoid two callers simultaneously getting
603 // the same texture).
604 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
605 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000606 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000607 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000608 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000609}
610
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000611GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000612 void* srcData,
613 size_t rowBytes) {
614 return fGpu->createTexture(desc, srcData, rowBytes);
615}
616
617void GrContext::getTextureCacheLimits(int* maxTextures,
618 size_t* maxTextureBytes) const {
619 fTextureCache->getLimits(maxTextures, maxTextureBytes);
620}
621
622void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
623 fTextureCache->setLimits(maxTextures, maxTextureBytes);
624}
625
bsalomon@google.com91958362011-06-13 17:58:13 +0000626int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000627 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000628}
629
630int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000631 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000632}
633
634///////////////////////////////////////////////////////////////////////////////
635
bsalomon@google.come269f212011-11-07 13:29:52 +0000636GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
637 return fGpu->createPlatformTexture(desc);
638}
639
640GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
641 return fGpu->createPlatformRenderTarget(desc);
642}
643
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000644///////////////////////////////////////////////////////////////////////////////
645
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000646bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000647 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000648 const GrDrawTarget::Caps& caps = fGpu->getCaps();
649 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000650 return false;
651 }
652
bsalomon@google.com27847de2011-02-22 20:59:41 +0000653 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
654
655 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000656 bool tiled = NULL != sampler &&
657 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
658 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000659 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000660 return false;
661 }
662 }
663 return true;
664}
665
666////////////////////////////////////////////////////////////////////////////////
667
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000668const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
669
bsalomon@google.com27847de2011-02-22 20:59:41 +0000670void GrContext::setClip(const GrClip& clip) {
671 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000672 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000673}
674
675void GrContext::setClip(const GrIRect& rect) {
676 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000677 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000678 fGpu->setClip(clip);
679}
680
681////////////////////////////////////////////////////////////////////////////////
682
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000683void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000684 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000685 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000686}
687
688void GrContext::drawPaint(const GrPaint& paint) {
689 // set rect to be big enough to fill the space, but not super-huge, so we
690 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000691 GrRect r;
692 r.setLTRB(0, 0,
693 GrIntToScalar(getRenderTarget()->width()),
694 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000695 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000696 SkTLazy<GrPaint> tmpPaint;
697 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000698 GrAutoMatrix am;
699
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000700 // We attempt to map r by the inverse matrix and draw that. mapRect will
701 // map the four corners and bound them with a new rect. This will not
702 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000703 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000704 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000705 GrPrintf("Could not invert matrix");
706 return;
707 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000708 inverse.mapRect(&r);
709 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000710 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000711 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000712 GrPrintf("Could not invert matrix");
713 return;
714 }
715 tmpPaint.set(paint);
716 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
717 p = tmpPaint.get();
718 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000719 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000720 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000721 // by definition this fills the entire clip, no need for AA
722 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000723 if (!tmpPaint.isValid()) {
724 tmpPaint.set(paint);
725 p = tmpPaint.get();
726 }
727 GrAssert(p == tmpPaint.get());
728 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000729 }
730 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000731}
732
bsalomon@google.com205d4602011-04-25 12:43:45 +0000733////////////////////////////////////////////////////////////////////////////////
734
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000735namespace {
736inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
737 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
738}
739}
740
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000741////////////////////////////////////////////////////////////////////////////////
742
bsalomon@google.com27847de2011-02-22 20:59:41 +0000743/* create a triangle strip that strokes the specified triangle. There are 8
744 unique vertices, but we repreat the last 2 to close up. Alternatively we
745 could use an indices array, and then only send 8 verts, but not sure that
746 would be faster.
747 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000748static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000749 GrScalar width) {
750 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000751 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000752
753 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
754 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
755 verts[2].set(rect.fRight - rad, rect.fTop + rad);
756 verts[3].set(rect.fRight + rad, rect.fTop - rad);
757 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
758 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
759 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
760 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
761 verts[8] = verts[0];
762 verts[9] = verts[1];
763}
764
bsalomon@google.com205d4602011-04-25 12:43:45 +0000765static void setInsetFan(GrPoint* pts, size_t stride,
766 const GrRect& r, GrScalar dx, GrScalar dy) {
767 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
768}
769
770static const uint16_t gFillAARectIdx[] = {
771 0, 1, 5, 5, 4, 0,
772 1, 2, 6, 6, 5, 1,
773 2, 3, 7, 7, 6, 2,
774 3, 0, 4, 4, 7, 3,
775 4, 5, 6, 6, 7, 4,
776};
777
778int GrContext::aaFillRectIndexCount() const {
779 return GR_ARRAY_COUNT(gFillAARectIdx);
780}
781
782GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
783 if (NULL == fAAFillRectIndexBuffer) {
784 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
785 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000786 if (NULL != fAAFillRectIndexBuffer) {
787 #if GR_DEBUG
788 bool updated =
789 #endif
790 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
791 sizeof(gFillAARectIdx));
792 GR_DEBUGASSERT(updated);
793 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000794 }
795 return fAAFillRectIndexBuffer;
796}
797
798static const uint16_t gStrokeAARectIdx[] = {
799 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
800 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
801 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
802 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
803
804 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
805 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
806 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
807 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
808
809 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
810 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
811 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
812 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
813};
814
815int GrContext::aaStrokeRectIndexCount() const {
816 return GR_ARRAY_COUNT(gStrokeAARectIdx);
817}
818
819GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
820 if (NULL == fAAStrokeRectIndexBuffer) {
821 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
822 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000823 if (NULL != fAAStrokeRectIndexBuffer) {
824 #if GR_DEBUG
825 bool updated =
826 #endif
827 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
828 sizeof(gStrokeAARectIdx));
829 GR_DEBUGASSERT(updated);
830 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000831 }
832 return fAAStrokeRectIndexBuffer;
833}
834
bsalomon@google.coma3108262011-10-10 14:08:47 +0000835static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
836 bool useCoverage) {
837 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000838 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000839 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000840 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
841 }
842 }
843 if (useCoverage) {
844 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
845 } else {
846 layout |= GrDrawTarget::kColor_VertexLayoutBit;
847 }
848 return layout;
849}
850
bsalomon@google.com205d4602011-04-25 12:43:45 +0000851void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000852 const GrRect& devRect,
853 bool useVertexCoverage) {
854 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000855
856 size_t vsize = GrDrawTarget::VertexSize(layout);
857
858 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000859 if (!geo.succeeded()) {
860 GrPrintf("Failed to get space for vertices!\n");
861 return;
862 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000863 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
864 if (NULL == indexBuffer) {
865 GrPrintf("Failed to create index buffer!\n");
866 return;
867 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000868
869 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
870
871 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
872 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
873
874 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
875 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
876
877 verts += sizeof(GrPoint);
878 for (int i = 0; i < 4; ++i) {
879 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
880 }
881
bsalomon@google.coma3108262011-10-10 14:08:47 +0000882 GrColor innerColor;
883 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000884 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000885 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000886 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000887 }
888
bsalomon@google.com205d4602011-04-25 12:43:45 +0000889 verts += 4 * vsize;
890 for (int i = 0; i < 4; ++i) {
891 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
892 }
893
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000894 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000895
896 target->drawIndexed(kTriangles_PrimitiveType, 0,
897 0, 8, this->aaFillRectIndexCount());
898}
899
bsalomon@google.coma3108262011-10-10 14:08:47 +0000900void GrContext::strokeAARect(GrDrawTarget* target,
901 const GrRect& devRect,
902 const GrVec& devStrokeSize,
903 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000904 const GrScalar& dx = devStrokeSize.fX;
905 const GrScalar& dy = devStrokeSize.fY;
906 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
907 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
908
bsalomon@google.com205d4602011-04-25 12:43:45 +0000909 GrScalar spare;
910 {
911 GrScalar w = devRect.width() - dx;
912 GrScalar h = devRect.height() - dy;
913 spare = GrMin(w, h);
914 }
915
916 if (spare <= 0) {
917 GrRect r(devRect);
918 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000919 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000920 return;
921 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000922 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000923 size_t vsize = GrDrawTarget::VertexSize(layout);
924
925 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000926 if (!geo.succeeded()) {
927 GrPrintf("Failed to get space for vertices!\n");
928 return;
929 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000930 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
931 if (NULL == indexBuffer) {
932 GrPrintf("Failed to create index buffer!\n");
933 return;
934 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000935
936 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
937
938 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
939 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
940 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
941 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
942
943 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
944 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
945 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
946 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
947
948 verts += sizeof(GrPoint);
949 for (int i = 0; i < 4; ++i) {
950 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
951 }
952
bsalomon@google.coma3108262011-10-10 14:08:47 +0000953 GrColor innerColor;
954 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000955 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000956 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000957 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000958 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000959 verts += 4 * vsize;
960 for (int i = 0; i < 8; ++i) {
961 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
962 }
963
964 verts += 8 * vsize;
965 for (int i = 0; i < 8; ++i) {
966 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
967 }
968
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000969 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000970 target->drawIndexed(kTriangles_PrimitiveType,
971 0, 0, 16, aaStrokeRectIndexCount());
972}
973
reed@google.com20efde72011-05-09 17:00:02 +0000974/**
975 * Returns true if the rects edges are integer-aligned.
976 */
977static bool isIRect(const GrRect& r) {
978 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
979 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
980}
981
bsalomon@google.com205d4602011-04-25 12:43:45 +0000982static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000983 const GrRect& rect,
984 GrScalar width,
985 const GrMatrix* matrix,
986 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000987 GrRect* devRect,
988 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000989 // we use a simple coverage ramp to do aa on axis-aligned rects
990 // we check if the rect will be axis-aligned, and the rect won't land on
991 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000992
bsalomon@google.coma3108262011-10-10 14:08:47 +0000993 // we are keeping around the "tweak the alpha" trick because
994 // it is our only hope for the fixed-pipe implementation.
995 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000996 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000997 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000998 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000999 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001000#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001001 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001002#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001003 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001004 } else {
1005 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001006 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001007 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001008 const GrDrawState& drawState = target->getDrawState();
1009 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001010 return false;
1011 }
1012
bsalomon@google.com471d4712011-08-23 15:45:25 +00001013 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001014 return false;
1015 }
1016
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001017 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001018 return false;
1019 }
1020
1021 if (NULL != matrix &&
1022 !matrix->preservesAxisAlignment()) {
1023 return false;
1024 }
1025
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001026 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001027 if (NULL != matrix) {
1028 combinedMatrix->preConcat(*matrix);
1029 GrAssert(combinedMatrix->preservesAxisAlignment());
1030 }
1031
1032 combinedMatrix->mapRect(devRect, rect);
1033 devRect->sort();
1034
1035 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001036 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001037 } else {
1038 return true;
1039 }
1040}
1041
bsalomon@google.com27847de2011-02-22 20:59:41 +00001042void GrContext::drawRect(const GrPaint& paint,
1043 const GrRect& rect,
1044 GrScalar width,
1045 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001046 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001047
1048 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001049 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001050
bsalomon@google.com205d4602011-04-25 12:43:45 +00001051 GrRect devRect = rect;
1052 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001053 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001054 bool needAA = paint.fAntiAlias &&
1055 !this->getRenderTarget()->isMultisampled();
1056 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1057 &combinedMatrix, &devRect,
1058 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059
1060 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001061 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001062 if (width >= 0) {
1063 GrVec strokeSize;;
1064 if (width > 0) {
1065 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001066 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001067 strokeSize.setAbs(strokeSize);
1068 } else {
1069 strokeSize.set(GR_Scalar1, GR_Scalar1);
1070 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001071 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001072 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001073 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001074 }
1075 return;
1076 }
1077
bsalomon@google.com27847de2011-02-22 20:59:41 +00001078 if (width >= 0) {
1079 // TODO: consider making static vertex buffers for these cases.
1080 // Hairline could be done by just adding closing vertex to
1081 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001082 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1083
bsalomon@google.com27847de2011-02-22 20:59:41 +00001084 static const int worstCaseVertCount = 10;
1085 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1086
1087 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001088 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001089 return;
1090 }
1091
1092 GrPrimitiveType primType;
1093 int vertCount;
1094 GrPoint* vertex = geo.positions();
1095
1096 if (width > 0) {
1097 vertCount = 10;
1098 primType = kTriangleStrip_PrimitiveType;
1099 setStrokeRectStrip(vertex, rect, width);
1100 } else {
1101 // hairline
1102 vertCount = 5;
1103 primType = kLineStrip_PrimitiveType;
1104 vertex[0].set(rect.fLeft, rect.fTop);
1105 vertex[1].set(rect.fRight, rect.fTop);
1106 vertex[2].set(rect.fRight, rect.fBottom);
1107 vertex[3].set(rect.fLeft, rect.fBottom);
1108 vertex[4].set(rect.fLeft, rect.fTop);
1109 }
1110
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001111 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001112 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001113 GrDrawState* drawState = target->drawState();
1114 avmr.set(drawState);
1115 drawState->preConcatViewMatrix(*matrix);
1116 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001117 }
1118
1119 target->drawNonIndexed(primType, 0, vertCount);
1120 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001121#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001122 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001123 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1124 if (NULL == sqVB) {
1125 GrPrintf("Failed to create static rect vb.\n");
1126 return;
1127 }
1128 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001129 GrDrawState* drawState = target->drawState();
1130 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001131 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001132 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001133 0, rect.height(), rect.fTop,
1134 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001135
1136 if (NULL != matrix) {
1137 m.postConcat(*matrix);
1138 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001139 drawState->preConcatViewMatrix(m);
1140 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001141
bsalomon@google.com27847de2011-02-22 20:59:41 +00001142 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001143#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001144 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001145#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 }
1147}
1148
1149void GrContext::drawRectToRect(const GrPaint& paint,
1150 const GrRect& dstRect,
1151 const GrRect& srcRect,
1152 const GrMatrix* dstMatrix,
1153 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001154 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001155
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001156 // srcRect refers to paint's first texture
1157 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001158 drawRect(paint, dstRect, -1, dstMatrix);
1159 return;
1160 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001161
bsalomon@google.com27847de2011-02-22 20:59:41 +00001162 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1163
1164#if GR_STATIC_RECT_VB
1165 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001166 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001167 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001168 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001169
1170 GrMatrix m;
1171
1172 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1173 0, dstRect.height(), dstRect.fTop,
1174 0, 0, GrMatrix::I()[8]);
1175 if (NULL != dstMatrix) {
1176 m.postConcat(*dstMatrix);
1177 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001178 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001179
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001180 // srcRect refers to first stage
1181 int otherStageMask = paint.getActiveStageMask() &
1182 (~(1 << GrPaint::kFirstTextureStage));
1183 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001184 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001185 }
1186
bsalomon@google.com27847de2011-02-22 20:59:41 +00001187 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1188 0, srcRect.height(), srcRect.fTop,
1189 0, 0, GrMatrix::I()[8]);
1190 if (NULL != srcMatrix) {
1191 m.postConcat(*srcMatrix);
1192 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001193 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001194
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001195 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1196 if (NULL == sqVB) {
1197 GrPrintf("Failed to create static rect vb.\n");
1198 return;
1199 }
1200 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001201 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1202#else
1203
1204 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001205#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001206 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001207#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001208 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1209#endif
1210
tomhudson@google.com93813632011-10-27 20:21:16 +00001211 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1212 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001213 srcRects[0] = &srcRect;
1214 srcMatrices[0] = srcMatrix;
1215
1216 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1217#endif
1218}
1219
1220void GrContext::drawVertices(const GrPaint& paint,
1221 GrPrimitiveType primitiveType,
1222 int vertexCount,
1223 const GrPoint positions[],
1224 const GrPoint texCoords[],
1225 const GrColor colors[],
1226 const uint16_t indices[],
1227 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001228 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229
1230 GrDrawTarget::AutoReleaseGeometry geo;
1231
1232 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1233
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001234 bool hasTexCoords[GrPaint::kTotalStages] = {
1235 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1236 0 // remaining stages use positions
1237 };
1238
1239 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240
1241 if (NULL != colors) {
1242 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001243 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001244 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001245
1246 if (sizeof(GrPoint) != vertexSize) {
1247 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001248 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001249 return;
1250 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001251 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001252 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1254 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001255 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001256 NULL,
1257 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258 void* curVertex = geo.vertices();
1259
1260 for (int i = 0; i < vertexCount; ++i) {
1261 *((GrPoint*)curVertex) = positions[i];
1262
1263 if (texOffsets[0] > 0) {
1264 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1265 }
1266 if (colorOffset > 0) {
1267 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1268 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001269 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001270 }
1271 } else {
1272 target->setVertexSourceToArray(layout, positions, vertexCount);
1273 }
1274
bsalomon@google.com91958362011-06-13 17:58:13 +00001275 // we don't currently apply offscreen AA to this path. Need improved
1276 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001277
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001278 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001279 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001280 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001281 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001282 target->drawNonIndexed(primitiveType, 0, vertexCount);
1283 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001284}
1285
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001286///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001287namespace {
1288
bsalomon@google.com93c96602012-04-27 13:05:21 +00001289struct CircleVertex {
1290 GrPoint fPos;
1291 GrPoint fCenter;
1292 GrScalar fOuterRadius;
1293 GrScalar fInnerRadius;
1294};
1295
1296/* Returns true if will map a circle to another circle. This can be true
1297 * if the matrix only includes square-scale, rotation, translation.
1298 */
1299inline bool isSimilarityTransformation(const SkMatrix& matrix,
1300 SkScalar tol = SK_ScalarNearlyZero) {
1301 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1302 return true;
1303 }
1304 if (matrix.hasPerspective()) {
1305 return false;
1306 }
1307
1308 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1309 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1310 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1311 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1312
1313 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1314 return false;
1315 }
1316
1317 // it has scales or skews, but it could also be rotation, check it out.
1318 SkVector vec[2];
1319 vec[0].set(mx, sx);
1320 vec[1].set(sy, my);
1321
1322 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1323 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1324 SkScalarSquare(tol));
1325}
1326
1327}
1328
1329// TODO: strokeWidth can't be larger than zero right now.
1330// It will be fixed when drawPath() can handle strokes.
1331void GrContext::drawOval(const GrPaint& paint,
1332 const GrRect& rect,
1333 SkScalar strokeWidth) {
1334 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1335 kUnbuffered_DrawCategory;
1336 GrDrawTarget* target = this->prepareToDraw(paint, category);
1337 GrDrawState* drawState = target->drawState();
1338 GrMatrix vm = drawState->getViewMatrix();
1339
1340 if (!isSimilarityTransformation(vm) ||
1341 !paint.fAntiAlias ||
1342 rect.height() != rect.width()) {
1343 SkPath path;
1344 path.addOval(rect);
1345 GrPathFill fill = (strokeWidth == 0) ?
1346 kHairLine_PathFill : kWinding_PathFill;
1347 this->internalDrawPath(paint, path, fill, NULL);
1348 return;
1349 }
1350
1351 const GrRenderTarget* rt = drawState->getRenderTarget();
1352 if (NULL == rt) {
1353 return;
1354 }
1355
1356 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1357
1358 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1359 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1360 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1361
1362 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1363 GrScalar radius = SkScalarHalf(rect.width());
1364
1365 vm.mapPoints(&center, 1);
1366 radius = vm.mapRadius(radius);
1367
1368 GrScalar outerRadius = radius;
1369 GrScalar innerRadius = 0;
1370 SkScalar halfWidth = 0;
1371 if (strokeWidth == 0) {
1372 halfWidth = SkScalarHalf(SK_Scalar1);
1373
1374 outerRadius += halfWidth;
1375 innerRadius = SkMaxScalar(0, radius - halfWidth);
1376 }
1377
1378 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1379 if (!geo.succeeded()) {
1380 GrPrintf("Failed to get space for vertices!\n");
1381 return;
1382 }
1383
1384 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1385
1386 SkScalar L = center.fX - outerRadius;
1387 SkScalar R = center.fX + outerRadius;
1388 SkScalar T = center.fY - outerRadius;
1389 SkScalar B = center.fY + outerRadius;
1390
1391 verts[0].fPos = SkPoint::Make(L, T);
1392 verts[1].fPos = SkPoint::Make(R, T);
1393 verts[2].fPos = SkPoint::Make(L, B);
1394 verts[3].fPos = SkPoint::Make(R, B);
1395
1396 for (int i = 0; i < 4; ++i) {
1397 // this goes to fragment shader, it should be in y-points-up space.
1398 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1399
1400 verts[i].fOuterRadius = outerRadius;
1401 verts[i].fInnerRadius = innerRadius;
1402 }
1403
1404 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1405 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001406}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001407
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001408void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001409 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001411 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001412 if (GrIsFillInverted(fill)) {
1413 this->drawPaint(paint);
1414 }
1415 return;
1416 }
1417
bsalomon@google.com93c96602012-04-27 13:05:21 +00001418 SkRect ovalRect;
1419 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1420 if (translate) {
1421 ovalRect.offset(*translate);
1422 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001423 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001424 this->drawOval(paint, ovalRect, width);
1425 return;
1426 }
1427
1428 internalDrawPath(paint, path, fill, translate);
1429}
1430
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001431void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001432 GrPathFill fill, const GrPoint* translate) {
1433
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001434 // Note that below we may sw-rasterize the path into a scratch texture.
1435 // Scratch textures can be recycled after they are returned to the texture
1436 // cache. This presents a potential hazard for buffered drawing. However,
1437 // the writePixels that uploads to the scratch will perform a flush so we're
1438 // OK.
1439 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1440 kUnbuffered_DrawCategory;
1441 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001442 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001443
bsalomon@google.com289533a2011-10-27 12:34:25 +00001444 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1445
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001446 // An Assumption here is that path renderer would use some form of tweaking
1447 // the src color (either the input alpha or in the frag shader) to implement
1448 // aa. If we have some future driver-mojo path AA that can do the right
1449 // thing WRT to the blend then we'll need some query on the PR.
1450 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001451#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001452 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001453#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001454 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001455 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001456
robertphillips@google.comed4155d2012-05-01 14:30:24 +00001457 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA);
bsalomon@google.com30085192011-08-19 15:42:31 +00001458 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001459#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001460 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001461#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001462 return;
1463 }
1464
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001465 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001467
bsalomon@google.com27847de2011-02-22 20:59:41 +00001468////////////////////////////////////////////////////////////////////////////////
1469
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001470void GrContext::flush(int flagsBitfield) {
1471 if (kDiscard_FlushBit & flagsBitfield) {
1472 fDrawBuffer->reset();
1473 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001474 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001475 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001476 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001477 fGpu->forceRenderTargetFlush();
1478 }
1479}
1480
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001482 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001483 // With addition of the AA clip path, flushing the draw buffer can
1484 // result in the generation of an AA clip mask. During this
1485 // process the SW path renderer may be invoked which recusively
1486 // calls this method (via internalWriteTexturePixels) creating
1487 // infinite recursion
1488 GrInOrderDrawBuffer* temp = fDrawBuffer;
1489 fDrawBuffer = NULL;
1490
1491 temp->flushTo(fGpu);
1492
1493 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001494 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001495}
1496
bsalomon@google.com6f379512011-11-16 20:36:03 +00001497void GrContext::internalWriteTexturePixels(GrTexture* texture,
1498 int left, int top,
1499 int width, int height,
1500 GrPixelConfig config,
1501 const void* buffer,
1502 size_t rowBytes,
1503 uint32_t flags) {
1504 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001505 ASSERT_OWNED_RESOURCE(texture);
1506
bsalomon@google.com6f379512011-11-16 20:36:03 +00001507 if (!(kDontFlush_PixelOpsFlag & flags)) {
1508 this->flush();
1509 }
1510 // TODO: use scratch texture to perform conversion
1511 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1512 GrPixelConfigIsUnpremultiplied(config)) {
1513 return;
1514 }
1515
1516 fGpu->writeTexturePixels(texture, left, top, width, height,
1517 config, buffer, rowBytes);
1518}
1519
1520bool GrContext::internalReadTexturePixels(GrTexture* texture,
1521 int left, int top,
1522 int width, int height,
1523 GrPixelConfig config,
1524 void* buffer,
1525 size_t rowBytes,
1526 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001527 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001528 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001529
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001530 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001531 GrRenderTarget* target = texture->asRenderTarget();
1532 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001533 return this->internalReadRenderTargetPixels(target,
1534 left, top, width, height,
1535 config, buffer, rowBytes,
1536 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001537 } else {
1538 return false;
1539 }
1540}
1541
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001542#include "SkConfig8888.h"
1543
1544namespace {
1545/**
1546 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1547 * formats are representable as Config8888 and so the function returns false
1548 * if the GrPixelConfig has no equivalent Config8888.
1549 */
1550bool grconfig_to_config8888(GrPixelConfig config,
1551 SkCanvas::Config8888* config8888) {
1552 switch (config) {
1553 case kRGBA_8888_PM_GrPixelConfig:
1554 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1555 return true;
1556 case kRGBA_8888_UPM_GrPixelConfig:
1557 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1558 return true;
1559 case kBGRA_8888_PM_GrPixelConfig:
1560 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1561 return true;
1562 case kBGRA_8888_UPM_GrPixelConfig:
1563 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1564 return true;
1565 default:
1566 return false;
1567 }
1568}
1569}
1570
bsalomon@google.com6f379512011-11-16 20:36:03 +00001571bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1572 int left, int top,
1573 int width, int height,
1574 GrPixelConfig config,
1575 void* buffer,
1576 size_t rowBytes,
1577 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001578 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001579 ASSERT_OWNED_RESOURCE(target);
1580
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001581 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001582 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001583 if (NULL == target) {
1584 return false;
1585 }
1586 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001587
bsalomon@google.com6f379512011-11-16 20:36:03 +00001588 if (!(kDontFlush_PixelOpsFlag & flags)) {
1589 this->flush();
1590 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001591
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001592 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1593 GrPixelConfigIsUnpremultiplied(config) &&
1594 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1595 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1596 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1597 !grconfig_to_config8888(config, &dstConfig8888)) {
1598 return false;
1599 }
1600 // do read back using target's own config
1601 this->internalReadRenderTargetPixels(target,
1602 left, top,
1603 width, height,
1604 target->config(),
1605 buffer, rowBytes,
1606 kDontFlush_PixelOpsFlag);
1607 // sw convert the pixels to unpremul config
1608 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1609 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1610 pixels, rowBytes, srcConfig8888,
1611 width, height);
1612 return true;
1613 }
1614
bsalomon@google.comc4364992011-11-07 15:54:49 +00001615 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001616 bool swapRAndB = NULL != src &&
1617 fGpu->preferredReadPixelsConfig(config) ==
1618 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001619
1620 bool flipY = NULL != src &&
1621 fGpu->readPixelsWillPayForYFlip(target, left, top,
1622 width, height, config,
1623 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001624 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1625 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001626
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001627 if (NULL == src && alphaConversion) {
1628 // we should fallback to cpu conversion here. This could happen when
1629 // we were given an external render target by the client that is not
1630 // also a texture (e.g. FBO 0 in GL)
1631 return false;
1632 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001633 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001634 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001635 if (flipY || swapRAndB || alphaConversion) {
1636 GrAssert(NULL != src);
1637 if (swapRAndB) {
1638 config = GrPixelConfigSwapRAndB(config);
1639 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001640 }
1641 // Make the scratch a render target because we don't have a robust
1642 // readTexturePixels as of yet (it calls this function).
1643 const GrTextureDesc desc = {
1644 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001645 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001646 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001647 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001648 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001649
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001650 // When a full readback is faster than a partial we could always make
1651 // the scratch exactly match the passed rect. However, if we see many
1652 // different size rectangles we will trash our texture cache and pay the
1653 // cost of creating and destroying many textures. So, we only request
1654 // an exact match when the caller is reading an entire RT.
1655 ScratchTexMatch match = kApprox_ScratchTexMatch;
1656 if (0 == left &&
1657 0 == top &&
1658 target->width() == width &&
1659 target->height() == height &&
1660 fGpu->fullReadPixelsIsFasterThanPartial()) {
1661 match = kExact_ScratchTexMatch;
1662 }
1663 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001664 GrTexture* texture = ast.texture();
1665 if (!texture) {
1666 return false;
1667 }
1668 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001669 GrAssert(NULL != target);
1670
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001671 GrDrawTarget::AutoStateRestore asr(fGpu,
1672 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001673 GrDrawState* drawState = fGpu->drawState();
1674 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001675
bsalomon@google.comc4364992011-11-07 15:54:49 +00001676 GrMatrix matrix;
1677 if (flipY) {
1678 matrix.setTranslate(SK_Scalar1 * left,
1679 SK_Scalar1 * (top + height));
1680 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1681 } else {
1682 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1683 }
1684 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001685 drawState->sampler(0)->reset(matrix);
1686 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001687 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001688 GrRect rect;
1689 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1690 fGpu->drawSimpleRect(rect, NULL, 0x1);
1691 left = 0;
1692 top = 0;
1693 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001694 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001695 left, top, width, height,
1696 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001697}
1698
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001699void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1700 GrAssert(target);
1701 ASSERT_OWNED_RESOURCE(target);
1702 // In the future we may track whether there are any pending draws to this
1703 // target. We don't today so we always perform a flush. We don't promise
1704 // this to our clients, though.
1705 this->flush();
1706 fGpu->resolveRenderTarget(target);
1707}
1708
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001709void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1710 if (NULL == src || NULL == dst) {
1711 return;
1712 }
1713 ASSERT_OWNED_RESOURCE(src);
1714
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001715 // Writes pending to the source texture are not tracked, so a flush
1716 // is required to ensure that the copy captures the most recent contents
1717 // of the source texture. See similar behaviour in
1718 // GrContext::resolveRenderTarget.
1719 this->flush();
1720
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001721 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001722 GrDrawState* drawState = fGpu->drawState();
1723 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001724 GrMatrix sampleM;
1725 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001726 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001727 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001728 SkRect rect = SkRect::MakeXYWH(0, 0,
1729 SK_Scalar1 * src->width(),
1730 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001731 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1732}
1733
bsalomon@google.com6f379512011-11-16 20:36:03 +00001734void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1735 int left, int top,
1736 int width, int height,
1737 GrPixelConfig config,
1738 const void* buffer,
1739 size_t rowBytes,
1740 uint32_t flags) {
1741 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001742 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001743
1744 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001745 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001746 if (NULL == target) {
1747 return;
1748 }
1749 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001750
1751 // TODO: when underlying api has a direct way to do this we should use it
1752 // (e.g. glDrawPixels on desktop GL).
1753
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001754 // If the RT is also a texture and we don't have to do PM/UPM conversion
1755 // then take the texture path, which we expect to be at least as fast or
1756 // faster since it doesn't use an intermediate texture as we do below.
1757
1758#if !GR_MAC_BUILD
1759 // At least some drivers on the Mac get confused when glTexImage2D is called
1760 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1761 // determine what OS versions and/or HW is affected.
1762 if (NULL != target->asTexture() &&
1763 GrPixelConfigIsUnpremultiplied(target->config()) ==
1764 GrPixelConfigIsUnpremultiplied(config)) {
1765
1766 this->internalWriteTexturePixels(target->asTexture(),
1767 left, top, width, height,
1768 config, buffer, rowBytes, flags);
1769 return;
1770 }
1771#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001772 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1773 GrPixelConfigIsUnpremultiplied(config) &&
1774 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1775 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1776 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1777 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1778 return;
1779 }
1780 // allocate a tmp buffer and sw convert the pixels to premul
1781 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1782 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1783 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1784 src, rowBytes, srcConfig8888,
1785 width, height);
1786 // upload the already premul pixels
1787 this->internalWriteRenderTargetPixels(target,
1788 left, top,
1789 width, height,
1790 target->config(),
1791 tmpPixels, 4 * width, flags);
1792 return;
1793 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001794
1795 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1796 GrPixelConfigSwapRAndB(config);
1797 if (swapRAndB) {
1798 config = GrPixelConfigSwapRAndB(config);
1799 }
1800
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001801 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001802 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001803 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001804 GrAutoScratchTexture ast(this, desc);
1805 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001806 if (NULL == texture) {
1807 return;
1808 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001809 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1810 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001811
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001812 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001813 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001814
1815 GrMatrix matrix;
1816 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001817 drawState->setViewMatrix(matrix);
1818 drawState->setRenderTarget(target);
1819 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001820
bsalomon@google.com5c638652011-07-18 19:31:59 +00001821 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001822 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1823 GrSamplerState::kNearest_Filter,
1824 matrix);
1825 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001826
1827 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1828 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001829 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1831 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001832 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001833 return;
1834 }
1835 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1836 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1837}
1838////////////////////////////////////////////////////////////////////////////////
1839
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001840void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001841
1842 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1843 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001844 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001845 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001846 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001847 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001848 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001849 }
1850
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001851 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001852
1853 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1854 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001855 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001856 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001857 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001858 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001859 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001860 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001861
1862 // disable all stages not accessible via the paint
1863 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001864 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001865 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001866
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001867 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868
1869 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001870 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001872 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001873 }
1874 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001875 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001876 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001877 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001878 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001879 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001880 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1881 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001882 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001883 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001884 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001885 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1886 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1887 fDrawState->setCoverage(paint.fCoverage);
reed@google.com4b2d3f32012-05-15 18:05:50 +00001888#if GR_DEBUG_PARTIAL_COVERAGE_CHECK
bsalomon@google.come79c8152012-03-29 19:07:12 +00001889 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001890 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001891 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1892 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001893#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001894}
1895
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001896GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001897 DrawCategory category) {
1898 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001899 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001900 fLastDrawCategory = category;
1901 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001902 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001903 GrDrawTarget* target = fGpu;
1904 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001905 case kUnbuffered_DrawCategory:
1906 target = fGpu;
1907 break;
1908 case kBuffered_DrawCategory:
1909 target = fDrawBuffer;
1910 fDrawBuffer->setClip(fGpu->getClip());
1911 break;
1912 default:
1913 GrCrash("Unexpected DrawCategory.");
1914 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001915 }
1916 return target;
1917}
1918
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001919GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001920 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001921 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001922 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001923 if (NULL == fPathRendererChain) {
1924 fPathRendererChain =
1925 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1926 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001927 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001928}
1929
bsalomon@google.com27847de2011-02-22 20:59:41 +00001930////////////////////////////////////////////////////////////////////////////////
1931
bsalomon@google.com27847de2011-02-22 20:59:41 +00001932void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001933 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001934 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001935 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001936 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001937 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938}
1939
1940GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001941 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001942}
1943
1944const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001945 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946}
1947
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001948bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1949 return fGpu->isConfigRenderable(config);
1950}
1951
bsalomon@google.com27847de2011-02-22 20:59:41 +00001952const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001953 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001954}
1955
1956void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001957 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001958}
1959
1960void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001961 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001962}
1963
1964static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1965 intptr_t mask = 1 << shift;
1966 if (pred) {
1967 bits |= mask;
1968 } else {
1969 bits &= ~mask;
1970 }
1971 return bits;
1972}
1973
1974void GrContext::resetStats() {
1975 fGpu->resetStats();
1976}
1977
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001978const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001979 return fGpu->getStats();
1980}
1981
1982void GrContext::printStats() const {
1983 fGpu->printStats();
1984}
1985
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001986GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001987 fGpu = gpu;
1988 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001989 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001990
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001991 fDrawState = new GrDrawState();
1992 fGpu->setDrawState(fDrawState);
1993
bsalomon@google.com30085192011-08-19 15:42:31 +00001994 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001995
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001996 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1997 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001998 fFontCache = new GrFontCache(fGpu);
1999
2000 fLastDrawCategory = kUnbuffered_DrawCategory;
2001
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002002 fDrawBuffer = NULL;
2003 fDrawBufferVBAllocPool = NULL;
2004 fDrawBufferIBAllocPool = NULL;
2005
bsalomon@google.com205d4602011-04-25 12:43:45 +00002006 fAAFillRectIndexBuffer = NULL;
2007 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002008
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002009 this->setupDrawBuffer();
2010}
2011
2012void GrContext::setupDrawBuffer() {
2013
2014 GrAssert(NULL == fDrawBuffer);
2015 GrAssert(NULL == fDrawBufferVBAllocPool);
2016 GrAssert(NULL == fDrawBufferIBAllocPool);
2017
bsalomon@google.com92edd312012-04-04 21:40:21 +00002018#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002019 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002020 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002021 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2022 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002023 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002024 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002025 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002026 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2027
bsalomon@google.com471d4712011-08-23 15:45:25 +00002028 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2029 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002030 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002031#endif
2032
2033#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002034 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002035#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002036 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002037 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002038}
2039
bsalomon@google.com27847de2011-02-22 20:59:41 +00002040GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002041#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002042 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002043#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002044 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002045#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002046}
2047
2048const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2049 return fGpu->getQuadIndexBuffer();
2050}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002051
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002052GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2053 GrAutoScratchTexture* temp1,
2054 GrAutoScratchTexture* temp2,
2055 const SkRect& rect,
2056 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002057 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002058 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2059 GrClip oldClip = this->getClip();
2060 GrTexture* origTexture = srcTexture;
2061 GrAutoMatrix avm(this, GrMatrix::I());
2062 SkIRect clearRect;
2063 int scaleFactorX, halfWidthX, kernelWidthX;
2064 int scaleFactorY, halfWidthY, kernelWidthY;
2065 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2066 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002067
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002068 SkRect srcRect(rect);
2069 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2070 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002071 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2072 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002073 this->setClip(srcRect);
2074
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002075 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2076 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2077 kAlpha_8_GrPixelConfig == srcTexture->config());
2078
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002079 const GrTextureDesc desc = {
2080 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002081 SkScalarFloorToInt(srcRect.width()),
2082 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002083 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002084 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002085 };
2086
2087 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002088 if (temp2) {
2089 temp2->set(this, desc);
2090 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002091
2092 GrTexture* dstTexture = temp1->texture();
2093 GrPaint paint;
2094 paint.reset();
2095 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2096
2097 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2098 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2099 srcTexture->height());
2100 this->setRenderTarget(dstTexture->asRenderTarget());
2101 SkRect dstRect(srcRect);
2102 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2103 i < scaleFactorY ? 0.5f : 1.0f);
2104 paint.setTexture(0, srcTexture);
2105 this->drawRectToRect(paint, dstRect, srcRect);
2106 srcRect = dstRect;
2107 SkTSwap(srcTexture, dstTexture);
2108 // If temp2 is non-NULL, don't render back to origTexture
2109 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2110 }
2111
robertphillips@google.com7a396332012-05-10 15:11:27 +00002112 SkIRect srcIRect;
2113 srcRect.roundOut(&srcIRect);
2114
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002115 if (sigmaX > 0.0f) {
2116 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2117 float* kernelX = kernelStorageX.get();
2118 build_kernel(sigmaX, kernelX, kernelWidthX);
2119
2120 if (scaleFactorX > 1) {
2121 // Clear out a halfWidth to the right of the srcRect to prevent the
2122 // X convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002123 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2124 halfWidthX, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002125 this->clear(&clearRect, 0x0);
2126 }
2127
2128 this->setRenderTarget(dstTexture->asRenderTarget());
2129 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2130 GrSamplerState::kX_FilterDirection);
2131 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002132 if (temp2 && dstTexture == origTexture) {
2133 dstTexture = temp2->texture();
2134 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002135 }
2136
2137 if (sigmaY > 0.0f) {
2138 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2139 float* kernelY = kernelStorageY.get();
2140 build_kernel(sigmaY, kernelY, kernelWidthY);
2141
2142 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2143 // Clear out a halfWidth below the srcRect to prevent the Y
2144 // convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002145 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2146 srcIRect.width(), halfWidthY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002147 this->clear(&clearRect, 0x0);
2148 }
2149
2150 this->setRenderTarget(dstTexture->asRenderTarget());
2151 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2152 GrSamplerState::kY_FilterDirection);
2153 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002154 if (temp2 && dstTexture == origTexture) {
2155 dstTexture = temp2->texture();
2156 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002157 }
2158
2159 if (scaleFactorX > 1 || scaleFactorY > 1) {
2160 // Clear one pixel to the right and below, to accommodate bilinear
2161 // upsampling.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002162 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2163 srcIRect.width() + 1, 1);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002164 this->clear(&clearRect, 0x0);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002165 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2166 1, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002167 this->clear(&clearRect, 0x0);
2168 // FIXME: This should be mitchell, not bilinear.
2169 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2170 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2171 srcTexture->height());
2172 this->setRenderTarget(dstTexture->asRenderTarget());
2173 paint.setTexture(0, srcTexture);
2174 SkRect dstRect(srcRect);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002175 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002176 this->drawRectToRect(paint, dstRect, srcRect);
2177 srcRect = dstRect;
2178 SkTSwap(srcTexture, dstTexture);
2179 }
2180 this->setRenderTarget(oldRenderTarget);
2181 this->setClip(oldClip);
2182 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002183}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002184
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002185GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2186 const GrRect& rect,
2187 GrTexture* temp1, GrTexture* temp2,
2188 GrSamplerState::Filter filter,
2189 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002190 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002191 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2192 GrAutoMatrix avm(this, GrMatrix::I());
2193 GrClip oldClip = this->getClip();
robertphillips@google.com7a396332012-05-10 15:11:27 +00002194 this->setClip(GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
2195 SkIntToScalar(srcTexture->height())));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002196 if (radius.fWidth > 0) {
2197 this->setRenderTarget(temp1->asRenderTarget());
2198 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2199 GrSamplerState::kX_FilterDirection);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002200 SkIRect clearRect = SkIRect::MakeXYWH(
2201 SkScalarFloorToInt(rect.fLeft),
2202 SkScalarFloorToInt(rect.fBottom),
2203 SkScalarFloorToInt(rect.width()),
2204 radius.fHeight);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002205 this->clear(&clearRect, 0x0);
2206 srcTexture = temp1;
2207 }
2208 if (radius.fHeight > 0) {
2209 this->setRenderTarget(temp2->asRenderTarget());
2210 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2211 GrSamplerState::kY_FilterDirection);
2212 srcTexture = temp2;
2213 }
2214 this->setRenderTarget(oldRenderTarget);
2215 this->setClip(oldClip);
2216 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002217}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002218
2219///////////////////////////////////////////////////////////////////////////////