blob: e5f95e6b5c532a9630ac85f38e7bb64cd4a4e7a0 [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"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
25#define DEFER_TEXT_RENDERING 1
26
27#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
28
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000029#define MAX_BLUR_SIGMA 4.0f
30
bsalomon@google.comd46e2422011-09-23 17:40:07 +000031// When we're using coverage AA but the blend is incompatible (given gpu
32// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000033#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000034
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000035static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
36static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000037
38static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
39static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
40
41// We are currently only batching Text and drawRectToRect, both
42// of which use the quad index buffer.
43static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
44static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
45
bsalomon@google.combc4b6542011-11-19 13:56:11 +000046#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
47
bsalomon@google.com05ef5102011-05-02 21:14:59 +000048GrContext* GrContext::Create(GrEngine engine,
49 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000050 GrContext* ctx = NULL;
51 GrGpu* fGpu = GrGpu::Create(engine, context3D);
52 if (NULL != fGpu) {
53 ctx = new GrContext(fGpu);
54 fGpu->unref();
55 }
56 return ctx;
57}
58
bsalomon@google.com27847de2011-02-22 20:59:41 +000059GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000060 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000061 delete fTextureCache;
62 delete fFontCache;
63 delete fDrawBuffer;
64 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000065 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000066
bsalomon@google.com205d4602011-04-25 12:43:45 +000067 GrSafeUnref(fAAFillRectIndexBuffer);
68 GrSafeUnref(fAAStrokeRectIndexBuffer);
69 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000070 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000071}
72
bsalomon@google.com8fe72472011-03-30 21:26:44 +000073void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000074 contextDestroyed();
75 this->setupDrawBuffer();
76}
77
78void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000079 // abandon first to so destructors
80 // don't try to free the resources in the API.
81 fGpu->abandonResources();
82
bsalomon@google.com30085192011-08-19 15:42:31 +000083 // a path renderer may be holding onto resources that
84 // are now unusable
85 GrSafeSetNull(fPathRendererChain);
86
bsalomon@google.com8fe72472011-03-30 21:26:44 +000087 delete fDrawBuffer;
88 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000089
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 delete fDrawBufferVBAllocPool;
91 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000092
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 delete fDrawBufferIBAllocPool;
94 fDrawBufferIBAllocPool = NULL;
95
bsalomon@google.com205d4602011-04-25 12:43:45 +000096 GrSafeSetNull(fAAFillRectIndexBuffer);
97 GrSafeSetNull(fAAStrokeRectIndexBuffer);
98
bsalomon@google.com8fe72472011-03-30 21:26:44 +000099 fTextureCache->removeAll();
100 fFontCache->freeAll();
101 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102}
103
104void GrContext::resetContext() {
105 fGpu->markContextDirty();
106}
107
108void GrContext::freeGpuResources() {
109 this->flush();
110 fTextureCache->removeAll();
111 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000112 // a path renderer may be holding onto resources
113 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000114}
115
twiz@google.com05e70242012-01-27 19:12:00 +0000116size_t GrContext::getGpuTextureCacheBytes() const {
117 return fTextureCache->getCachedResourceBytes();
118}
119
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000120////////////////////////////////////////////////////////////////////////////////
121
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000122int GrContext::PaintStageVertexLayoutBits(
123 const GrPaint& paint,
124 const bool hasTexCoords[GrPaint::kTotalStages]) {
125 int stageMask = paint.getActiveStageMask();
126 int layout = 0;
127 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
128 if ((1 << i) & stageMask) {
129 if (NULL != hasTexCoords && hasTexCoords[i]) {
130 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
131 } else {
132 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
133 }
134 }
135 }
136 return layout;
137}
138
139
140////////////////////////////////////////////////////////////////////////////////
141
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000142enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000143 // flags for textures
144 kNPOTBit = 0x1,
145 kFilterBit = 0x2,
146 kScratchBit = 0x4,
147
148 // resource type
149 kTextureBit = 0x8,
150 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000151};
152
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000153GrTexture* GrContext::TextureCacheEntry::texture() const {
154 if (NULL == fEntry) {
155 return NULL;
156 } else {
157 return (GrTexture*) fEntry->resource();
158 }
159}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000160
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000161namespace {
162// returns true if this is a "special" texture because of gpu NPOT limitations
163bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000164 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000165 GrContext::TextureKey clientKey,
166 int width,
167 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000168 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000169 bool scratch,
170 uint32_t v[4]) {
171 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
172 // we assume we only need 16 bits of width and height
173 // assert that texture creation will fail anyway if this assumption
174 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000175 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000176 v[0] = clientKey & 0xffffffffUL;
177 v[1] = (clientKey >> 32) & 0xffffffffUL;
178 v[2] = width | (height << 16);
179
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000180 v[3] = (sampleCnt << 24);
181 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
182
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000183 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
185
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000186 bool tiled = NULL != sampler &&
187 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
188 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189
190 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000192 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000194 }
195 }
196 }
197
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000198 if (scratch) {
199 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000200 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000201
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000202 v[3] |= kTextureBit;
203
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000204 return v[3] & kNPOTBit;
205}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000206
207// we should never have more than one stencil buffer with same combo of
208// (width,height,samplecount)
209void gen_stencil_key_values(int width, int height,
210 int sampleCnt, uint32_t v[4]) {
211 v[0] = width;
212 v[1] = height;
213 v[2] = sampleCnt;
214 v[3] = kStencilBufferBit;
215}
216
217void gen_stencil_key_values(const GrStencilBuffer* sb,
218 uint32_t v[4]) {
219 gen_stencil_key_values(sb->width(), sb->height(),
220 sb->numSamples(), v);
221}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000222
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000223void build_kernel(float sigma, float* kernel, int kernelWidth) {
224 int halfWidth = (kernelWidth - 1) / 2;
225 float sum = 0.0f;
226 float denom = 1.0f / (2.0f * sigma * sigma);
227 for (int i = 0; i < kernelWidth; ++i) {
228 float x = static_cast<float>(i - halfWidth);
229 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
230 // is dropped here, since we renormalize the kernel below.
231 kernel[i] = sk_float_exp(- x * x * denom);
232 sum += kernel[i];
233 }
234 // Normalize the kernel
235 float scale = 1.0f / sum;
236 for (int i = 0; i < kernelWidth; ++i)
237 kernel[i] *= scale;
238}
239
240void scale_rect(SkRect* rect, float xScale, float yScale) {
241 rect->fLeft *= xScale;
242 rect->fTop *= yScale;
243 rect->fRight *= xScale;
244 rect->fBottom *= yScale;
245}
246
247float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
248 int *kernelWidth) {
249 *scaleFactor = 1;
250 while (sigma > MAX_BLUR_SIGMA) {
251 *scaleFactor *= 2;
252 sigma *= 0.5f;
253 }
254 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
255 *kernelWidth = *halfWidth * 2 + 1;
256 return sigma;
257}
258
259void apply_morphology(GrGpu* gpu,
260 GrTexture* texture,
261 const SkRect& rect,
262 int radius,
263 GrSamplerState::Filter filter,
264 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000265 GrAssert(filter == GrSamplerState::kErode_Filter ||
266 filter == GrSamplerState::kDilate_Filter);
267
268 GrDrawTarget::AutoStateRestore asr(gpu);
269 GrDrawState* drawState = gpu->drawState();
270 GrRenderTarget* target = drawState->getRenderTarget();
271 drawState->reset();
272 drawState->setRenderTarget(target);
273 GrMatrix sampleM;
274 sampleM.setIDiv(texture->width(), texture->height());
275 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
276 sampleM);
277 drawState->sampler(0)->setMorphologyRadius(radius);
278 drawState->sampler(0)->setFilterDirection(direction);
279 drawState->setTexture(0, texture);
280 gpu->drawSimpleRect(rect, NULL, 1 << 0);
281}
282
283void convolve(GrGpu* gpu,
284 GrTexture* texture,
285 const SkRect& rect,
286 const float* kernel,
287 int kernelWidth,
288 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000289 GrDrawTarget::AutoStateRestore asr(gpu);
290 GrDrawState* drawState = gpu->drawState();
291 GrRenderTarget* target = drawState->getRenderTarget();
292 drawState->reset();
293 drawState->setRenderTarget(target);
294 GrMatrix sampleM;
295 sampleM.setIDiv(texture->width(), texture->height());
296 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
297 GrSamplerState::kConvolution_Filter,
298 sampleM);
299 drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel);
300 drawState->sampler(0)->setFilterDirection(direction);
301 drawState->setTexture(0, texture);
302 gpu->drawSimpleRect(rect, NULL, 1 << 0);
303}
304
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000305}
306
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000307GrContext::TextureCacheEntry GrContext::findAndLockTexture(
308 TextureKey key,
309 int width,
310 int height,
311 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000312 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000313 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000314 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000315 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
316 GrResourceCache::kNested_LockType));
317}
318
bsalomon@google.comfb309512011-11-30 14:13:48 +0000319bool GrContext::isTextureInCache(TextureKey key,
320 int width,
321 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000322 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000323 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000324 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000325 GrResourceKey resourceKey(v);
326 return fTextureCache->hasKey(resourceKey);
327}
328
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000329GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000330 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000331 uint32_t v[4];
332 gen_stencil_key_values(sb, v);
333 GrResourceKey resourceKey(v);
334 return fTextureCache->createAndLock(resourceKey, sb);
335}
336
337GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
338 int sampleCnt) {
339 uint32_t v[4];
340 gen_stencil_key_values(width, height, sampleCnt, v);
341 GrResourceKey resourceKey(v);
342 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
343 GrResourceCache::kSingle_LockType);
344 if (NULL != entry) {
345 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
346 return sb;
347 } else {
348 return NULL;
349 }
350}
351
352void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000353 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000354 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000355}
356
357static void stretchImage(void* dst,
358 int dstW,
359 int dstH,
360 void* src,
361 int srcW,
362 int srcH,
363 int bpp) {
364 GrFixed dx = (srcW << 16) / dstW;
365 GrFixed dy = (srcH << 16) / dstH;
366
367 GrFixed y = dy >> 1;
368
369 int dstXLimit = dstW*bpp;
370 for (int j = 0; j < dstH; ++j) {
371 GrFixed x = dx >> 1;
372 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
373 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
374 for (int i = 0; i < dstXLimit; i += bpp) {
375 memcpy((uint8_t*) dstRow + i,
376 (uint8_t*) srcRow + (x>>16)*bpp,
377 bpp);
378 x += dx;
379 }
380 y += dy;
381 }
382}
383
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000384GrContext::TextureCacheEntry GrContext::createAndLockTexture(
385 TextureKey key,
386 const GrSamplerState* sampler,
387 const GrTextureDesc& desc,
388 void* srcData,
389 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000390 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391
392#if GR_DUMP_TEXTURE_UPLOAD
393 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
394#endif
395
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000396 TextureCacheEntry entry;
397 uint32_t v[4];
398 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000399 desc.fWidth, desc.fHeight,
400 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000401 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000404 GrAssert(NULL != sampler);
405 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
406 desc.fWidth,
407 desc.fHeight,
408 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000409
410 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000411 clampEntry = this->createAndLockTexture(key, NULL, desc,
412 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000413 GrAssert(NULL != clampEntry.texture());
414 if (NULL == clampEntry.texture()) {
415 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000416 }
417 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000418 GrTextureDesc rtDesc = desc;
419 rtDesc.fFlags = rtDesc.fFlags |
420 kRenderTarget_GrTextureFlagBit |
421 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000422 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
423 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000424
425 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
426
427 if (NULL != texture) {
428 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000429 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000430 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000431 drawState->setRenderTarget(texture->asRenderTarget());
432 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000433
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000434 GrSamplerState::Filter filter;
435 // if filtering is not desired then we want to ensure all
436 // texels in the resampled image are copies of texels from
437 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000438 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000439 filter = GrSamplerState::kNearest_Filter;
440 } else {
441 filter = GrSamplerState::kBilinear_Filter;
442 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000443 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
444 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000445
446 static const GrVertexLayout layout =
447 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
448 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
449
450 if (arg.succeeded()) {
451 GrPoint* verts = (GrPoint*) arg.vertices();
452 verts[0].setIRectFan(0, 0,
453 texture->width(),
454 texture->height(),
455 2*sizeof(GrPoint));
456 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
457 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
458 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000459 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000460 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000461 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000462 } else {
463 // TODO: Our CPU stretch doesn't filter. But we create separate
464 // stretched textures when the sampler state is either filtered or
465 // not. Either implement filtered stretch blit on CPU or just create
466 // one when FBO case fails.
467
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000468 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000469 // no longer need to clamp at min RT size.
470 rtDesc.fWidth = GrNextPow2(desc.fWidth);
471 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000472 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000473 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000474 rtDesc.fWidth *
475 rtDesc.fHeight);
476 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
477 srcData, desc.fWidth, desc.fHeight, bpp);
478
479 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
480
481 GrTexture* texture = fGpu->createTexture(rtDesc,
482 stretchedPixels.get(),
483 stretchedRowBytes);
484 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000486 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000487 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000488
489 } else {
490 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
491 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000493 }
494 }
495 return entry;
496}
497
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000498namespace {
499inline void gen_scratch_tex_key_values(const GrGpu* gpu,
500 const GrTextureDesc& desc,
501 uint32_t v[4]) {
502 // Instead of a client-provided key of the texture contents
503 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000504 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000505 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000506 // this code path isn't friendly to tiling with NPOT restricitons
507 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000508 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000509 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000510}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000511}
512
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513GrContext::TextureCacheEntry GrContext::lockScratchTexture(
514 const GrTextureDesc& inDesc,
515 ScratchTexMatch match) {
516
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000517 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 if (kExact_ScratchTexMatch != match) {
519 // bin by pow2 with a reasonable min
520 static const int MIN_SIZE = 256;
521 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
522 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
523 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000524
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000525 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000526 int origWidth = desc.fWidth;
527 int origHeight = desc.fHeight;
528 bool doubledW = false;
529 bool doubledH = false;
530
531 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000532 uint32_t v[4];
533 gen_scratch_tex_key_values(fGpu, desc, v);
534 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000535 entry = fTextureCache->findAndLock(key,
536 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000537 // if we miss, relax the fit of the flags...
538 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000539 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000540 break;
541 }
542 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
543 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
544 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
545 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
546 } else if (!doubledW) {
547 desc.fFlags = inDesc.fFlags;
548 desc.fWidth *= 2;
549 doubledW = true;
550 } else if (!doubledH) {
551 desc.fFlags = inDesc.fFlags;
552 desc.fWidth = origWidth;
553 desc.fHeight *= 2;
554 doubledH = true;
555 } else {
556 break;
557 }
558
559 } while (true);
560
561 if (NULL == entry) {
562 desc.fFlags = inDesc.fFlags;
563 desc.fWidth = origWidth;
564 desc.fHeight = origHeight;
565 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
566 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000567 uint32_t v[4];
568 gen_scratch_tex_key_values(fGpu, desc, v);
569 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000570 entry = fTextureCache->createAndLock(key, texture);
571 }
572 }
573
574 // If the caller gives us the same desc/sampler twice we don't want
575 // to return the same texture the second time (unless it was previously
576 // released). So we detach the entry from the cache and reattach at release.
577 if (NULL != entry) {
578 fTextureCache->detach(entry);
579 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000580 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000581}
582
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000583void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000584 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000585 // If this is a scratch texture we detached it from the cache
586 // while it was locked (to avoid two callers simultaneously getting
587 // the same texture).
588 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
589 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000590 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000591 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000592 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000593}
594
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000595GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596 void* srcData,
597 size_t rowBytes) {
598 return fGpu->createTexture(desc, srcData, rowBytes);
599}
600
601void GrContext::getTextureCacheLimits(int* maxTextures,
602 size_t* maxTextureBytes) const {
603 fTextureCache->getLimits(maxTextures, maxTextureBytes);
604}
605
606void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
607 fTextureCache->setLimits(maxTextures, maxTextureBytes);
608}
609
bsalomon@google.com91958362011-06-13 17:58:13 +0000610int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000611 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000612}
613
614int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000615 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000616}
617
618///////////////////////////////////////////////////////////////////////////////
619
bsalomon@google.come269f212011-11-07 13:29:52 +0000620GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
621 return fGpu->createPlatformTexture(desc);
622}
623
624GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
625 return fGpu->createPlatformRenderTarget(desc);
626}
627
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000628///////////////////////////////////////////////////////////////////////////////
629
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000630bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000631 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000632 const GrDrawTarget::Caps& caps = fGpu->getCaps();
633 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000634 return false;
635 }
636
bsalomon@google.com27847de2011-02-22 20:59:41 +0000637 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
638
639 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000640 bool tiled = NULL != sampler &&
641 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
642 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000643 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644 return false;
645 }
646 }
647 return true;
648}
649
650////////////////////////////////////////////////////////////////////////////////
651
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000652const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
653
bsalomon@google.com27847de2011-02-22 20:59:41 +0000654void GrContext::setClip(const GrClip& clip) {
655 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000656 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000657}
658
659void GrContext::setClip(const GrIRect& rect) {
660 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000661 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000662 fGpu->setClip(clip);
663}
664
665////////////////////////////////////////////////////////////////////////////////
666
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000667void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000668 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000669 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000670}
671
672void GrContext::drawPaint(const GrPaint& paint) {
673 // set rect to be big enough to fill the space, but not super-huge, so we
674 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000675 GrRect r;
676 r.setLTRB(0, 0,
677 GrIntToScalar(getRenderTarget()->width()),
678 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000679 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000680 SkTLazy<GrPaint> tmpPaint;
681 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000682 GrDrawState* drawState = fGpu->drawState();
683 GrAutoMatrix am;
684
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000685 // We attempt to map r by the inverse matrix and draw that. mapRect will
686 // map the four corners and bound them with a new rect. This will not
687 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000688 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000689 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000690 GrPrintf("Could not invert matrix");
691 return;
692 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000693 inverse.mapRect(&r);
694 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000695 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000696 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000697 GrPrintf("Could not invert matrix");
698 return;
699 }
700 tmpPaint.set(paint);
701 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
702 p = tmpPaint.get();
703 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000704 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000705 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000706 // by definition this fills the entire clip, no need for AA
707 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000708 if (!tmpPaint.isValid()) {
709 tmpPaint.set(paint);
710 p = tmpPaint.get();
711 }
712 GrAssert(p == tmpPaint.get());
713 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000714 }
715 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000716}
717
bsalomon@google.com205d4602011-04-25 12:43:45 +0000718////////////////////////////////////////////////////////////////////////////////
719
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000720namespace {
721inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
722 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
723}
724}
725
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000726////////////////////////////////////////////////////////////////////////////////
727
bsalomon@google.com27847de2011-02-22 20:59:41 +0000728/* create a triangle strip that strokes the specified triangle. There are 8
729 unique vertices, but we repreat the last 2 to close up. Alternatively we
730 could use an indices array, and then only send 8 verts, but not sure that
731 would be faster.
732 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000733static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000734 GrScalar width) {
735 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000736 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000737
738 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
739 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
740 verts[2].set(rect.fRight - rad, rect.fTop + rad);
741 verts[3].set(rect.fRight + rad, rect.fTop - rad);
742 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
743 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
744 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
745 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
746 verts[8] = verts[0];
747 verts[9] = verts[1];
748}
749
bsalomon@google.com205d4602011-04-25 12:43:45 +0000750static void setInsetFan(GrPoint* pts, size_t stride,
751 const GrRect& r, GrScalar dx, GrScalar dy) {
752 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
753}
754
755static const uint16_t gFillAARectIdx[] = {
756 0, 1, 5, 5, 4, 0,
757 1, 2, 6, 6, 5, 1,
758 2, 3, 7, 7, 6, 2,
759 3, 0, 4, 4, 7, 3,
760 4, 5, 6, 6, 7, 4,
761};
762
763int GrContext::aaFillRectIndexCount() const {
764 return GR_ARRAY_COUNT(gFillAARectIdx);
765}
766
767GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
768 if (NULL == fAAFillRectIndexBuffer) {
769 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
770 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000771 if (NULL != fAAFillRectIndexBuffer) {
772 #if GR_DEBUG
773 bool updated =
774 #endif
775 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
776 sizeof(gFillAARectIdx));
777 GR_DEBUGASSERT(updated);
778 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000779 }
780 return fAAFillRectIndexBuffer;
781}
782
783static const uint16_t gStrokeAARectIdx[] = {
784 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
785 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
786 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
787 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
788
789 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
790 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
791 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
792 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
793
794 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
795 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
796 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
797 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
798};
799
800int GrContext::aaStrokeRectIndexCount() const {
801 return GR_ARRAY_COUNT(gStrokeAARectIdx);
802}
803
804GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
805 if (NULL == fAAStrokeRectIndexBuffer) {
806 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
807 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000808 if (NULL != fAAStrokeRectIndexBuffer) {
809 #if GR_DEBUG
810 bool updated =
811 #endif
812 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
813 sizeof(gStrokeAARectIdx));
814 GR_DEBUGASSERT(updated);
815 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000816 }
817 return fAAStrokeRectIndexBuffer;
818}
819
bsalomon@google.coma3108262011-10-10 14:08:47 +0000820static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
821 bool useCoverage) {
822 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000823 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000824 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000825 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
826 }
827 }
828 if (useCoverage) {
829 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
830 } else {
831 layout |= GrDrawTarget::kColor_VertexLayoutBit;
832 }
833 return layout;
834}
835
bsalomon@google.com205d4602011-04-25 12:43:45 +0000836void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000837 const GrRect& devRect,
838 bool useVertexCoverage) {
839 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000840
841 size_t vsize = GrDrawTarget::VertexSize(layout);
842
843 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000844 if (!geo.succeeded()) {
845 GrPrintf("Failed to get space for vertices!\n");
846 return;
847 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000848 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
849 if (NULL == indexBuffer) {
850 GrPrintf("Failed to create index buffer!\n");
851 return;
852 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000853
854 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
855
856 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
857 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
858
859 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
860 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
861
862 verts += sizeof(GrPoint);
863 for (int i = 0; i < 4; ++i) {
864 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
865 }
866
bsalomon@google.coma3108262011-10-10 14:08:47 +0000867 GrColor innerColor;
868 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000869 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000870 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000871 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000872 }
873
bsalomon@google.com205d4602011-04-25 12:43:45 +0000874 verts += 4 * vsize;
875 for (int i = 0; i < 4; ++i) {
876 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
877 }
878
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000879 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000880
881 target->drawIndexed(kTriangles_PrimitiveType, 0,
882 0, 8, this->aaFillRectIndexCount());
883}
884
bsalomon@google.coma3108262011-10-10 14:08:47 +0000885void GrContext::strokeAARect(GrDrawTarget* target,
886 const GrRect& devRect,
887 const GrVec& devStrokeSize,
888 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000889 const GrScalar& dx = devStrokeSize.fX;
890 const GrScalar& dy = devStrokeSize.fY;
891 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
892 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
893
bsalomon@google.com205d4602011-04-25 12:43:45 +0000894 GrScalar spare;
895 {
896 GrScalar w = devRect.width() - dx;
897 GrScalar h = devRect.height() - dy;
898 spare = GrMin(w, h);
899 }
900
901 if (spare <= 0) {
902 GrRect r(devRect);
903 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000904 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000905 return;
906 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000907 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 size_t vsize = GrDrawTarget::VertexSize(layout);
909
910 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000911 if (!geo.succeeded()) {
912 GrPrintf("Failed to get space for vertices!\n");
913 return;
914 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000915 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
916 if (NULL == indexBuffer) {
917 GrPrintf("Failed to create index buffer!\n");
918 return;
919 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000920
921 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
922
923 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
924 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
925 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
926 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
927
928 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
929 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
930 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
931 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
932
933 verts += sizeof(GrPoint);
934 for (int i = 0; i < 4; ++i) {
935 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
936 }
937
bsalomon@google.coma3108262011-10-10 14:08:47 +0000938 GrColor innerColor;
939 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000940 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000941 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000942 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000943 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000944 verts += 4 * vsize;
945 for (int i = 0; i < 8; ++i) {
946 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
947 }
948
949 verts += 8 * vsize;
950 for (int i = 0; i < 8; ++i) {
951 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
952 }
953
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000954 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000955 target->drawIndexed(kTriangles_PrimitiveType,
956 0, 0, 16, aaStrokeRectIndexCount());
957}
958
reed@google.com20efde72011-05-09 17:00:02 +0000959/**
960 * Returns true if the rects edges are integer-aligned.
961 */
962static bool isIRect(const GrRect& r) {
963 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
964 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
965}
966
bsalomon@google.com205d4602011-04-25 12:43:45 +0000967static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000968 const GrRect& rect,
969 GrScalar width,
970 const GrMatrix* matrix,
971 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000972 GrRect* devRect,
973 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000974 // we use a simple coverage ramp to do aa on axis-aligned rects
975 // we check if the rect will be axis-aligned, and the rect won't land on
976 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000977
bsalomon@google.coma3108262011-10-10 14:08:47 +0000978 // we are keeping around the "tweak the alpha" trick because
979 // it is our only hope for the fixed-pipe implementation.
980 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000981 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000982 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000983 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000984 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000985#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000986 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000987#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000988 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000989 } else {
990 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000991 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000992 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000993 const GrDrawState& drawState = target->getDrawState();
994 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000995 return false;
996 }
997
bsalomon@google.com471d4712011-08-23 15:45:25 +0000998 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000999 return false;
1000 }
1001
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001002 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001003 return false;
1004 }
1005
1006 if (NULL != matrix &&
1007 !matrix->preservesAxisAlignment()) {
1008 return false;
1009 }
1010
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001011 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001012 if (NULL != matrix) {
1013 combinedMatrix->preConcat(*matrix);
1014 GrAssert(combinedMatrix->preservesAxisAlignment());
1015 }
1016
1017 combinedMatrix->mapRect(devRect, rect);
1018 devRect->sort();
1019
1020 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001021 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022 } else {
1023 return true;
1024 }
1025}
1026
bsalomon@google.com27847de2011-02-22 20:59:41 +00001027void GrContext::drawRect(const GrPaint& paint,
1028 const GrRect& rect,
1029 GrScalar width,
1030 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001031 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001032
1033 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001034 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001035
bsalomon@google.com205d4602011-04-25 12:43:45 +00001036 GrRect devRect = rect;
1037 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001038 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001039 bool needAA = paint.fAntiAlias &&
1040 !this->getRenderTarget()->isMultisampled();
1041 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1042 &combinedMatrix, &devRect,
1043 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001044
1045 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001046 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001047 if (width >= 0) {
1048 GrVec strokeSize;;
1049 if (width > 0) {
1050 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001051 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001052 strokeSize.setAbs(strokeSize);
1053 } else {
1054 strokeSize.set(GR_Scalar1, GR_Scalar1);
1055 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001056 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001057 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059 }
1060 return;
1061 }
1062
bsalomon@google.com27847de2011-02-22 20:59:41 +00001063 if (width >= 0) {
1064 // TODO: consider making static vertex buffers for these cases.
1065 // Hairline could be done by just adding closing vertex to
1066 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001067 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1068
bsalomon@google.com27847de2011-02-22 20:59:41 +00001069 static const int worstCaseVertCount = 10;
1070 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1071
1072 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001073 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001074 return;
1075 }
1076
1077 GrPrimitiveType primType;
1078 int vertCount;
1079 GrPoint* vertex = geo.positions();
1080
1081 if (width > 0) {
1082 vertCount = 10;
1083 primType = kTriangleStrip_PrimitiveType;
1084 setStrokeRectStrip(vertex, rect, width);
1085 } else {
1086 // hairline
1087 vertCount = 5;
1088 primType = kLineStrip_PrimitiveType;
1089 vertex[0].set(rect.fLeft, rect.fTop);
1090 vertex[1].set(rect.fRight, rect.fTop);
1091 vertex[2].set(rect.fRight, rect.fBottom);
1092 vertex[3].set(rect.fLeft, rect.fBottom);
1093 vertex[4].set(rect.fLeft, rect.fTop);
1094 }
1095
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001096 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001097 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001098 GrDrawState* drawState = target->drawState();
1099 avmr.set(drawState);
1100 drawState->preConcatViewMatrix(*matrix);
1101 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001102 }
1103
1104 target->drawNonIndexed(primType, 0, vertCount);
1105 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001106#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001107 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001108 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1109 if (NULL == sqVB) {
1110 GrPrintf("Failed to create static rect vb.\n");
1111 return;
1112 }
1113 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001114 GrDrawState* drawState = target->drawState();
1115 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001116 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001117 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001118 0, rect.height(), rect.fTop,
1119 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001120
1121 if (NULL != matrix) {
1122 m.postConcat(*matrix);
1123 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001124 drawState->preConcatViewMatrix(m);
1125 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001126
bsalomon@google.com27847de2011-02-22 20:59:41 +00001127 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001128#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001129 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001130#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001131 }
1132}
1133
1134void GrContext::drawRectToRect(const GrPaint& paint,
1135 const GrRect& dstRect,
1136 const GrRect& srcRect,
1137 const GrMatrix* dstMatrix,
1138 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001139 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001140
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001141 // srcRect refers to paint's first texture
1142 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001143 drawRect(paint, dstRect, -1, dstMatrix);
1144 return;
1145 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001146
bsalomon@google.com27847de2011-02-22 20:59:41 +00001147 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1148
1149#if GR_STATIC_RECT_VB
1150 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001151 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001152 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001153 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001154
1155 GrMatrix m;
1156
1157 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1158 0, dstRect.height(), dstRect.fTop,
1159 0, 0, GrMatrix::I()[8]);
1160 if (NULL != dstMatrix) {
1161 m.postConcat(*dstMatrix);
1162 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001163 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001164
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001165 // srcRect refers to first stage
1166 int otherStageMask = paint.getActiveStageMask() &
1167 (~(1 << GrPaint::kFirstTextureStage));
1168 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001169 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001170 }
1171
bsalomon@google.com27847de2011-02-22 20:59:41 +00001172 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1173 0, srcRect.height(), srcRect.fTop,
1174 0, 0, GrMatrix::I()[8]);
1175 if (NULL != srcMatrix) {
1176 m.postConcat(*srcMatrix);
1177 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001178 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001179
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001180 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1181 if (NULL == sqVB) {
1182 GrPrintf("Failed to create static rect vb.\n");
1183 return;
1184 }
1185 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001186 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1187#else
1188
1189 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001190#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001191 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001192#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1194#endif
1195
tomhudson@google.com93813632011-10-27 20:21:16 +00001196 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1197 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198 srcRects[0] = &srcRect;
1199 srcMatrices[0] = srcMatrix;
1200
1201 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1202#endif
1203}
1204
1205void GrContext::drawVertices(const GrPaint& paint,
1206 GrPrimitiveType primitiveType,
1207 int vertexCount,
1208 const GrPoint positions[],
1209 const GrPoint texCoords[],
1210 const GrColor colors[],
1211 const uint16_t indices[],
1212 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001213 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001214
1215 GrDrawTarget::AutoReleaseGeometry geo;
1216
1217 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1218
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001219 bool hasTexCoords[GrPaint::kTotalStages] = {
1220 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1221 0 // remaining stages use positions
1222 };
1223
1224 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001225
1226 if (NULL != colors) {
1227 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001228 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001229 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001230
1231 if (sizeof(GrPoint) != vertexSize) {
1232 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001233 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234 return;
1235 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001236 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001237 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001238 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1239 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001240 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001241 NULL,
1242 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001243 void* curVertex = geo.vertices();
1244
1245 for (int i = 0; i < vertexCount; ++i) {
1246 *((GrPoint*)curVertex) = positions[i];
1247
1248 if (texOffsets[0] > 0) {
1249 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1250 }
1251 if (colorOffset > 0) {
1252 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1253 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001254 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255 }
1256 } else {
1257 target->setVertexSourceToArray(layout, positions, vertexCount);
1258 }
1259
bsalomon@google.com91958362011-06-13 17:58:13 +00001260 // we don't currently apply offscreen AA to this path. Need improved
1261 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001262
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001263 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001264 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001265 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001266 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001267 target->drawNonIndexed(primitiveType, 0, vertexCount);
1268 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269}
1270
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001271///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001272#include "SkDraw.h"
1273#include "SkRasterClip.h"
1274
1275namespace {
1276
1277SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1278 switch (fill) {
1279 case kWinding_PathFill:
1280 return SkPath::kWinding_FillType;
1281 case kEvenOdd_PathFill:
1282 return SkPath::kEvenOdd_FillType;
1283 case kInverseWinding_PathFill:
1284 return SkPath::kInverseWinding_FillType;
1285 case kInverseEvenOdd_PathFill:
1286 return SkPath::kInverseEvenOdd_FillType;
1287 default:
1288 GrCrash("Unexpected fill.");
1289 return SkPath::kWinding_FillType;
1290 }
1291}
1292
1293// gets device coord bounds of path (not considering the fill) and clip. The
1294// path bounds will be a subset of the clip bounds. returns false if path bounds
1295// would be empty.
1296bool get_path_and_clip_bounds(const GrDrawTarget* target,
1297 const GrPath& path,
1298 const GrVec* translate,
1299 GrIRect* pathBounds,
1300 GrIRect* clipBounds) {
1301 // compute bounds as intersection of rt size, clip, and path
1302 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1303 if (NULL == rt) {
1304 return false;
1305 }
1306 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1307 const GrClip& clip = target->getClip();
1308 if (clip.hasConservativeBounds()) {
1309 clip.getConservativeBounds().roundOut(clipBounds);
1310 if (!pathBounds->intersect(*clipBounds)) {
1311 return false;
1312 }
1313 } else {
1314 // pathBounds is currently the rt extent, set clip bounds to that rect.
1315 *clipBounds = *pathBounds;
1316 }
1317 GrRect pathSBounds = path.getBounds();
1318 if (!pathSBounds.isEmpty()) {
1319 if (NULL != translate) {
1320 pathSBounds.offset(*translate);
1321 }
1322 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1323 pathSBounds);
1324 GrIRect pathIBounds;
1325 pathSBounds.roundOut(&pathIBounds);
1326 if (!pathBounds->intersect(pathIBounds)) {
1327 return false;
1328 }
1329 } else {
1330 return false;
1331 }
1332 return true;
1333}
1334
1335/**
1336 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1337 * scratch texture.
1338 */
1339
1340bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1341 const GrIRect& pathDevBounds,
1342 GrPathFill fill,
1343 GrContext* context,
1344 const GrPoint* translate,
1345 GrAutoScratchTexture* tex) {
1346 SkPaint paint;
1347 SkPath tmpPath;
1348 const SkPath* pathToDraw = &clientPath;
1349 if (kHairLine_PathFill == fill) {
1350 paint.setStyle(SkPaint::kStroke_Style);
1351 paint.setStrokeWidth(SK_Scalar1);
1352 } else {
1353 paint.setStyle(SkPaint::kFill_Style);
1354 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1355 if (skfill != pathToDraw->getFillType()) {
1356 tmpPath = *pathToDraw;
1357 tmpPath.setFillType(skfill);
1358 pathToDraw = &tmpPath;
1359 }
1360 }
1361 paint.setAntiAlias(true);
1362 paint.setColor(SK_ColorWHITE);
1363
1364 GrMatrix matrix = context->getMatrix();
1365 if (NULL != translate) {
1366 matrix.postTranslate(translate->fX, translate->fY);
1367 }
1368
1369 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1370 -pathDevBounds.fTop * SK_Scalar1);
1371 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1372 pathDevBounds.height());
1373
1374 SkBitmap bm;
1375 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1376 if (!bm.allocPixels()) {
1377 return false;
1378 }
1379 sk_bzero(bm.getPixels(), bm.getSafeSize());
1380
1381 SkDraw draw;
1382 sk_bzero(&draw, sizeof(draw));
1383 SkRasterClip rc(bounds);
1384 draw.fRC = &rc;
1385 draw.fClip = &rc.bwRgn();
1386 draw.fMatrix = &matrix;
1387 draw.fBitmap = &bm;
1388 draw.drawPath(*pathToDraw, paint);
1389
1390 const GrTextureDesc desc = {
1391 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001392 bounds.fRight,
1393 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001394 kAlpha_8_GrPixelConfig,
1395 {0} // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001396 };
1397
1398 tex->set(context, desc);
1399 GrTexture* texture = tex->texture();
1400
1401 if (NULL == texture) {
1402 return false;
1403 }
1404 SkAutoLockPixels alp(bm);
1405 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1406 bm.getPixels(), bm.rowBytes());
1407 return true;
1408}
1409
1410void draw_around_inv_path(GrDrawTarget* target,
1411 GrDrawState::StageMask stageMask,
1412 const GrIRect& clipBounds,
1413 const GrIRect& pathBounds) {
1414 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1415 GrRect rect;
1416 if (clipBounds.fTop < pathBounds.fTop) {
1417 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1418 clipBounds.fRight, pathBounds.fTop);
1419 target->drawSimpleRect(rect, NULL, stageMask);
1420 }
1421 if (clipBounds.fLeft < pathBounds.fLeft) {
1422 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1423 pathBounds.fLeft, pathBounds.fBottom);
1424 target->drawSimpleRect(rect, NULL, stageMask);
1425 }
1426 if (clipBounds.fRight > pathBounds.fRight) {
1427 rect.iset(pathBounds.fRight, pathBounds.fTop,
1428 clipBounds.fRight, pathBounds.fBottom);
1429 target->drawSimpleRect(rect, NULL, stageMask);
1430 }
1431 if (clipBounds.fBottom > pathBounds.fBottom) {
1432 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1433 clipBounds.fRight, clipBounds.fBottom);
1434 target->drawSimpleRect(rect, NULL, stageMask);
1435 }
1436}
1437
1438}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001439
reed@google.com07f3ee12011-05-16 17:21:57 +00001440void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1441 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001442
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001443 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001444 if (GrIsFillInverted(fill)) {
1445 this->drawPaint(paint);
1446 }
1447 return;
1448 }
1449
bsalomon@google.com27847de2011-02-22 20:59:41 +00001450 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001451 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001452
bsalomon@google.com289533a2011-10-27 12:34:25 +00001453 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1454
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001455 // An Assumption here is that path renderer would use some form of tweaking
1456 // the src color (either the input alpha or in the frag shader) to implement
1457 // aa. If we have some future driver-mojo path AA that can do the right
1458 // thing WRT to the blend then we'll need some query on the PR.
1459 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001460#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001461 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001462#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001463 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001464 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001465
bsalomon@google.com289533a2011-10-27 12:34:25 +00001466 GrPathRenderer* pr = NULL;
1467 if (prAA) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001468 pr = this->getPathRenderer(path, fill, target, true);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001469 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001470 GrAutoScratchTexture ast;
1471 GrIRect pathBounds, clipBounds;
1472 if (!get_path_and_clip_bounds(target, path, translate,
1473 &pathBounds, &clipBounds)) {
1474 return;
1475 }
bsalomon@google.com150d2842012-01-12 20:19:56 +00001476 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1477 fill, this,
1478 translate, &ast)) {
1479 GrTexture* texture = ast.texture();
1480 GrAssert(NULL != texture);
1481 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1482 enum {
1483 kPathMaskStage = GrPaint::kTotalStages,
1484 };
1485 target->drawState()->setTexture(kPathMaskStage, texture);
1486 target->drawState()->sampler(kPathMaskStage)->reset();
1487 GrScalar w = GrIntToScalar(pathBounds.width());
1488 GrScalar h = GrIntToScalar(pathBounds.height());
1489 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1490 h / texture->height());
1491 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1492 srcRects[kPathMaskStage] = &maskRect;
1493 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001494 GrRect dstRect = GrRect::MakeLTRB(
1495 SK_Scalar1* pathBounds.fLeft,
1496 SK_Scalar1* pathBounds.fTop,
1497 SK_Scalar1* pathBounds.fRight,
1498 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001499 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1500 target->drawState()->setTexture(kPathMaskStage, NULL);
1501 if (GrIsFillInverted(fill)) {
1502 draw_around_inv_path(target, stageMask,
1503 clipBounds, pathBounds);
1504 }
1505 return;
1506 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001507 }
1508 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001509 pr = this->getPathRenderer(path, fill, target, false);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001510 }
1511
bsalomon@google.com30085192011-08-19 15:42:31 +00001512 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001513#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001514 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001515#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001516 return;
1517 }
1518
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001519 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001520}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001521
bsalomon@google.com27847de2011-02-22 20:59:41 +00001522////////////////////////////////////////////////////////////////////////////////
1523
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001524void GrContext::flush(int flagsBitfield) {
1525 if (kDiscard_FlushBit & flagsBitfield) {
1526 fDrawBuffer->reset();
1527 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001528 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001529 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001530 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001531 fGpu->forceRenderTargetFlush();
1532 }
1533}
1534
1535void GrContext::flushText() {
1536 if (kText_DrawCategory == fLastDrawCategory) {
1537 flushDrawBuffer();
1538 }
1539}
1540
1541void GrContext::flushDrawBuffer() {
1542#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001543 if (fDrawBuffer) {
bsalomon@google.com97805382012-03-13 14:32:07 +00001544 fDrawBuffer->flushTo(fGpu);
junov@google.com53a55842011-06-08 22:55:10 +00001545 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546#endif
1547}
1548
bsalomon@google.com6f379512011-11-16 20:36:03 +00001549void GrContext::internalWriteTexturePixels(GrTexture* texture,
1550 int left, int top,
1551 int width, int height,
1552 GrPixelConfig config,
1553 const void* buffer,
1554 size_t rowBytes,
1555 uint32_t flags) {
1556 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001557 ASSERT_OWNED_RESOURCE(texture);
1558
bsalomon@google.com6f379512011-11-16 20:36:03 +00001559 if (!(kDontFlush_PixelOpsFlag & flags)) {
1560 this->flush();
1561 }
1562 // TODO: use scratch texture to perform conversion
1563 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1564 GrPixelConfigIsUnpremultiplied(config)) {
1565 return;
1566 }
1567
1568 fGpu->writeTexturePixels(texture, left, top, width, height,
1569 config, buffer, rowBytes);
1570}
1571
1572bool GrContext::internalReadTexturePixels(GrTexture* texture,
1573 int left, int top,
1574 int width, int height,
1575 GrPixelConfig config,
1576 void* buffer,
1577 size_t rowBytes,
1578 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001579 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001580 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001581
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001582 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001583 GrRenderTarget* target = texture->asRenderTarget();
1584 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001585 return this->internalReadRenderTargetPixels(target,
1586 left, top, width, height,
1587 config, buffer, rowBytes,
1588 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001589 } else {
1590 return false;
1591 }
1592}
1593
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001594#include "SkConfig8888.h"
1595
1596namespace {
1597/**
1598 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1599 * formats are representable as Config8888 and so the function returns false
1600 * if the GrPixelConfig has no equivalent Config8888.
1601 */
1602bool grconfig_to_config8888(GrPixelConfig config,
1603 SkCanvas::Config8888* config8888) {
1604 switch (config) {
1605 case kRGBA_8888_PM_GrPixelConfig:
1606 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1607 return true;
1608 case kRGBA_8888_UPM_GrPixelConfig:
1609 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1610 return true;
1611 case kBGRA_8888_PM_GrPixelConfig:
1612 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1613 return true;
1614 case kBGRA_8888_UPM_GrPixelConfig:
1615 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1616 return true;
1617 default:
1618 return false;
1619 }
1620}
1621}
1622
bsalomon@google.com6f379512011-11-16 20:36:03 +00001623bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1624 int left, int top,
1625 int width, int height,
1626 GrPixelConfig config,
1627 void* buffer,
1628 size_t rowBytes,
1629 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001630 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001631 ASSERT_OWNED_RESOURCE(target);
1632
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001633 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001634 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001635 if (NULL == target) {
1636 return false;
1637 }
1638 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001639
bsalomon@google.com6f379512011-11-16 20:36:03 +00001640 if (!(kDontFlush_PixelOpsFlag & flags)) {
1641 this->flush();
1642 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001643
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001644 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1645 GrPixelConfigIsUnpremultiplied(config) &&
1646 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1647 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1648 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1649 !grconfig_to_config8888(config, &dstConfig8888)) {
1650 return false;
1651 }
1652 // do read back using target's own config
1653 this->internalReadRenderTargetPixels(target,
1654 left, top,
1655 width, height,
1656 target->config(),
1657 buffer, rowBytes,
1658 kDontFlush_PixelOpsFlag);
1659 // sw convert the pixels to unpremul config
1660 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1661 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1662 pixels, rowBytes, srcConfig8888,
1663 width, height);
1664 return true;
1665 }
1666
bsalomon@google.comc4364992011-11-07 15:54:49 +00001667 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001668 bool swapRAndB = NULL != src &&
1669 fGpu->preferredReadPixelsConfig(config) ==
1670 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001671
1672 bool flipY = NULL != src &&
1673 fGpu->readPixelsWillPayForYFlip(target, left, top,
1674 width, height, config,
1675 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001676 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1677 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001678
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001679 if (NULL == src && alphaConversion) {
1680 // we should fallback to cpu conversion here. This could happen when
1681 // we were given an external render target by the client that is not
1682 // also a texture (e.g. FBO 0 in GL)
1683 return false;
1684 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001685 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001686 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001687 if (flipY || swapRAndB || alphaConversion) {
1688 GrAssert(NULL != src);
1689 if (swapRAndB) {
1690 config = GrPixelConfigSwapRAndB(config);
1691 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001692 }
1693 // Make the scratch a render target because we don't have a robust
1694 // readTexturePixels as of yet (it calls this function).
1695 const GrTextureDesc desc = {
1696 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001697 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001698 config,
1699 {0}, // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001700 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001701
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001702 // When a full readback is faster than a partial we could always make
1703 // the scratch exactly match the passed rect. However, if we see many
1704 // different size rectangles we will trash our texture cache and pay the
1705 // cost of creating and destroying many textures. So, we only request
1706 // an exact match when the caller is reading an entire RT.
1707 ScratchTexMatch match = kApprox_ScratchTexMatch;
1708 if (0 == left &&
1709 0 == top &&
1710 target->width() == width &&
1711 target->height() == height &&
1712 fGpu->fullReadPixelsIsFasterThanPartial()) {
1713 match = kExact_ScratchTexMatch;
1714 }
1715 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001716 GrTexture* texture = ast.texture();
1717 if (!texture) {
1718 return false;
1719 }
1720 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001721 GrAssert(NULL != target);
1722
1723 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001724 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001725 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001726 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001727
bsalomon@google.comc4364992011-11-07 15:54:49 +00001728 GrMatrix matrix;
1729 if (flipY) {
1730 matrix.setTranslate(SK_Scalar1 * left,
1731 SK_Scalar1 * (top + height));
1732 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1733 } else {
1734 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1735 }
1736 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001737 drawState->sampler(0)->reset(matrix);
1738 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001739 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001740 GrRect rect;
1741 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1742 fGpu->drawSimpleRect(rect, NULL, 0x1);
1743 left = 0;
1744 top = 0;
1745 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001746 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001747 left, top, width, height,
1748 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001749}
1750
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001751void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1752 GrAssert(target);
1753 ASSERT_OWNED_RESOURCE(target);
1754 // In the future we may track whether there are any pending draws to this
1755 // target. We don't today so we always perform a flush. We don't promise
1756 // this to our clients, though.
1757 this->flush();
1758 fGpu->resolveRenderTarget(target);
1759}
1760
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001761void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1762 if (NULL == src || NULL == dst) {
1763 return;
1764 }
1765 ASSERT_OWNED_RESOURCE(src);
1766
1767 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001768 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001769 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001770 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001771 GrMatrix sampleM;
1772 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001773 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001774 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001775 SkRect rect = SkRect::MakeXYWH(0, 0,
1776 SK_Scalar1 * src->width(),
1777 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001778 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1779}
1780
bsalomon@google.com6f379512011-11-16 20:36:03 +00001781void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1782 int left, int top,
1783 int width, int height,
1784 GrPixelConfig config,
1785 const void* buffer,
1786 size_t rowBytes,
1787 uint32_t flags) {
1788 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001789 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001790
1791 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001792 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001793 if (NULL == target) {
1794 return;
1795 }
1796 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001797
1798 // TODO: when underlying api has a direct way to do this we should use it
1799 // (e.g. glDrawPixels on desktop GL).
1800
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001801 // If the RT is also a texture and we don't have to do PM/UPM conversion
1802 // then take the texture path, which we expect to be at least as fast or
1803 // faster since it doesn't use an intermediate texture as we do below.
1804
1805#if !GR_MAC_BUILD
1806 // At least some drivers on the Mac get confused when glTexImage2D is called
1807 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1808 // determine what OS versions and/or HW is affected.
1809 if (NULL != target->asTexture() &&
1810 GrPixelConfigIsUnpremultiplied(target->config()) ==
1811 GrPixelConfigIsUnpremultiplied(config)) {
1812
1813 this->internalWriteTexturePixels(target->asTexture(),
1814 left, top, width, height,
1815 config, buffer, rowBytes, flags);
1816 return;
1817 }
1818#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001819 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1820 GrPixelConfigIsUnpremultiplied(config) &&
1821 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1822 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1823 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1824 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1825 return;
1826 }
1827 // allocate a tmp buffer and sw convert the pixels to premul
1828 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1829 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1830 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1831 src, rowBytes, srcConfig8888,
1832 width, height);
1833 // upload the already premul pixels
1834 this->internalWriteRenderTargetPixels(target,
1835 left, top,
1836 width, height,
1837 target->config(),
1838 tmpPixels, 4 * width, flags);
1839 return;
1840 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001841
1842 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1843 GrPixelConfigSwapRAndB(config);
1844 if (swapRAndB) {
1845 config = GrPixelConfigSwapRAndB(config);
1846 }
1847
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001848 const GrTextureDesc desc = {
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001849 kNone_GrTextureFlags, width, height, config, {0}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001850 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001851 GrAutoScratchTexture ast(this, desc);
1852 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001853 if (NULL == texture) {
1854 return;
1855 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001856 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1857 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001858
bsalomon@google.com27847de2011-02-22 20:59:41 +00001859 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001860 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001861 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001862
1863 GrMatrix matrix;
1864 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001865 drawState->setViewMatrix(matrix);
1866 drawState->setRenderTarget(target);
1867 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868
bsalomon@google.com5c638652011-07-18 19:31:59 +00001869 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001870 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1871 GrSamplerState::kNearest_Filter,
1872 matrix);
1873 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001874
1875 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1876 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001877 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001878 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1879 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001880 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001881 return;
1882 }
1883 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1884 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1885}
1886////////////////////////////////////////////////////////////////////////////////
1887
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001888void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001889 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001890
1891 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1892 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001893 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001894 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001895 if (paint.getTexture(i)) {
1896 *drawState->sampler(s) = paint.getTextureSampler(i);
1897 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001898 }
1899
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001900 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001901
1902 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1903 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001904 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001905 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001906 if (paint.getMask(i)) {
1907 *drawState->sampler(s) = paint.getMaskSampler(i);
1908 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001909 }
1910
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001911 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001912
1913 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001914 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001915 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001916 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001917 }
1918 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001919 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001920 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001921 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001922 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001923 if (paint.fColorMatrixEnabled) {
1924 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
bsalomon@google.com9b1517e2012-03-05 17:58:34 +00001925 drawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001926 } else {
1927 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
1928 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001929 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001930 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comdd1be602012-01-18 20:34:00 +00001931 drawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001932
1933 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1934 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1935 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001936}
1937
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001938GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001939 DrawCategory category) {
1940 if (category != fLastDrawCategory) {
1941 flushDrawBuffer();
1942 fLastDrawCategory = category;
1943 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001944 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001945 GrDrawTarget* target = fGpu;
1946 switch (category) {
1947 case kText_DrawCategory:
1948#if DEFER_TEXT_RENDERING
1949 target = fDrawBuffer;
1950 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1951#else
1952 target = fGpu;
1953#endif
1954 break;
1955 case kUnbuffered_DrawCategory:
1956 target = fGpu;
1957 break;
1958 case kBuffered_DrawCategory:
1959 target = fDrawBuffer;
1960 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1961 break;
1962 }
1963 return target;
1964}
1965
bsalomon@google.com289533a2011-10-27 12:34:25 +00001966GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1967 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001968 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001969 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001970 if (NULL == fPathRendererChain) {
1971 fPathRendererChain =
1972 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1973 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001974 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001975}
1976
bsalomon@google.com27847de2011-02-22 20:59:41 +00001977////////////////////////////////////////////////////////////////////////////////
1978
bsalomon@google.com27847de2011-02-22 20:59:41 +00001979void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001980 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001981 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001982 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001983}
1984
1985GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001986 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001987}
1988
1989const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001990 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001991}
1992
1993const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001994 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001995}
1996
1997void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001998 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999}
2000
2001void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002002 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002003}
2004
2005static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2006 intptr_t mask = 1 << shift;
2007 if (pred) {
2008 bits |= mask;
2009 } else {
2010 bits &= ~mask;
2011 }
2012 return bits;
2013}
2014
2015void GrContext::resetStats() {
2016 fGpu->resetStats();
2017}
2018
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002019const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002020 return fGpu->getStats();
2021}
2022
2023void GrContext::printStats() const {
2024 fGpu->printStats();
2025}
2026
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002027GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002028 fGpu = gpu;
2029 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002030 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002031
bsalomon@google.com30085192011-08-19 15:42:31 +00002032 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002033
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002034 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2035 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002036 fFontCache = new GrFontCache(fGpu);
2037
2038 fLastDrawCategory = kUnbuffered_DrawCategory;
2039
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002040 fDrawBuffer = NULL;
2041 fDrawBufferVBAllocPool = NULL;
2042 fDrawBufferIBAllocPool = NULL;
2043
bsalomon@google.com205d4602011-04-25 12:43:45 +00002044 fAAFillRectIndexBuffer = NULL;
2045 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002046
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002047 this->setupDrawBuffer();
2048}
2049
2050void GrContext::setupDrawBuffer() {
2051
2052 GrAssert(NULL == fDrawBuffer);
2053 GrAssert(NULL == fDrawBufferVBAllocPool);
2054 GrAssert(NULL == fDrawBufferIBAllocPool);
2055
bsalomon@google.com27847de2011-02-22 20:59:41 +00002056#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002057 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002058 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002059 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2060 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002061 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002062 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002063 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002064 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2065
bsalomon@google.com471d4712011-08-23 15:45:25 +00002066 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2067 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002068 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002069#endif
2070
2071#if BATCH_RECT_TO_RECT
2072 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2073#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002074}
2075
bsalomon@google.com27847de2011-02-22 20:59:41 +00002076GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2077 GrDrawTarget* target;
2078#if DEFER_TEXT_RENDERING
2079 target = prepareToDraw(paint, kText_DrawCategory);
2080#else
2081 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2082#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002083 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002084 return target;
2085}
2086
2087const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2088 return fGpu->getQuadIndexBuffer();
2089}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002090
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002091GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2092 GrAutoScratchTexture* temp1,
2093 GrAutoScratchTexture* temp2,
2094 const SkRect& rect,
2095 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002096 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002097 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2098 GrClip oldClip = this->getClip();
2099 GrTexture* origTexture = srcTexture;
2100 GrAutoMatrix avm(this, GrMatrix::I());
2101 SkIRect clearRect;
2102 int scaleFactorX, halfWidthX, kernelWidthX;
2103 int scaleFactorY, halfWidthY, kernelWidthY;
2104 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2105 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002106
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002107 SkRect srcRect(rect);
2108 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2109 srcRect.roundOut();
2110 scale_rect(&srcRect, scaleFactorX, scaleFactorY);
2111 this->setClip(srcRect);
2112
2113 const GrTextureDesc desc = {
2114 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
2115 srcRect.width(),
2116 srcRect.height(),
2117 kRGBA_8888_GrPixelConfig,
2118 {0} // samples
2119 };
2120
2121 temp1->set(this, desc);
2122 if (temp2) temp2->set(this, desc);
2123
2124 GrTexture* dstTexture = temp1->texture();
2125 GrPaint paint;
2126 paint.reset();
2127 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2128
2129 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2130 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2131 srcTexture->height());
2132 this->setRenderTarget(dstTexture->asRenderTarget());
2133 SkRect dstRect(srcRect);
2134 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2135 i < scaleFactorY ? 0.5f : 1.0f);
2136 paint.setTexture(0, srcTexture);
2137 this->drawRectToRect(paint, dstRect, srcRect);
2138 srcRect = dstRect;
2139 SkTSwap(srcTexture, dstTexture);
2140 // If temp2 is non-NULL, don't render back to origTexture
2141 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2142 }
2143
2144 if (sigmaX > 0.0f) {
2145 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2146 float* kernelX = kernelStorageX.get();
2147 build_kernel(sigmaX, kernelX, kernelWidthX);
2148
2149 if (scaleFactorX > 1) {
2150 // Clear out a halfWidth to the right of the srcRect to prevent the
2151 // X convolution from reading garbage.
2152 clearRect = SkIRect::MakeXYWH(
2153 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2154 this->clear(&clearRect, 0x0);
2155 }
2156
2157 this->setRenderTarget(dstTexture->asRenderTarget());
2158 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2159 GrSamplerState::kX_FilterDirection);
2160 SkTSwap(srcTexture, dstTexture);
2161 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2162 }
2163
2164 if (sigmaY > 0.0f) {
2165 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2166 float* kernelY = kernelStorageY.get();
2167 build_kernel(sigmaY, kernelY, kernelWidthY);
2168
2169 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2170 // Clear out a halfWidth below the srcRect to prevent the Y
2171 // convolution from reading garbage.
2172 clearRect = SkIRect::MakeXYWH(
2173 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2174 this->clear(&clearRect, 0x0);
2175 }
2176
2177 this->setRenderTarget(dstTexture->asRenderTarget());
2178 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2179 GrSamplerState::kY_FilterDirection);
2180 SkTSwap(srcTexture, dstTexture);
2181 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2182 }
2183
2184 if (scaleFactorX > 1 || scaleFactorY > 1) {
2185 // Clear one pixel to the right and below, to accommodate bilinear
2186 // upsampling.
2187 clearRect = SkIRect::MakeXYWH(
2188 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2189 this->clear(&clearRect, 0x0);
2190 clearRect = SkIRect::MakeXYWH(
2191 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2192 this->clear(&clearRect, 0x0);
2193 // FIXME: This should be mitchell, not bilinear.
2194 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2195 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2196 srcTexture->height());
2197 this->setRenderTarget(dstTexture->asRenderTarget());
2198 paint.setTexture(0, srcTexture);
2199 SkRect dstRect(srcRect);
2200 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2201 this->drawRectToRect(paint, dstRect, srcRect);
2202 srcRect = dstRect;
2203 SkTSwap(srcTexture, dstTexture);
2204 }
2205 this->setRenderTarget(oldRenderTarget);
2206 this->setClip(oldClip);
2207 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002208}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002209
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002210GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2211 const GrRect& rect,
2212 GrTexture* temp1, GrTexture* temp2,
2213 GrSamplerState::Filter filter,
2214 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002215 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002216 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2217 GrAutoMatrix avm(this, GrMatrix::I());
2218 GrClip oldClip = this->getClip();
2219 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2220 if (radius.fWidth > 0) {
2221 this->setRenderTarget(temp1->asRenderTarget());
2222 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2223 GrSamplerState::kX_FilterDirection);
2224 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2225 rect.width(), radius.fHeight);
2226 this->clear(&clearRect, 0x0);
2227 srcTexture = temp1;
2228 }
2229 if (radius.fHeight > 0) {
2230 this->setRenderTarget(temp2->asRenderTarget());
2231 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2232 GrSamplerState::kY_FilterDirection);
2233 srcTexture = temp2;
2234 }
2235 this->setRenderTarget(oldRenderTarget);
2236 this->setClip(oldClip);
2237 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002238}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002239
2240///////////////////////////////////////////////////////////////////////////////