blob: 038f953b8edd870d2e5405c35c1c49f6efba6e77 [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) {
265 ASSERT_OWNED_RESOURCE(texture);
266 GrAssert(filter == GrSamplerState::kErode_Filter ||
267 filter == GrSamplerState::kDilate_Filter);
268
269 GrDrawTarget::AutoStateRestore asr(gpu);
270 GrDrawState* drawState = gpu->drawState();
271 GrRenderTarget* target = drawState->getRenderTarget();
272 drawState->reset();
273 drawState->setRenderTarget(target);
274 GrMatrix sampleM;
275 sampleM.setIDiv(texture->width(), texture->height());
276 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
277 sampleM);
278 drawState->sampler(0)->setMorphologyRadius(radius);
279 drawState->sampler(0)->setFilterDirection(direction);
280 drawState->setTexture(0, texture);
281 gpu->drawSimpleRect(rect, NULL, 1 << 0);
282}
283
284void convolve(GrGpu* gpu,
285 GrTexture* texture,
286 const SkRect& rect,
287 const float* kernel,
288 int kernelWidth,
289 GrSamplerState::FilterDirection direction) {
290 ASSERT_OWNED_RESOURCE(texture);
291
292 GrDrawTarget::AutoStateRestore asr(gpu);
293 GrDrawState* drawState = gpu->drawState();
294 GrRenderTarget* target = drawState->getRenderTarget();
295 drawState->reset();
296 drawState->setRenderTarget(target);
297 GrMatrix sampleM;
298 sampleM.setIDiv(texture->width(), texture->height());
299 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
300 GrSamplerState::kConvolution_Filter,
301 sampleM);
302 drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel);
303 drawState->sampler(0)->setFilterDirection(direction);
304 drawState->setTexture(0, texture);
305 gpu->drawSimpleRect(rect, NULL, 1 << 0);
306}
307
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000308}
309
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000310GrContext::TextureCacheEntry GrContext::findAndLockTexture(
311 TextureKey key,
312 int width,
313 int height,
314 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000315 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000316 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000317 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000318 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
319 GrResourceCache::kNested_LockType));
320}
321
bsalomon@google.comfb309512011-11-30 14:13:48 +0000322bool GrContext::isTextureInCache(TextureKey key,
323 int width,
324 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000325 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000326 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000327 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000328 GrResourceKey resourceKey(v);
329 return fTextureCache->hasKey(resourceKey);
330}
331
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000332GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000333 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000334 uint32_t v[4];
335 gen_stencil_key_values(sb, v);
336 GrResourceKey resourceKey(v);
337 return fTextureCache->createAndLock(resourceKey, sb);
338}
339
340GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
341 int sampleCnt) {
342 uint32_t v[4];
343 gen_stencil_key_values(width, height, sampleCnt, v);
344 GrResourceKey resourceKey(v);
345 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
346 GrResourceCache::kSingle_LockType);
347 if (NULL != entry) {
348 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
349 return sb;
350 } else {
351 return NULL;
352 }
353}
354
355void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000356 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000357 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000358}
359
360static void stretchImage(void* dst,
361 int dstW,
362 int dstH,
363 void* src,
364 int srcW,
365 int srcH,
366 int bpp) {
367 GrFixed dx = (srcW << 16) / dstW;
368 GrFixed dy = (srcH << 16) / dstH;
369
370 GrFixed y = dy >> 1;
371
372 int dstXLimit = dstW*bpp;
373 for (int j = 0; j < dstH; ++j) {
374 GrFixed x = dx >> 1;
375 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
376 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
377 for (int i = 0; i < dstXLimit; i += bpp) {
378 memcpy((uint8_t*) dstRow + i,
379 (uint8_t*) srcRow + (x>>16)*bpp,
380 bpp);
381 x += dx;
382 }
383 y += dy;
384 }
385}
386
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000387GrContext::TextureCacheEntry GrContext::createAndLockTexture(
388 TextureKey key,
389 const GrSamplerState* sampler,
390 const GrTextureDesc& desc,
391 void* srcData,
392 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000393 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000394
395#if GR_DUMP_TEXTURE_UPLOAD
396 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
397#endif
398
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000399 TextureCacheEntry entry;
400 uint32_t v[4];
401 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000402 desc.fWidth, desc.fHeight,
403 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000404 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000405
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000406 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000407 GrAssert(NULL != sampler);
408 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
409 desc.fWidth,
410 desc.fHeight,
411 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412
413 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000414 clampEntry = this->createAndLockTexture(key, NULL, desc,
415 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416 GrAssert(NULL != clampEntry.texture());
417 if (NULL == clampEntry.texture()) {
418 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000419 }
420 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000421 GrTextureDesc rtDesc = desc;
422 rtDesc.fFlags = rtDesc.fFlags |
423 kRenderTarget_GrTextureFlagBit |
424 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000425 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
426 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000427
428 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
429
430 if (NULL != texture) {
431 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000432 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000433 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000434 drawState->setRenderTarget(texture->asRenderTarget());
435 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000436
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000437 GrSamplerState::Filter filter;
438 // if filtering is not desired then we want to ensure all
439 // texels in the resampled image are copies of texels from
440 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000441 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000442 filter = GrSamplerState::kNearest_Filter;
443 } else {
444 filter = GrSamplerState::kBilinear_Filter;
445 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000446 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
447 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000448
449 static const GrVertexLayout layout =
450 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
451 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
452
453 if (arg.succeeded()) {
454 GrPoint* verts = (GrPoint*) arg.vertices();
455 verts[0].setIRectFan(0, 0,
456 texture->width(),
457 texture->height(),
458 2*sizeof(GrPoint));
459 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
460 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
461 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000462 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000463 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000464 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000465 } else {
466 // TODO: Our CPU stretch doesn't filter. But we create separate
467 // stretched textures when the sampler state is either filtered or
468 // not. Either implement filtered stretch blit on CPU or just create
469 // one when FBO case fails.
470
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000471 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000472 // no longer need to clamp at min RT size.
473 rtDesc.fWidth = GrNextPow2(desc.fWidth);
474 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000475 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000476 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000477 rtDesc.fWidth *
478 rtDesc.fHeight);
479 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
480 srcData, desc.fWidth, desc.fHeight, bpp);
481
482 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
483
484 GrTexture* texture = fGpu->createTexture(rtDesc,
485 stretchedPixels.get(),
486 stretchedRowBytes);
487 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000488 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000489 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000490 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000491
492 } else {
493 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
494 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000495 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000496 }
497 }
498 return entry;
499}
500
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000501namespace {
502inline void gen_scratch_tex_key_values(const GrGpu* gpu,
503 const GrTextureDesc& desc,
504 uint32_t v[4]) {
505 // Instead of a client-provided key of the texture contents
506 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000507 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000508 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000509 // this code path isn't friendly to tiling with NPOT restricitons
510 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000511 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000512 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000514}
515
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000516GrContext::TextureCacheEntry GrContext::lockScratchTexture(
517 const GrTextureDesc& inDesc,
518 ScratchTexMatch match) {
519
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000520 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000521 if (kExact_ScratchTexMatch != match) {
522 // bin by pow2 with a reasonable min
523 static const int MIN_SIZE = 256;
524 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
525 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
526 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000527
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000528 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000529 int origWidth = desc.fWidth;
530 int origHeight = desc.fHeight;
531 bool doubledW = false;
532 bool doubledH = false;
533
534 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000535 uint32_t v[4];
536 gen_scratch_tex_key_values(fGpu, desc, v);
537 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000538 entry = fTextureCache->findAndLock(key,
539 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000540 // if we miss, relax the fit of the flags...
541 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000542 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000543 break;
544 }
545 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
546 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
547 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
548 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
549 } else if (!doubledW) {
550 desc.fFlags = inDesc.fFlags;
551 desc.fWidth *= 2;
552 doubledW = true;
553 } else if (!doubledH) {
554 desc.fFlags = inDesc.fFlags;
555 desc.fWidth = origWidth;
556 desc.fHeight *= 2;
557 doubledH = true;
558 } else {
559 break;
560 }
561
562 } while (true);
563
564 if (NULL == entry) {
565 desc.fFlags = inDesc.fFlags;
566 desc.fWidth = origWidth;
567 desc.fHeight = origHeight;
568 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
569 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000570 uint32_t v[4];
571 gen_scratch_tex_key_values(fGpu, desc, v);
572 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000573 entry = fTextureCache->createAndLock(key, texture);
574 }
575 }
576
577 // If the caller gives us the same desc/sampler twice we don't want
578 // to return the same texture the second time (unless it was previously
579 // released). So we detach the entry from the cache and reattach at release.
580 if (NULL != entry) {
581 fTextureCache->detach(entry);
582 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000583 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000584}
585
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000586void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000587 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000588 // If this is a scratch texture we detached it from the cache
589 // while it was locked (to avoid two callers simultaneously getting
590 // the same texture).
591 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
592 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000593 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000594 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000595 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596}
597
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000598GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000599 void* srcData,
600 size_t rowBytes) {
601 return fGpu->createTexture(desc, srcData, rowBytes);
602}
603
604void GrContext::getTextureCacheLimits(int* maxTextures,
605 size_t* maxTextureBytes) const {
606 fTextureCache->getLimits(maxTextures, maxTextureBytes);
607}
608
609void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
610 fTextureCache->setLimits(maxTextures, maxTextureBytes);
611}
612
bsalomon@google.com91958362011-06-13 17:58:13 +0000613int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000614 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000615}
616
617int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000618 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000619}
620
621///////////////////////////////////////////////////////////////////////////////
622
bsalomon@google.come269f212011-11-07 13:29:52 +0000623GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
624 return fGpu->createPlatformTexture(desc);
625}
626
627GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
628 return fGpu->createPlatformRenderTarget(desc);
629}
630
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000631///////////////////////////////////////////////////////////////////////////////
632
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000633bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000634 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000635 const GrDrawTarget::Caps& caps = fGpu->getCaps();
636 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000637 return false;
638 }
639
bsalomon@google.com27847de2011-02-22 20:59:41 +0000640 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
641
642 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000643 bool tiled = NULL != sampler &&
644 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
645 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000646 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000647 return false;
648 }
649 }
650 return true;
651}
652
653////////////////////////////////////////////////////////////////////////////////
654
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000655const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
656
bsalomon@google.com27847de2011-02-22 20:59:41 +0000657void GrContext::setClip(const GrClip& clip) {
658 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000659 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000660}
661
662void GrContext::setClip(const GrIRect& rect) {
663 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000664 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000665 fGpu->setClip(clip);
666}
667
668////////////////////////////////////////////////////////////////////////////////
669
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000670void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000671 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000672 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000673}
674
675void GrContext::drawPaint(const GrPaint& paint) {
676 // set rect to be big enough to fill the space, but not super-huge, so we
677 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000678 GrRect r;
679 r.setLTRB(0, 0,
680 GrIntToScalar(getRenderTarget()->width()),
681 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000682 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000683 SkTLazy<GrPaint> tmpPaint;
684 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000685 GrDrawState* drawState = fGpu->drawState();
686 GrAutoMatrix am;
687
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000688 // We attempt to map r by the inverse matrix and draw that. mapRect will
689 // map the four corners and bound them with a new rect. This will not
690 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000691 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000692 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000693 GrPrintf("Could not invert matrix");
694 return;
695 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000696 inverse.mapRect(&r);
697 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000698 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000699 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000700 GrPrintf("Could not invert matrix");
701 return;
702 }
703 tmpPaint.set(paint);
704 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
705 p = tmpPaint.get();
706 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000707 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000708 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000709 // by definition this fills the entire clip, no need for AA
710 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000711 if (!tmpPaint.isValid()) {
712 tmpPaint.set(paint);
713 p = tmpPaint.get();
714 }
715 GrAssert(p == tmpPaint.get());
716 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000717 }
718 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000719}
720
bsalomon@google.com205d4602011-04-25 12:43:45 +0000721////////////////////////////////////////////////////////////////////////////////
722
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000723namespace {
724inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
725 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
726}
727}
728
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729////////////////////////////////////////////////////////////////////////////////
730
bsalomon@google.com27847de2011-02-22 20:59:41 +0000731/* create a triangle strip that strokes the specified triangle. There are 8
732 unique vertices, but we repreat the last 2 to close up. Alternatively we
733 could use an indices array, and then only send 8 verts, but not sure that
734 would be faster.
735 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000736static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000737 GrScalar width) {
738 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000739 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000740
741 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
742 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
743 verts[2].set(rect.fRight - rad, rect.fTop + rad);
744 verts[3].set(rect.fRight + rad, rect.fTop - rad);
745 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
746 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
747 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
748 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
749 verts[8] = verts[0];
750 verts[9] = verts[1];
751}
752
bsalomon@google.com205d4602011-04-25 12:43:45 +0000753static void setInsetFan(GrPoint* pts, size_t stride,
754 const GrRect& r, GrScalar dx, GrScalar dy) {
755 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
756}
757
758static const uint16_t gFillAARectIdx[] = {
759 0, 1, 5, 5, 4, 0,
760 1, 2, 6, 6, 5, 1,
761 2, 3, 7, 7, 6, 2,
762 3, 0, 4, 4, 7, 3,
763 4, 5, 6, 6, 7, 4,
764};
765
766int GrContext::aaFillRectIndexCount() const {
767 return GR_ARRAY_COUNT(gFillAARectIdx);
768}
769
770GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
771 if (NULL == fAAFillRectIndexBuffer) {
772 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
773 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000774 if (NULL != fAAFillRectIndexBuffer) {
775 #if GR_DEBUG
776 bool updated =
777 #endif
778 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
779 sizeof(gFillAARectIdx));
780 GR_DEBUGASSERT(updated);
781 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000782 }
783 return fAAFillRectIndexBuffer;
784}
785
786static const uint16_t gStrokeAARectIdx[] = {
787 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
788 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
789 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
790 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
791
792 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
793 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
794 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
795 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
796
797 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
798 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
799 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
800 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
801};
802
803int GrContext::aaStrokeRectIndexCount() const {
804 return GR_ARRAY_COUNT(gStrokeAARectIdx);
805}
806
807GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
808 if (NULL == fAAStrokeRectIndexBuffer) {
809 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
810 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000811 if (NULL != fAAStrokeRectIndexBuffer) {
812 #if GR_DEBUG
813 bool updated =
814 #endif
815 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
816 sizeof(gStrokeAARectIdx));
817 GR_DEBUGASSERT(updated);
818 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000819 }
820 return fAAStrokeRectIndexBuffer;
821}
822
bsalomon@google.coma3108262011-10-10 14:08:47 +0000823static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
824 bool useCoverage) {
825 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000826 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000827 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000828 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
829 }
830 }
831 if (useCoverage) {
832 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
833 } else {
834 layout |= GrDrawTarget::kColor_VertexLayoutBit;
835 }
836 return layout;
837}
838
bsalomon@google.com205d4602011-04-25 12:43:45 +0000839void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000840 const GrRect& devRect,
841 bool useVertexCoverage) {
842 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000843
844 size_t vsize = GrDrawTarget::VertexSize(layout);
845
846 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000847 if (!geo.succeeded()) {
848 GrPrintf("Failed to get space for vertices!\n");
849 return;
850 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000851 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
852 if (NULL == indexBuffer) {
853 GrPrintf("Failed to create index buffer!\n");
854 return;
855 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000856
857 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
858
859 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
860 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
861
862 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
863 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
864
865 verts += sizeof(GrPoint);
866 for (int i = 0; i < 4; ++i) {
867 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
868 }
869
bsalomon@google.coma3108262011-10-10 14:08:47 +0000870 GrColor innerColor;
871 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000872 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000873 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000874 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000875 }
876
bsalomon@google.com205d4602011-04-25 12:43:45 +0000877 verts += 4 * vsize;
878 for (int i = 0; i < 4; ++i) {
879 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
880 }
881
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000882 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000883
884 target->drawIndexed(kTriangles_PrimitiveType, 0,
885 0, 8, this->aaFillRectIndexCount());
886}
887
bsalomon@google.coma3108262011-10-10 14:08:47 +0000888void GrContext::strokeAARect(GrDrawTarget* target,
889 const GrRect& devRect,
890 const GrVec& devStrokeSize,
891 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000892 const GrScalar& dx = devStrokeSize.fX;
893 const GrScalar& dy = devStrokeSize.fY;
894 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
895 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
896
bsalomon@google.com205d4602011-04-25 12:43:45 +0000897 GrScalar spare;
898 {
899 GrScalar w = devRect.width() - dx;
900 GrScalar h = devRect.height() - dy;
901 spare = GrMin(w, h);
902 }
903
904 if (spare <= 0) {
905 GrRect r(devRect);
906 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000907 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 return;
909 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000910 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000911 size_t vsize = GrDrawTarget::VertexSize(layout);
912
913 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000914 if (!geo.succeeded()) {
915 GrPrintf("Failed to get space for vertices!\n");
916 return;
917 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000918 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
919 if (NULL == indexBuffer) {
920 GrPrintf("Failed to create index buffer!\n");
921 return;
922 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000923
924 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
925
926 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
927 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
928 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
929 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
930
931 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
932 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
933 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
934 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
935
936 verts += sizeof(GrPoint);
937 for (int i = 0; i < 4; ++i) {
938 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
939 }
940
bsalomon@google.coma3108262011-10-10 14:08:47 +0000941 GrColor innerColor;
942 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000943 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000944 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000945 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000946 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000947 verts += 4 * vsize;
948 for (int i = 0; i < 8; ++i) {
949 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
950 }
951
952 verts += 8 * vsize;
953 for (int i = 0; i < 8; ++i) {
954 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
955 }
956
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000957 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000958 target->drawIndexed(kTriangles_PrimitiveType,
959 0, 0, 16, aaStrokeRectIndexCount());
960}
961
reed@google.com20efde72011-05-09 17:00:02 +0000962/**
963 * Returns true if the rects edges are integer-aligned.
964 */
965static bool isIRect(const GrRect& r) {
966 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
967 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
968}
969
bsalomon@google.com205d4602011-04-25 12:43:45 +0000970static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000971 const GrRect& rect,
972 GrScalar width,
973 const GrMatrix* matrix,
974 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000975 GrRect* devRect,
976 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000977 // we use a simple coverage ramp to do aa on axis-aligned rects
978 // we check if the rect will be axis-aligned, and the rect won't land on
979 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000980
bsalomon@google.coma3108262011-10-10 14:08:47 +0000981 // we are keeping around the "tweak the alpha" trick because
982 // it is our only hope for the fixed-pipe implementation.
983 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000984 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000985 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000986 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000987 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000988#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000989 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000990#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000991 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000992 } else {
993 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000994 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000995 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000996 const GrDrawState& drawState = target->getDrawState();
997 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000998 return false;
999 }
1000
bsalomon@google.com471d4712011-08-23 15:45:25 +00001001 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002 return false;
1003 }
1004
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001005 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001006 return false;
1007 }
1008
1009 if (NULL != matrix &&
1010 !matrix->preservesAxisAlignment()) {
1011 return false;
1012 }
1013
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001014 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001015 if (NULL != matrix) {
1016 combinedMatrix->preConcat(*matrix);
1017 GrAssert(combinedMatrix->preservesAxisAlignment());
1018 }
1019
1020 combinedMatrix->mapRect(devRect, rect);
1021 devRect->sort();
1022
1023 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001024 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001025 } else {
1026 return true;
1027 }
1028}
1029
bsalomon@google.com27847de2011-02-22 20:59:41 +00001030void GrContext::drawRect(const GrPaint& paint,
1031 const GrRect& rect,
1032 GrScalar width,
1033 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001034 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001035
1036 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001037 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001038
bsalomon@google.com205d4602011-04-25 12:43:45 +00001039 GrRect devRect = rect;
1040 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001041 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001042 bool needAA = paint.fAntiAlias &&
1043 !this->getRenderTarget()->isMultisampled();
1044 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1045 &combinedMatrix, &devRect,
1046 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001047
1048 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001049 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001050 if (width >= 0) {
1051 GrVec strokeSize;;
1052 if (width > 0) {
1053 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001054 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001055 strokeSize.setAbs(strokeSize);
1056 } else {
1057 strokeSize.set(GR_Scalar1, GR_Scalar1);
1058 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001059 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001061 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001062 }
1063 return;
1064 }
1065
bsalomon@google.com27847de2011-02-22 20:59:41 +00001066 if (width >= 0) {
1067 // TODO: consider making static vertex buffers for these cases.
1068 // Hairline could be done by just adding closing vertex to
1069 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001070 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1071
bsalomon@google.com27847de2011-02-22 20:59:41 +00001072 static const int worstCaseVertCount = 10;
1073 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1074
1075 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001076 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001077 return;
1078 }
1079
1080 GrPrimitiveType primType;
1081 int vertCount;
1082 GrPoint* vertex = geo.positions();
1083
1084 if (width > 0) {
1085 vertCount = 10;
1086 primType = kTriangleStrip_PrimitiveType;
1087 setStrokeRectStrip(vertex, rect, width);
1088 } else {
1089 // hairline
1090 vertCount = 5;
1091 primType = kLineStrip_PrimitiveType;
1092 vertex[0].set(rect.fLeft, rect.fTop);
1093 vertex[1].set(rect.fRight, rect.fTop);
1094 vertex[2].set(rect.fRight, rect.fBottom);
1095 vertex[3].set(rect.fLeft, rect.fBottom);
1096 vertex[4].set(rect.fLeft, rect.fTop);
1097 }
1098
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001099 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001100 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001101 GrDrawState* drawState = target->drawState();
1102 avmr.set(drawState);
1103 drawState->preConcatViewMatrix(*matrix);
1104 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001105 }
1106
1107 target->drawNonIndexed(primType, 0, vertCount);
1108 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001109#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001110 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001111 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1112 if (NULL == sqVB) {
1113 GrPrintf("Failed to create static rect vb.\n");
1114 return;
1115 }
1116 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001117 GrDrawState* drawState = target->drawState();
1118 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001120 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001121 0, rect.height(), rect.fTop,
1122 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001123
1124 if (NULL != matrix) {
1125 m.postConcat(*matrix);
1126 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001127 drawState->preConcatViewMatrix(m);
1128 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001129
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001131#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001132 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001133#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001134 }
1135}
1136
1137void GrContext::drawRectToRect(const GrPaint& paint,
1138 const GrRect& dstRect,
1139 const GrRect& srcRect,
1140 const GrMatrix* dstMatrix,
1141 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001142 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001143
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001144 // srcRect refers to paint's first texture
1145 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 drawRect(paint, dstRect, -1, dstMatrix);
1147 return;
1148 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001149
bsalomon@google.com27847de2011-02-22 20:59:41 +00001150 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1151
1152#if GR_STATIC_RECT_VB
1153 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001154 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001155 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001156 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001157
1158 GrMatrix m;
1159
1160 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1161 0, dstRect.height(), dstRect.fTop,
1162 0, 0, GrMatrix::I()[8]);
1163 if (NULL != dstMatrix) {
1164 m.postConcat(*dstMatrix);
1165 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001166 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001168 // srcRect refers to first stage
1169 int otherStageMask = paint.getActiveStageMask() &
1170 (~(1 << GrPaint::kFirstTextureStage));
1171 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001172 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001173 }
1174
bsalomon@google.com27847de2011-02-22 20:59:41 +00001175 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1176 0, srcRect.height(), srcRect.fTop,
1177 0, 0, GrMatrix::I()[8]);
1178 if (NULL != srcMatrix) {
1179 m.postConcat(*srcMatrix);
1180 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001181 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001182
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001183 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1184 if (NULL == sqVB) {
1185 GrPrintf("Failed to create static rect vb.\n");
1186 return;
1187 }
1188 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001189 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1190#else
1191
1192 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001193#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001194 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001195#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1197#endif
1198
tomhudson@google.com93813632011-10-27 20:21:16 +00001199 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1200 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001201 srcRects[0] = &srcRect;
1202 srcMatrices[0] = srcMatrix;
1203
1204 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1205#endif
1206}
1207
1208void GrContext::drawVertices(const GrPaint& paint,
1209 GrPrimitiveType primitiveType,
1210 int vertexCount,
1211 const GrPoint positions[],
1212 const GrPoint texCoords[],
1213 const GrColor colors[],
1214 const uint16_t indices[],
1215 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001216 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001217
1218 GrDrawTarget::AutoReleaseGeometry geo;
1219
1220 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1221
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001222 bool hasTexCoords[GrPaint::kTotalStages] = {
1223 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1224 0 // remaining stages use positions
1225 };
1226
1227 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001228
1229 if (NULL != colors) {
1230 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001231 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001232 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233
1234 if (sizeof(GrPoint) != vertexSize) {
1235 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001236 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001237 return;
1238 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001239 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001241 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1242 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001243 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001244 NULL,
1245 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246 void* curVertex = geo.vertices();
1247
1248 for (int i = 0; i < vertexCount; ++i) {
1249 *((GrPoint*)curVertex) = positions[i];
1250
1251 if (texOffsets[0] > 0) {
1252 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1253 }
1254 if (colorOffset > 0) {
1255 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1256 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001257 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258 }
1259 } else {
1260 target->setVertexSourceToArray(layout, positions, vertexCount);
1261 }
1262
bsalomon@google.com91958362011-06-13 17:58:13 +00001263 // we don't currently apply offscreen AA to this path. Need improved
1264 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001265
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001266 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001267 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001268 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001270 target->drawNonIndexed(primitiveType, 0, vertexCount);
1271 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001272}
1273
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001274///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001275#include "SkDraw.h"
1276#include "SkRasterClip.h"
1277
1278namespace {
1279
1280SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1281 switch (fill) {
1282 case kWinding_PathFill:
1283 return SkPath::kWinding_FillType;
1284 case kEvenOdd_PathFill:
1285 return SkPath::kEvenOdd_FillType;
1286 case kInverseWinding_PathFill:
1287 return SkPath::kInverseWinding_FillType;
1288 case kInverseEvenOdd_PathFill:
1289 return SkPath::kInverseEvenOdd_FillType;
1290 default:
1291 GrCrash("Unexpected fill.");
1292 return SkPath::kWinding_FillType;
1293 }
1294}
1295
1296// gets device coord bounds of path (not considering the fill) and clip. The
1297// path bounds will be a subset of the clip bounds. returns false if path bounds
1298// would be empty.
1299bool get_path_and_clip_bounds(const GrDrawTarget* target,
1300 const GrPath& path,
1301 const GrVec* translate,
1302 GrIRect* pathBounds,
1303 GrIRect* clipBounds) {
1304 // compute bounds as intersection of rt size, clip, and path
1305 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1306 if (NULL == rt) {
1307 return false;
1308 }
1309 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1310 const GrClip& clip = target->getClip();
1311 if (clip.hasConservativeBounds()) {
1312 clip.getConservativeBounds().roundOut(clipBounds);
1313 if (!pathBounds->intersect(*clipBounds)) {
1314 return false;
1315 }
1316 } else {
1317 // pathBounds is currently the rt extent, set clip bounds to that rect.
1318 *clipBounds = *pathBounds;
1319 }
1320 GrRect pathSBounds = path.getBounds();
1321 if (!pathSBounds.isEmpty()) {
1322 if (NULL != translate) {
1323 pathSBounds.offset(*translate);
1324 }
1325 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1326 pathSBounds);
1327 GrIRect pathIBounds;
1328 pathSBounds.roundOut(&pathIBounds);
1329 if (!pathBounds->intersect(pathIBounds)) {
1330 return false;
1331 }
1332 } else {
1333 return false;
1334 }
1335 return true;
1336}
1337
1338/**
1339 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1340 * scratch texture.
1341 */
1342
1343bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1344 const GrIRect& pathDevBounds,
1345 GrPathFill fill,
1346 GrContext* context,
1347 const GrPoint* translate,
1348 GrAutoScratchTexture* tex) {
1349 SkPaint paint;
1350 SkPath tmpPath;
1351 const SkPath* pathToDraw = &clientPath;
1352 if (kHairLine_PathFill == fill) {
1353 paint.setStyle(SkPaint::kStroke_Style);
1354 paint.setStrokeWidth(SK_Scalar1);
1355 } else {
1356 paint.setStyle(SkPaint::kFill_Style);
1357 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1358 if (skfill != pathToDraw->getFillType()) {
1359 tmpPath = *pathToDraw;
1360 tmpPath.setFillType(skfill);
1361 pathToDraw = &tmpPath;
1362 }
1363 }
1364 paint.setAntiAlias(true);
1365 paint.setColor(SK_ColorWHITE);
1366
1367 GrMatrix matrix = context->getMatrix();
1368 if (NULL != translate) {
1369 matrix.postTranslate(translate->fX, translate->fY);
1370 }
1371
1372 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1373 -pathDevBounds.fTop * SK_Scalar1);
1374 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1375 pathDevBounds.height());
1376
1377 SkBitmap bm;
1378 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1379 if (!bm.allocPixels()) {
1380 return false;
1381 }
1382 sk_bzero(bm.getPixels(), bm.getSafeSize());
1383
1384 SkDraw draw;
1385 sk_bzero(&draw, sizeof(draw));
1386 SkRasterClip rc(bounds);
1387 draw.fRC = &rc;
1388 draw.fClip = &rc.bwRgn();
1389 draw.fMatrix = &matrix;
1390 draw.fBitmap = &bm;
1391 draw.drawPath(*pathToDraw, paint);
1392
1393 const GrTextureDesc desc = {
1394 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001395 bounds.fRight,
1396 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001397 kAlpha_8_GrPixelConfig,
1398 {0} // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001399 };
1400
1401 tex->set(context, desc);
1402 GrTexture* texture = tex->texture();
1403
1404 if (NULL == texture) {
1405 return false;
1406 }
1407 SkAutoLockPixels alp(bm);
1408 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1409 bm.getPixels(), bm.rowBytes());
1410 return true;
1411}
1412
1413void draw_around_inv_path(GrDrawTarget* target,
1414 GrDrawState::StageMask stageMask,
1415 const GrIRect& clipBounds,
1416 const GrIRect& pathBounds) {
1417 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1418 GrRect rect;
1419 if (clipBounds.fTop < pathBounds.fTop) {
1420 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1421 clipBounds.fRight, pathBounds.fTop);
1422 target->drawSimpleRect(rect, NULL, stageMask);
1423 }
1424 if (clipBounds.fLeft < pathBounds.fLeft) {
1425 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1426 pathBounds.fLeft, pathBounds.fBottom);
1427 target->drawSimpleRect(rect, NULL, stageMask);
1428 }
1429 if (clipBounds.fRight > pathBounds.fRight) {
1430 rect.iset(pathBounds.fRight, pathBounds.fTop,
1431 clipBounds.fRight, pathBounds.fBottom);
1432 target->drawSimpleRect(rect, NULL, stageMask);
1433 }
1434 if (clipBounds.fBottom > pathBounds.fBottom) {
1435 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1436 clipBounds.fRight, clipBounds.fBottom);
1437 target->drawSimpleRect(rect, NULL, stageMask);
1438 }
1439}
1440
1441}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001442
reed@google.com07f3ee12011-05-16 17:21:57 +00001443void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1444 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001445
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001446 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001447 if (GrIsFillInverted(fill)) {
1448 this->drawPaint(paint);
1449 }
1450 return;
1451 }
1452
bsalomon@google.com27847de2011-02-22 20:59:41 +00001453 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001454 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001455
bsalomon@google.com289533a2011-10-27 12:34:25 +00001456 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1457
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001458 // An Assumption here is that path renderer would use some form of tweaking
1459 // the src color (either the input alpha or in the frag shader) to implement
1460 // aa. If we have some future driver-mojo path AA that can do the right
1461 // thing WRT to the blend then we'll need some query on the PR.
1462 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001463#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001464 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001465#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001466 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001467 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001468
bsalomon@google.com289533a2011-10-27 12:34:25 +00001469 GrPathRenderer* pr = NULL;
1470 if (prAA) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001471 pr = this->getPathRenderer(path, fill, target, true);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001472 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001473 GrAutoScratchTexture ast;
1474 GrIRect pathBounds, clipBounds;
1475 if (!get_path_and_clip_bounds(target, path, translate,
1476 &pathBounds, &clipBounds)) {
1477 return;
1478 }
bsalomon@google.com150d2842012-01-12 20:19:56 +00001479 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1480 fill, this,
1481 translate, &ast)) {
1482 GrTexture* texture = ast.texture();
1483 GrAssert(NULL != texture);
1484 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1485 enum {
1486 kPathMaskStage = GrPaint::kTotalStages,
1487 };
1488 target->drawState()->setTexture(kPathMaskStage, texture);
1489 target->drawState()->sampler(kPathMaskStage)->reset();
1490 GrScalar w = GrIntToScalar(pathBounds.width());
1491 GrScalar h = GrIntToScalar(pathBounds.height());
1492 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1493 h / texture->height());
1494 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1495 srcRects[kPathMaskStage] = &maskRect;
1496 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001497 GrRect dstRect = GrRect::MakeLTRB(
1498 SK_Scalar1* pathBounds.fLeft,
1499 SK_Scalar1* pathBounds.fTop,
1500 SK_Scalar1* pathBounds.fRight,
1501 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001502 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1503 target->drawState()->setTexture(kPathMaskStage, NULL);
1504 if (GrIsFillInverted(fill)) {
1505 draw_around_inv_path(target, stageMask,
1506 clipBounds, pathBounds);
1507 }
1508 return;
1509 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001510 }
1511 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001512 pr = this->getPathRenderer(path, fill, target, false);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001513 }
1514
bsalomon@google.com30085192011-08-19 15:42:31 +00001515 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001516#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001517 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001518#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001519 return;
1520 }
1521
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001522 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001523}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001524
bsalomon@google.com27847de2011-02-22 20:59:41 +00001525////////////////////////////////////////////////////////////////////////////////
1526
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001527void GrContext::flush(int flagsBitfield) {
1528 if (kDiscard_FlushBit & flagsBitfield) {
1529 fDrawBuffer->reset();
1530 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001531 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001532 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001533 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001534 fGpu->forceRenderTargetFlush();
1535 }
1536}
1537
1538void GrContext::flushText() {
1539 if (kText_DrawCategory == fLastDrawCategory) {
1540 flushDrawBuffer();
1541 }
1542}
1543
1544void GrContext::flushDrawBuffer() {
1545#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001546 if (fDrawBuffer) {
1547 fDrawBuffer->playback(fGpu);
1548 fDrawBuffer->reset();
1549 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001550#endif
1551}
1552
bsalomon@google.com6f379512011-11-16 20:36:03 +00001553void GrContext::internalWriteTexturePixels(GrTexture* texture,
1554 int left, int top,
1555 int width, int height,
1556 GrPixelConfig config,
1557 const void* buffer,
1558 size_t rowBytes,
1559 uint32_t flags) {
1560 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001561 ASSERT_OWNED_RESOURCE(texture);
1562
bsalomon@google.com6f379512011-11-16 20:36:03 +00001563 if (!(kDontFlush_PixelOpsFlag & flags)) {
1564 this->flush();
1565 }
1566 // TODO: use scratch texture to perform conversion
1567 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1568 GrPixelConfigIsUnpremultiplied(config)) {
1569 return;
1570 }
1571
1572 fGpu->writeTexturePixels(texture, left, top, width, height,
1573 config, buffer, rowBytes);
1574}
1575
1576bool GrContext::internalReadTexturePixels(GrTexture* texture,
1577 int left, int top,
1578 int width, int height,
1579 GrPixelConfig config,
1580 void* buffer,
1581 size_t rowBytes,
1582 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001583 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001584 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001585
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001586 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001587 GrRenderTarget* target = texture->asRenderTarget();
1588 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001589 return this->internalReadRenderTargetPixels(target,
1590 left, top, width, height,
1591 config, buffer, rowBytes,
1592 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001593 } else {
1594 return false;
1595 }
1596}
1597
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001598#include "SkConfig8888.h"
1599
1600namespace {
1601/**
1602 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1603 * formats are representable as Config8888 and so the function returns false
1604 * if the GrPixelConfig has no equivalent Config8888.
1605 */
1606bool grconfig_to_config8888(GrPixelConfig config,
1607 SkCanvas::Config8888* config8888) {
1608 switch (config) {
1609 case kRGBA_8888_PM_GrPixelConfig:
1610 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1611 return true;
1612 case kRGBA_8888_UPM_GrPixelConfig:
1613 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1614 return true;
1615 case kBGRA_8888_PM_GrPixelConfig:
1616 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1617 return true;
1618 case kBGRA_8888_UPM_GrPixelConfig:
1619 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1620 return true;
1621 default:
1622 return false;
1623 }
1624}
1625}
1626
bsalomon@google.com6f379512011-11-16 20:36:03 +00001627bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1628 int left, int top,
1629 int width, int height,
1630 GrPixelConfig config,
1631 void* buffer,
1632 size_t rowBytes,
1633 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001634 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001635 ASSERT_OWNED_RESOURCE(target);
1636
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001637 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001638 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001639 if (NULL == target) {
1640 return false;
1641 }
1642 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001643
bsalomon@google.com6f379512011-11-16 20:36:03 +00001644 if (!(kDontFlush_PixelOpsFlag & flags)) {
1645 this->flush();
1646 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001647
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001648 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1649 GrPixelConfigIsUnpremultiplied(config) &&
1650 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1651 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1652 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1653 !grconfig_to_config8888(config, &dstConfig8888)) {
1654 return false;
1655 }
1656 // do read back using target's own config
1657 this->internalReadRenderTargetPixels(target,
1658 left, top,
1659 width, height,
1660 target->config(),
1661 buffer, rowBytes,
1662 kDontFlush_PixelOpsFlag);
1663 // sw convert the pixels to unpremul config
1664 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1665 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1666 pixels, rowBytes, srcConfig8888,
1667 width, height);
1668 return true;
1669 }
1670
bsalomon@google.comc4364992011-11-07 15:54:49 +00001671 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001672 bool swapRAndB = NULL != src &&
1673 fGpu->preferredReadPixelsConfig(config) ==
1674 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001675
1676 bool flipY = NULL != src &&
1677 fGpu->readPixelsWillPayForYFlip(target, left, top,
1678 width, height, config,
1679 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001680 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1681 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001682
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001683 if (NULL == src && alphaConversion) {
1684 // we should fallback to cpu conversion here. This could happen when
1685 // we were given an external render target by the client that is not
1686 // also a texture (e.g. FBO 0 in GL)
1687 return false;
1688 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001689 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001690 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001691 if (flipY || swapRAndB || alphaConversion) {
1692 GrAssert(NULL != src);
1693 if (swapRAndB) {
1694 config = GrPixelConfigSwapRAndB(config);
1695 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001696 }
1697 // Make the scratch a render target because we don't have a robust
1698 // readTexturePixels as of yet (it calls this function).
1699 const GrTextureDesc desc = {
1700 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001701 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001702 config,
1703 {0}, // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001704 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001705
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001706 // When a full readback is faster than a partial we could always make
1707 // the scratch exactly match the passed rect. However, if we see many
1708 // different size rectangles we will trash our texture cache and pay the
1709 // cost of creating and destroying many textures. So, we only request
1710 // an exact match when the caller is reading an entire RT.
1711 ScratchTexMatch match = kApprox_ScratchTexMatch;
1712 if (0 == left &&
1713 0 == top &&
1714 target->width() == width &&
1715 target->height() == height &&
1716 fGpu->fullReadPixelsIsFasterThanPartial()) {
1717 match = kExact_ScratchTexMatch;
1718 }
1719 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001720 GrTexture* texture = ast.texture();
1721 if (!texture) {
1722 return false;
1723 }
1724 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001725 GrAssert(NULL != target);
1726
1727 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001728 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001729 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001730 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001731
bsalomon@google.comc4364992011-11-07 15:54:49 +00001732 GrMatrix matrix;
1733 if (flipY) {
1734 matrix.setTranslate(SK_Scalar1 * left,
1735 SK_Scalar1 * (top + height));
1736 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1737 } else {
1738 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1739 }
1740 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001741 drawState->sampler(0)->reset(matrix);
1742 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001743 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001744 GrRect rect;
1745 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1746 fGpu->drawSimpleRect(rect, NULL, 0x1);
1747 left = 0;
1748 top = 0;
1749 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001750 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001751 left, top, width, height,
1752 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001753}
1754
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001755void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1756 GrAssert(target);
1757 ASSERT_OWNED_RESOURCE(target);
1758 // In the future we may track whether there are any pending draws to this
1759 // target. We don't today so we always perform a flush. We don't promise
1760 // this to our clients, though.
1761 this->flush();
1762 fGpu->resolveRenderTarget(target);
1763}
1764
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001765void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1766 if (NULL == src || NULL == dst) {
1767 return;
1768 }
1769 ASSERT_OWNED_RESOURCE(src);
1770
1771 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001772 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001773 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001774 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001775 GrMatrix sampleM;
1776 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001777 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001778 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001779 SkRect rect = SkRect::MakeXYWH(0, 0,
1780 SK_Scalar1 * src->width(),
1781 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001782 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1783}
1784
bsalomon@google.com6f379512011-11-16 20:36:03 +00001785void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1786 int left, int top,
1787 int width, int height,
1788 GrPixelConfig config,
1789 const void* buffer,
1790 size_t rowBytes,
1791 uint32_t flags) {
1792 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001793 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001794
1795 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001796 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001797 if (NULL == target) {
1798 return;
1799 }
1800 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001801
1802 // TODO: when underlying api has a direct way to do this we should use it
1803 // (e.g. glDrawPixels on desktop GL).
1804
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001805 // If the RT is also a texture and we don't have to do PM/UPM conversion
1806 // then take the texture path, which we expect to be at least as fast or
1807 // faster since it doesn't use an intermediate texture as we do below.
1808
1809#if !GR_MAC_BUILD
1810 // At least some drivers on the Mac get confused when glTexImage2D is called
1811 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1812 // determine what OS versions and/or HW is affected.
1813 if (NULL != target->asTexture() &&
1814 GrPixelConfigIsUnpremultiplied(target->config()) ==
1815 GrPixelConfigIsUnpremultiplied(config)) {
1816
1817 this->internalWriteTexturePixels(target->asTexture(),
1818 left, top, width, height,
1819 config, buffer, rowBytes, flags);
1820 return;
1821 }
1822#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001823 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1824 GrPixelConfigIsUnpremultiplied(config) &&
1825 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1826 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1827 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1828 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1829 return;
1830 }
1831 // allocate a tmp buffer and sw convert the pixels to premul
1832 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1833 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1834 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1835 src, rowBytes, srcConfig8888,
1836 width, height);
1837 // upload the already premul pixels
1838 this->internalWriteRenderTargetPixels(target,
1839 left, top,
1840 width, height,
1841 target->config(),
1842 tmpPixels, 4 * width, flags);
1843 return;
1844 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001845
1846 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1847 GrPixelConfigSwapRAndB(config);
1848 if (swapRAndB) {
1849 config = GrPixelConfigSwapRAndB(config);
1850 }
1851
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001852 const GrTextureDesc desc = {
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001853 kNone_GrTextureFlags, width, height, config, {0}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001854 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001855 GrAutoScratchTexture ast(this, desc);
1856 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001857 if (NULL == texture) {
1858 return;
1859 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001860 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1861 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001862
bsalomon@google.com27847de2011-02-22 20:59:41 +00001863 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001864 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001865 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001866
1867 GrMatrix matrix;
1868 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001869 drawState->setViewMatrix(matrix);
1870 drawState->setRenderTarget(target);
1871 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001872
bsalomon@google.com5c638652011-07-18 19:31:59 +00001873 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001874 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1875 GrSamplerState::kNearest_Filter,
1876 matrix);
1877 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001878
1879 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1880 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001881 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001882 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1883 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001884 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885 return;
1886 }
1887 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1888 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1889}
1890////////////////////////////////////////////////////////////////////////////////
1891
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001892void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001893 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001894
1895 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1896 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001897 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001898 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001899 if (paint.getTexture(i)) {
1900 *drawState->sampler(s) = paint.getTextureSampler(i);
1901 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001902 }
1903
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001904 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001905
1906 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1907 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001908 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001909 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001910 if (paint.getMask(i)) {
1911 *drawState->sampler(s) = paint.getMaskSampler(i);
1912 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001913 }
1914
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001915 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001916
1917 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001918 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001919 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001920 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001921 }
1922 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001923 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001924 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001925 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001926 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001927 if (paint.fColorMatrixEnabled) {
1928 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
bsalomon@google.com9b1517e2012-03-05 17:58:34 +00001929 drawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001930 } else {
1931 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
1932 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001933 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001934 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comdd1be602012-01-18 20:34:00 +00001935 drawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001936
1937 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1938 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1939 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001940}
1941
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001942GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001943 DrawCategory category) {
1944 if (category != fLastDrawCategory) {
1945 flushDrawBuffer();
1946 fLastDrawCategory = category;
1947 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001948 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001949 GrDrawTarget* target = fGpu;
1950 switch (category) {
1951 case kText_DrawCategory:
1952#if DEFER_TEXT_RENDERING
1953 target = fDrawBuffer;
1954 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1955#else
1956 target = fGpu;
1957#endif
1958 break;
1959 case kUnbuffered_DrawCategory:
1960 target = fGpu;
1961 break;
1962 case kBuffered_DrawCategory:
1963 target = fDrawBuffer;
1964 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1965 break;
1966 }
1967 return target;
1968}
1969
bsalomon@google.com289533a2011-10-27 12:34:25 +00001970GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1971 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001972 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001973 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001974 if (NULL == fPathRendererChain) {
1975 fPathRendererChain =
1976 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1977 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001978 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001979}
1980
bsalomon@google.com27847de2011-02-22 20:59:41 +00001981////////////////////////////////////////////////////////////////////////////////
1982
bsalomon@google.com27847de2011-02-22 20:59:41 +00001983void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001984 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001985 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001986 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001987}
1988
1989GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001990 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001991}
1992
1993const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001994 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001995}
1996
1997const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001998 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999}
2000
2001void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002002 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002003}
2004
2005void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002006 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002007}
2008
2009static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2010 intptr_t mask = 1 << shift;
2011 if (pred) {
2012 bits |= mask;
2013 } else {
2014 bits &= ~mask;
2015 }
2016 return bits;
2017}
2018
2019void GrContext::resetStats() {
2020 fGpu->resetStats();
2021}
2022
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002023const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002024 return fGpu->getStats();
2025}
2026
2027void GrContext::printStats() const {
2028 fGpu->printStats();
2029}
2030
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002031GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002032 fGpu = gpu;
2033 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002034 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002035
bsalomon@google.com30085192011-08-19 15:42:31 +00002036 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002037
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002038 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2039 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002040 fFontCache = new GrFontCache(fGpu);
2041
2042 fLastDrawCategory = kUnbuffered_DrawCategory;
2043
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002044 fDrawBuffer = NULL;
2045 fDrawBufferVBAllocPool = NULL;
2046 fDrawBufferIBAllocPool = NULL;
2047
bsalomon@google.com205d4602011-04-25 12:43:45 +00002048 fAAFillRectIndexBuffer = NULL;
2049 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002050
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002051 this->setupDrawBuffer();
2052}
2053
2054void GrContext::setupDrawBuffer() {
2055
2056 GrAssert(NULL == fDrawBuffer);
2057 GrAssert(NULL == fDrawBufferVBAllocPool);
2058 GrAssert(NULL == fDrawBufferIBAllocPool);
2059
bsalomon@google.com27847de2011-02-22 20:59:41 +00002060#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002061 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002062 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002063 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2064 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002065 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002066 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002067 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002068 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2069
bsalomon@google.com471d4712011-08-23 15:45:25 +00002070 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2071 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002072 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002073#endif
2074
2075#if BATCH_RECT_TO_RECT
2076 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2077#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002078}
2079
bsalomon@google.com27847de2011-02-22 20:59:41 +00002080GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2081 GrDrawTarget* target;
2082#if DEFER_TEXT_RENDERING
2083 target = prepareToDraw(paint, kText_DrawCategory);
2084#else
2085 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2086#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002087 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002088 return target;
2089}
2090
2091const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2092 return fGpu->getQuadIndexBuffer();
2093}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002094
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002095GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2096 GrAutoScratchTexture* temp1,
2097 GrAutoScratchTexture* temp2,
2098 const SkRect& rect,
2099 float sigmaX, float sigmaY) {
2100 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2101 GrClip oldClip = this->getClip();
2102 GrTexture* origTexture = srcTexture;
2103 GrAutoMatrix avm(this, GrMatrix::I());
2104 SkIRect clearRect;
2105 int scaleFactorX, halfWidthX, kernelWidthX;
2106 int scaleFactorY, halfWidthY, kernelWidthY;
2107 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2108 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002109
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002110 SkRect srcRect(rect);
2111 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2112 srcRect.roundOut();
2113 scale_rect(&srcRect, scaleFactorX, scaleFactorY);
2114 this->setClip(srcRect);
2115
2116 const GrTextureDesc desc = {
2117 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
2118 srcRect.width(),
2119 srcRect.height(),
2120 kRGBA_8888_GrPixelConfig,
2121 {0} // samples
2122 };
2123
2124 temp1->set(this, desc);
2125 if (temp2) temp2->set(this, desc);
2126
2127 GrTexture* dstTexture = temp1->texture();
2128 GrPaint paint;
2129 paint.reset();
2130 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2131
2132 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2133 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2134 srcTexture->height());
2135 this->setRenderTarget(dstTexture->asRenderTarget());
2136 SkRect dstRect(srcRect);
2137 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2138 i < scaleFactorY ? 0.5f : 1.0f);
2139 paint.setTexture(0, srcTexture);
2140 this->drawRectToRect(paint, dstRect, srcRect);
2141 srcRect = dstRect;
2142 SkTSwap(srcTexture, dstTexture);
2143 // If temp2 is non-NULL, don't render back to origTexture
2144 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2145 }
2146
2147 if (sigmaX > 0.0f) {
2148 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2149 float* kernelX = kernelStorageX.get();
2150 build_kernel(sigmaX, kernelX, kernelWidthX);
2151
2152 if (scaleFactorX > 1) {
2153 // Clear out a halfWidth to the right of the srcRect to prevent the
2154 // X convolution from reading garbage.
2155 clearRect = SkIRect::MakeXYWH(
2156 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2157 this->clear(&clearRect, 0x0);
2158 }
2159
2160 this->setRenderTarget(dstTexture->asRenderTarget());
2161 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2162 GrSamplerState::kX_FilterDirection);
2163 SkTSwap(srcTexture, dstTexture);
2164 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2165 }
2166
2167 if (sigmaY > 0.0f) {
2168 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2169 float* kernelY = kernelStorageY.get();
2170 build_kernel(sigmaY, kernelY, kernelWidthY);
2171
2172 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2173 // Clear out a halfWidth below the srcRect to prevent the Y
2174 // convolution from reading garbage.
2175 clearRect = SkIRect::MakeXYWH(
2176 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2177 this->clear(&clearRect, 0x0);
2178 }
2179
2180 this->setRenderTarget(dstTexture->asRenderTarget());
2181 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2182 GrSamplerState::kY_FilterDirection);
2183 SkTSwap(srcTexture, dstTexture);
2184 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2185 }
2186
2187 if (scaleFactorX > 1 || scaleFactorY > 1) {
2188 // Clear one pixel to the right and below, to accommodate bilinear
2189 // upsampling.
2190 clearRect = SkIRect::MakeXYWH(
2191 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2192 this->clear(&clearRect, 0x0);
2193 clearRect = SkIRect::MakeXYWH(
2194 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2195 this->clear(&clearRect, 0x0);
2196 // FIXME: This should be mitchell, not bilinear.
2197 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2198 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2199 srcTexture->height());
2200 this->setRenderTarget(dstTexture->asRenderTarget());
2201 paint.setTexture(0, srcTexture);
2202 SkRect dstRect(srcRect);
2203 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2204 this->drawRectToRect(paint, dstRect, srcRect);
2205 srcRect = dstRect;
2206 SkTSwap(srcTexture, dstTexture);
2207 }
2208 this->setRenderTarget(oldRenderTarget);
2209 this->setClip(oldClip);
2210 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002211}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002212
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002213GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2214 const GrRect& rect,
2215 GrTexture* temp1, GrTexture* temp2,
2216 GrSamplerState::Filter filter,
2217 SkISize radius) {
2218 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2219 GrAutoMatrix avm(this, GrMatrix::I());
2220 GrClip oldClip = this->getClip();
2221 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2222 if (radius.fWidth > 0) {
2223 this->setRenderTarget(temp1->asRenderTarget());
2224 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2225 GrSamplerState::kX_FilterDirection);
2226 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2227 rect.width(), radius.fHeight);
2228 this->clear(&clearRect, 0x0);
2229 srcTexture = temp1;
2230 }
2231 if (radius.fHeight > 0) {
2232 this->setRenderTarget(temp2->asRenderTarget());
2233 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2234 GrSamplerState::kY_FilterDirection);
2235 srcTexture = temp2;
2236 }
2237 this->setRenderTarget(oldRenderTarget);
2238 this->setClip(oldClip);
2239 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002240}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002241
2242///////////////////////////////////////////////////////////////////////////////