blob: 0bcecd623360c16a3895493b0811ad7e2a59b565 [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
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000027#define DEFER_PATHS 1
28
bsalomon@google.com27847de2011-02-22 20:59:41 +000029#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
30
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000031#define MAX_BLUR_SIGMA 4.0f
32
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000033
bsalomon@google.comd46e2422011-09-23 17:40:07 +000034// When we're using coverage AA but the blend is incompatible (given gpu
35// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000036#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000037
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000038static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
39static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000040
bsalomon@google.com60361492012-03-15 17:47:06 +000041static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000042static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
43
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000044// path rendering is the only thing we defer today that uses non-static indices
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000047
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.coma5d22032012-03-27 17:40:15 +000073 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com30085192011-08-19 15:42:31 +000086 // a path renderer may be holding onto resources that
87 // are now unusable
88 GrSafeSetNull(fPathRendererChain);
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 delete fDrawBuffer;
91 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000092
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 delete fDrawBufferVBAllocPool;
94 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000095
bsalomon@google.com8fe72472011-03-30 21:26:44 +000096 delete fDrawBufferIBAllocPool;
97 fDrawBufferIBAllocPool = NULL;
98
bsalomon@google.com205d4602011-04-25 12:43:45 +000099 GrSafeSetNull(fAAFillRectIndexBuffer);
100 GrSafeSetNull(fAAStrokeRectIndexBuffer);
101
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102 fTextureCache->removeAll();
103 fFontCache->freeAll();
104 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105}
106
107void GrContext::resetContext() {
108 fGpu->markContextDirty();
109}
110
111void GrContext::freeGpuResources() {
112 this->flush();
113 fTextureCache->removeAll();
114 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000115 // a path renderer may be holding onto resources
116 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000117}
118
twiz@google.com05e70242012-01-27 19:12:00 +0000119size_t GrContext::getGpuTextureCacheBytes() const {
120 return fTextureCache->getCachedResourceBytes();
121}
122
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000123////////////////////////////////////////////////////////////////////////////////
124
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000125int GrContext::PaintStageVertexLayoutBits(
126 const GrPaint& paint,
127 const bool hasTexCoords[GrPaint::kTotalStages]) {
128 int stageMask = paint.getActiveStageMask();
129 int layout = 0;
130 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
131 if ((1 << i) & stageMask) {
132 if (NULL != hasTexCoords && hasTexCoords[i]) {
133 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
134 } else {
135 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
136 }
137 }
138 }
139 return layout;
140}
141
142
143////////////////////////////////////////////////////////////////////////////////
144
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000145enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000146 // flags for textures
147 kNPOTBit = 0x1,
148 kFilterBit = 0x2,
149 kScratchBit = 0x4,
150
151 // resource type
152 kTextureBit = 0x8,
153 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000154};
155
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000156GrTexture* GrContext::TextureCacheEntry::texture() const {
157 if (NULL == fEntry) {
158 return NULL;
159 } else {
160 return (GrTexture*) fEntry->resource();
161 }
162}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000163
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000164namespace {
165// returns true if this is a "special" texture because of gpu NPOT limitations
166bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000167 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000168 GrContext::TextureKey clientKey,
169 int width,
170 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000171 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000172 bool scratch,
173 uint32_t v[4]) {
174 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
175 // we assume we only need 16 bits of width and height
176 // assert that texture creation will fail anyway if this assumption
177 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000178 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000179 v[0] = clientKey & 0xffffffffUL;
180 v[1] = (clientKey >> 32) & 0xffffffffUL;
181 v[2] = width | (height << 16);
182
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000183 v[3] = (sampleCnt << 24);
184 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
185
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000186 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000187 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
188
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000189 bool tiled = NULL != sampler &&
190 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
191 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000192
193 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000195 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000197 }
198 }
199 }
200
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000201 if (scratch) {
202 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000203 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000204
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000205 v[3] |= kTextureBit;
206
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000207 return v[3] & kNPOTBit;
208}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000209
210// we should never have more than one stencil buffer with same combo of
211// (width,height,samplecount)
212void gen_stencil_key_values(int width, int height,
213 int sampleCnt, uint32_t v[4]) {
214 v[0] = width;
215 v[1] = height;
216 v[2] = sampleCnt;
217 v[3] = kStencilBufferBit;
218}
219
220void gen_stencil_key_values(const GrStencilBuffer* sb,
221 uint32_t v[4]) {
222 gen_stencil_key_values(sb->width(), sb->height(),
223 sb->numSamples(), v);
224}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000225
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000226void build_kernel(float sigma, float* kernel, int kernelWidth) {
227 int halfWidth = (kernelWidth - 1) / 2;
228 float sum = 0.0f;
229 float denom = 1.0f / (2.0f * sigma * sigma);
230 for (int i = 0; i < kernelWidth; ++i) {
231 float x = static_cast<float>(i - halfWidth);
232 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
233 // is dropped here, since we renormalize the kernel below.
234 kernel[i] = sk_float_exp(- x * x * denom);
235 sum += kernel[i];
236 }
237 // Normalize the kernel
238 float scale = 1.0f / sum;
239 for (int i = 0; i < kernelWidth; ++i)
240 kernel[i] *= scale;
241}
242
243void scale_rect(SkRect* rect, float xScale, float yScale) {
244 rect->fLeft *= xScale;
245 rect->fTop *= yScale;
246 rect->fRight *= xScale;
247 rect->fBottom *= yScale;
248}
249
250float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
251 int *kernelWidth) {
252 *scaleFactor = 1;
253 while (sigma > MAX_BLUR_SIGMA) {
254 *scaleFactor *= 2;
255 sigma *= 0.5f;
256 }
257 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
258 *kernelWidth = *halfWidth * 2 + 1;
259 return sigma;
260}
261
262void apply_morphology(GrGpu* gpu,
263 GrTexture* texture,
264 const SkRect& rect,
265 int radius,
266 GrSamplerState::Filter filter,
267 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000268 GrAssert(filter == GrSamplerState::kErode_Filter ||
269 filter == GrSamplerState::kDilate_Filter);
270
271 GrDrawTarget::AutoStateRestore asr(gpu);
272 GrDrawState* drawState = gpu->drawState();
273 GrRenderTarget* target = drawState->getRenderTarget();
274 drawState->reset();
275 drawState->setRenderTarget(target);
276 GrMatrix sampleM;
277 sampleM.setIDiv(texture->width(), texture->height());
278 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
279 sampleM);
280 drawState->sampler(0)->setMorphologyRadius(radius);
281 drawState->sampler(0)->setFilterDirection(direction);
282 drawState->setTexture(0, texture);
283 gpu->drawSimpleRect(rect, NULL, 1 << 0);
284}
285
286void convolve(GrGpu* gpu,
287 GrTexture* texture,
288 const SkRect& rect,
289 const float* kernel,
290 int kernelWidth,
291 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000292 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.coma5d22032012-03-27 17:40:15 +0000659 fDrawState->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 GrAutoMatrix am;
686
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000687 // We attempt to map r by the inverse matrix and draw that. mapRect will
688 // map the four corners and bound them with a new rect. This will not
689 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000690 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +0000691 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000692 GrPrintf("Could not invert matrix");
693 return;
694 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000695 inverse.mapRect(&r);
696 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000697 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +0000698 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000699 GrPrintf("Could not invert matrix");
700 return;
701 }
702 tmpPaint.set(paint);
703 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
704 p = tmpPaint.get();
705 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000706 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000707 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000708 // by definition this fills the entire clip, no need for AA
709 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000710 if (!tmpPaint.isValid()) {
711 tmpPaint.set(paint);
712 p = tmpPaint.get();
713 }
714 GrAssert(p == tmpPaint.get());
715 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000716 }
717 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000718}
719
bsalomon@google.com205d4602011-04-25 12:43:45 +0000720////////////////////////////////////////////////////////////////////////////////
721
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000722namespace {
723inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
724 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
725}
726}
727
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000728////////////////////////////////////////////////////////////////////////////////
729
bsalomon@google.com27847de2011-02-22 20:59:41 +0000730/* create a triangle strip that strokes the specified triangle. There are 8
731 unique vertices, but we repreat the last 2 to close up. Alternatively we
732 could use an indices array, and then only send 8 verts, but not sure that
733 would be faster.
734 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000735static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000736 GrScalar width) {
737 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000738 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000739
740 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
741 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
742 verts[2].set(rect.fRight - rad, rect.fTop + rad);
743 verts[3].set(rect.fRight + rad, rect.fTop - rad);
744 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
745 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
746 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
747 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
748 verts[8] = verts[0];
749 verts[9] = verts[1];
750}
751
bsalomon@google.com205d4602011-04-25 12:43:45 +0000752static void setInsetFan(GrPoint* pts, size_t stride,
753 const GrRect& r, GrScalar dx, GrScalar dy) {
754 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
755}
756
757static const uint16_t gFillAARectIdx[] = {
758 0, 1, 5, 5, 4, 0,
759 1, 2, 6, 6, 5, 1,
760 2, 3, 7, 7, 6, 2,
761 3, 0, 4, 4, 7, 3,
762 4, 5, 6, 6, 7, 4,
763};
764
765int GrContext::aaFillRectIndexCount() const {
766 return GR_ARRAY_COUNT(gFillAARectIdx);
767}
768
769GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
770 if (NULL == fAAFillRectIndexBuffer) {
771 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
772 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000773 if (NULL != fAAFillRectIndexBuffer) {
774 #if GR_DEBUG
775 bool updated =
776 #endif
777 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
778 sizeof(gFillAARectIdx));
779 GR_DEBUGASSERT(updated);
780 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000781 }
782 return fAAFillRectIndexBuffer;
783}
784
785static const uint16_t gStrokeAARectIdx[] = {
786 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
787 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
788 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
789 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
790
791 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
792 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
793 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
794 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
795
796 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
797 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
798 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
799 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
800};
801
802int GrContext::aaStrokeRectIndexCount() const {
803 return GR_ARRAY_COUNT(gStrokeAARectIdx);
804}
805
806GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
807 if (NULL == fAAStrokeRectIndexBuffer) {
808 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
809 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000810 if (NULL != fAAStrokeRectIndexBuffer) {
811 #if GR_DEBUG
812 bool updated =
813 #endif
814 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
815 sizeof(gStrokeAARectIdx));
816 GR_DEBUGASSERT(updated);
817 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000818 }
819 return fAAStrokeRectIndexBuffer;
820}
821
bsalomon@google.coma3108262011-10-10 14:08:47 +0000822static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
823 bool useCoverage) {
824 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000825 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000826 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000827 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
828 }
829 }
830 if (useCoverage) {
831 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
832 } else {
833 layout |= GrDrawTarget::kColor_VertexLayoutBit;
834 }
835 return layout;
836}
837
bsalomon@google.com205d4602011-04-25 12:43:45 +0000838void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000839 const GrRect& devRect,
840 bool useVertexCoverage) {
841 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000842
843 size_t vsize = GrDrawTarget::VertexSize(layout);
844
845 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000846 if (!geo.succeeded()) {
847 GrPrintf("Failed to get space for vertices!\n");
848 return;
849 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000850 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
851 if (NULL == indexBuffer) {
852 GrPrintf("Failed to create index buffer!\n");
853 return;
854 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000855
856 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
857
858 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
859 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
860
861 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
862 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
863
864 verts += sizeof(GrPoint);
865 for (int i = 0; i < 4; ++i) {
866 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
867 }
868
bsalomon@google.coma3108262011-10-10 14:08:47 +0000869 GrColor innerColor;
870 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000871 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000872 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000873 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000874 }
875
bsalomon@google.com205d4602011-04-25 12:43:45 +0000876 verts += 4 * vsize;
877 for (int i = 0; i < 4; ++i) {
878 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
879 }
880
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000881 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000882
883 target->drawIndexed(kTriangles_PrimitiveType, 0,
884 0, 8, this->aaFillRectIndexCount());
885}
886
bsalomon@google.coma3108262011-10-10 14:08:47 +0000887void GrContext::strokeAARect(GrDrawTarget* target,
888 const GrRect& devRect,
889 const GrVec& devStrokeSize,
890 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000891 const GrScalar& dx = devStrokeSize.fX;
892 const GrScalar& dy = devStrokeSize.fY;
893 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
894 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
895
bsalomon@google.com205d4602011-04-25 12:43:45 +0000896 GrScalar spare;
897 {
898 GrScalar w = devRect.width() - dx;
899 GrScalar h = devRect.height() - dy;
900 spare = GrMin(w, h);
901 }
902
903 if (spare <= 0) {
904 GrRect r(devRect);
905 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000906 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000907 return;
908 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000909 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000910 size_t vsize = GrDrawTarget::VertexSize(layout);
911
912 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000913 if (!geo.succeeded()) {
914 GrPrintf("Failed to get space for vertices!\n");
915 return;
916 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000917 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
918 if (NULL == indexBuffer) {
919 GrPrintf("Failed to create index buffer!\n");
920 return;
921 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922
923 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
924
925 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
926 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
927 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
928 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
929
930 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
931 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
932 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
933 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
934
935 verts += sizeof(GrPoint);
936 for (int i = 0; i < 4; ++i) {
937 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
938 }
939
bsalomon@google.coma3108262011-10-10 14:08:47 +0000940 GrColor innerColor;
941 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000942 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000943 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000944 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000945 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000946 verts += 4 * vsize;
947 for (int i = 0; i < 8; ++i) {
948 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
949 }
950
951 verts += 8 * vsize;
952 for (int i = 0; i < 8; ++i) {
953 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
954 }
955
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000956 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000957 target->drawIndexed(kTriangles_PrimitiveType,
958 0, 0, 16, aaStrokeRectIndexCount());
959}
960
reed@google.com20efde72011-05-09 17:00:02 +0000961/**
962 * Returns true if the rects edges are integer-aligned.
963 */
964static bool isIRect(const GrRect& r) {
965 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
966 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
967}
968
bsalomon@google.com205d4602011-04-25 12:43:45 +0000969static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000970 const GrRect& rect,
971 GrScalar width,
972 const GrMatrix* matrix,
973 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000974 GrRect* devRect,
975 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000976 // we use a simple coverage ramp to do aa on axis-aligned rects
977 // we check if the rect will be axis-aligned, and the rect won't land on
978 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000979
bsalomon@google.coma3108262011-10-10 14:08:47 +0000980 // we are keeping around the "tweak the alpha" trick because
981 // it is our only hope for the fixed-pipe implementation.
982 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000983 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000984 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000985 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000986 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000987#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000988 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000989#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000990 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000991 } else {
992 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000993 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000994 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000995 const GrDrawState& drawState = target->getDrawState();
996 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000997 return false;
998 }
999
bsalomon@google.com471d4712011-08-23 15:45:25 +00001000 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001001 return false;
1002 }
1003
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001004 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001005 return false;
1006 }
1007
1008 if (NULL != matrix &&
1009 !matrix->preservesAxisAlignment()) {
1010 return false;
1011 }
1012
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001013 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001014 if (NULL != matrix) {
1015 combinedMatrix->preConcat(*matrix);
1016 GrAssert(combinedMatrix->preservesAxisAlignment());
1017 }
1018
1019 combinedMatrix->mapRect(devRect, rect);
1020 devRect->sort();
1021
1022 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001023 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001024 } else {
1025 return true;
1026 }
1027}
1028
bsalomon@google.com27847de2011-02-22 20:59:41 +00001029void GrContext::drawRect(const GrPaint& paint,
1030 const GrRect& rect,
1031 GrScalar width,
1032 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001033 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001034
1035 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001036 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001037
bsalomon@google.com205d4602011-04-25 12:43:45 +00001038 GrRect devRect = rect;
1039 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001040 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001041 bool needAA = paint.fAntiAlias &&
1042 !this->getRenderTarget()->isMultisampled();
1043 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1044 &combinedMatrix, &devRect,
1045 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001046
1047 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001048 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001049 if (width >= 0) {
1050 GrVec strokeSize;;
1051 if (width > 0) {
1052 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001053 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054 strokeSize.setAbs(strokeSize);
1055 } else {
1056 strokeSize.set(GR_Scalar1, GR_Scalar1);
1057 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001060 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061 }
1062 return;
1063 }
1064
bsalomon@google.com27847de2011-02-22 20:59:41 +00001065 if (width >= 0) {
1066 // TODO: consider making static vertex buffers for these cases.
1067 // Hairline could be done by just adding closing vertex to
1068 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001069 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1070
bsalomon@google.com27847de2011-02-22 20:59:41 +00001071 static const int worstCaseVertCount = 10;
1072 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1073
1074 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001075 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001076 return;
1077 }
1078
1079 GrPrimitiveType primType;
1080 int vertCount;
1081 GrPoint* vertex = geo.positions();
1082
1083 if (width > 0) {
1084 vertCount = 10;
1085 primType = kTriangleStrip_PrimitiveType;
1086 setStrokeRectStrip(vertex, rect, width);
1087 } else {
1088 // hairline
1089 vertCount = 5;
1090 primType = kLineStrip_PrimitiveType;
1091 vertex[0].set(rect.fLeft, rect.fTop);
1092 vertex[1].set(rect.fRight, rect.fTop);
1093 vertex[2].set(rect.fRight, rect.fBottom);
1094 vertex[3].set(rect.fLeft, rect.fBottom);
1095 vertex[4].set(rect.fLeft, rect.fTop);
1096 }
1097
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001098 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001099 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001100 GrDrawState* drawState = target->drawState();
1101 avmr.set(drawState);
1102 drawState->preConcatViewMatrix(*matrix);
1103 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001104 }
1105
1106 target->drawNonIndexed(primType, 0, vertCount);
1107 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001108#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001109 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001110 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1111 if (NULL == sqVB) {
1112 GrPrintf("Failed to create static rect vb.\n");
1113 return;
1114 }
1115 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001116 GrDrawState* drawState = target->drawState();
1117 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001118 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001119 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001120 0, rect.height(), rect.fTop,
1121 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001122
1123 if (NULL != matrix) {
1124 m.postConcat(*matrix);
1125 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001126 drawState->preConcatViewMatrix(m);
1127 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001128
bsalomon@google.com27847de2011-02-22 20:59:41 +00001129 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001130#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001131 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001132#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001133 }
1134}
1135
1136void GrContext::drawRectToRect(const GrPaint& paint,
1137 const GrRect& dstRect,
1138 const GrRect& srcRect,
1139 const GrMatrix* dstMatrix,
1140 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001141 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001142
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001143 // srcRect refers to paint's first texture
1144 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001145 drawRect(paint, dstRect, -1, dstMatrix);
1146 return;
1147 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001148
bsalomon@google.com27847de2011-02-22 20:59:41 +00001149 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1150
1151#if GR_STATIC_RECT_VB
1152 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001153 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001154 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001155 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001156
1157 GrMatrix m;
1158
1159 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1160 0, dstRect.height(), dstRect.fTop,
1161 0, 0, GrMatrix::I()[8]);
1162 if (NULL != dstMatrix) {
1163 m.postConcat(*dstMatrix);
1164 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001165 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001166
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001167 // srcRect refers to first stage
1168 int otherStageMask = paint.getActiveStageMask() &
1169 (~(1 << GrPaint::kFirstTextureStage));
1170 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001171 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001172 }
1173
bsalomon@google.com27847de2011-02-22 20:59:41 +00001174 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1175 0, srcRect.height(), srcRect.fTop,
1176 0, 0, GrMatrix::I()[8]);
1177 if (NULL != srcMatrix) {
1178 m.postConcat(*srcMatrix);
1179 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001180 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001181
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001182 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1183 if (NULL == sqVB) {
1184 GrPrintf("Failed to create static rect vb.\n");
1185 return;
1186 }
1187 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001188 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1189#else
1190
1191 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001192#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001194#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001195 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1196#endif
1197
tomhudson@google.com93813632011-10-27 20:21:16 +00001198 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1199 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001200 srcRects[0] = &srcRect;
1201 srcMatrices[0] = srcMatrix;
1202
1203 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1204#endif
1205}
1206
1207void GrContext::drawVertices(const GrPaint& paint,
1208 GrPrimitiveType primitiveType,
1209 int vertexCount,
1210 const GrPoint positions[],
1211 const GrPoint texCoords[],
1212 const GrColor colors[],
1213 const uint16_t indices[],
1214 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001215 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001216
1217 GrDrawTarget::AutoReleaseGeometry geo;
1218
1219 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1220
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001221 bool hasTexCoords[GrPaint::kTotalStages] = {
1222 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1223 0 // remaining stages use positions
1224 };
1225
1226 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227
1228 if (NULL != colors) {
1229 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001230 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001231 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001232
1233 if (sizeof(GrPoint) != vertexSize) {
1234 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001235 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001236 return;
1237 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001238 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001239 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001240 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1241 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001242 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001243 NULL,
1244 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001245 void* curVertex = geo.vertices();
1246
1247 for (int i = 0; i < vertexCount; ++i) {
1248 *((GrPoint*)curVertex) = positions[i];
1249
1250 if (texOffsets[0] > 0) {
1251 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1252 }
1253 if (colorOffset > 0) {
1254 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1255 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001256 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001257 }
1258 } else {
1259 target->setVertexSourceToArray(layout, positions, vertexCount);
1260 }
1261
bsalomon@google.com91958362011-06-13 17:58:13 +00001262 // we don't currently apply offscreen AA to this path. Need improved
1263 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001264
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001265 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001266 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001267 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001268 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001269 target->drawNonIndexed(primitiveType, 0, vertexCount);
1270 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001271}
1272
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001273///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001274#include "SkDraw.h"
1275#include "SkRasterClip.h"
1276
1277namespace {
1278
1279SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1280 switch (fill) {
1281 case kWinding_PathFill:
1282 return SkPath::kWinding_FillType;
1283 case kEvenOdd_PathFill:
1284 return SkPath::kEvenOdd_FillType;
1285 case kInverseWinding_PathFill:
1286 return SkPath::kInverseWinding_FillType;
1287 case kInverseEvenOdd_PathFill:
1288 return SkPath::kInverseEvenOdd_FillType;
1289 default:
1290 GrCrash("Unexpected fill.");
1291 return SkPath::kWinding_FillType;
1292 }
1293}
1294
1295// gets device coord bounds of path (not considering the fill) and clip. The
1296// path bounds will be a subset of the clip bounds. returns false if path bounds
1297// would be empty.
1298bool get_path_and_clip_bounds(const GrDrawTarget* target,
1299 const GrPath& path,
1300 const GrVec* translate,
1301 GrIRect* pathBounds,
1302 GrIRect* clipBounds) {
1303 // compute bounds as intersection of rt size, clip, and path
1304 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1305 if (NULL == rt) {
1306 return false;
1307 }
1308 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1309 const GrClip& clip = target->getClip();
1310 if (clip.hasConservativeBounds()) {
1311 clip.getConservativeBounds().roundOut(clipBounds);
1312 if (!pathBounds->intersect(*clipBounds)) {
1313 return false;
1314 }
1315 } else {
1316 // pathBounds is currently the rt extent, set clip bounds to that rect.
1317 *clipBounds = *pathBounds;
1318 }
1319 GrRect pathSBounds = path.getBounds();
1320 if (!pathSBounds.isEmpty()) {
1321 if (NULL != translate) {
1322 pathSBounds.offset(*translate);
1323 }
1324 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1325 pathSBounds);
1326 GrIRect pathIBounds;
1327 pathSBounds.roundOut(&pathIBounds);
1328 if (!pathBounds->intersect(pathIBounds)) {
1329 return false;
1330 }
1331 } else {
1332 return false;
1333 }
1334 return true;
1335}
1336
1337/**
1338 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1339 * scratch texture.
1340 */
1341
1342bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1343 const GrIRect& pathDevBounds,
1344 GrPathFill fill,
1345 GrContext* context,
1346 const GrPoint* translate,
1347 GrAutoScratchTexture* tex) {
1348 SkPaint paint;
1349 SkPath tmpPath;
1350 const SkPath* pathToDraw = &clientPath;
1351 if (kHairLine_PathFill == fill) {
1352 paint.setStyle(SkPaint::kStroke_Style);
1353 paint.setStrokeWidth(SK_Scalar1);
1354 } else {
1355 paint.setStyle(SkPaint::kFill_Style);
1356 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1357 if (skfill != pathToDraw->getFillType()) {
1358 tmpPath = *pathToDraw;
1359 tmpPath.setFillType(skfill);
1360 pathToDraw = &tmpPath;
1361 }
1362 }
1363 paint.setAntiAlias(true);
1364 paint.setColor(SK_ColorWHITE);
1365
1366 GrMatrix matrix = context->getMatrix();
1367 if (NULL != translate) {
1368 matrix.postTranslate(translate->fX, translate->fY);
1369 }
1370
1371 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1372 -pathDevBounds.fTop * SK_Scalar1);
1373 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1374 pathDevBounds.height());
1375
1376 SkBitmap bm;
1377 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1378 if (!bm.allocPixels()) {
1379 return false;
1380 }
1381 sk_bzero(bm.getPixels(), bm.getSafeSize());
1382
1383 SkDraw draw;
1384 sk_bzero(&draw, sizeof(draw));
1385 SkRasterClip rc(bounds);
1386 draw.fRC = &rc;
1387 draw.fClip = &rc.bwRgn();
1388 draw.fMatrix = &matrix;
1389 draw.fBitmap = &bm;
1390 draw.drawPath(*pathToDraw, paint);
1391
1392 const GrTextureDesc desc = {
1393 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001394 bounds.fRight,
1395 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001396 kAlpha_8_GrPixelConfig,
1397 {0} // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001398 };
1399
1400 tex->set(context, desc);
1401 GrTexture* texture = tex->texture();
1402
1403 if (NULL == texture) {
1404 return false;
1405 }
1406 SkAutoLockPixels alp(bm);
1407 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1408 bm.getPixels(), bm.rowBytes());
1409 return true;
1410}
1411
1412void draw_around_inv_path(GrDrawTarget* target,
1413 GrDrawState::StageMask stageMask,
1414 const GrIRect& clipBounds,
1415 const GrIRect& pathBounds) {
1416 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1417 GrRect rect;
1418 if (clipBounds.fTop < pathBounds.fTop) {
1419 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1420 clipBounds.fRight, pathBounds.fTop);
1421 target->drawSimpleRect(rect, NULL, stageMask);
1422 }
1423 if (clipBounds.fLeft < pathBounds.fLeft) {
1424 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1425 pathBounds.fLeft, pathBounds.fBottom);
1426 target->drawSimpleRect(rect, NULL, stageMask);
1427 }
1428 if (clipBounds.fRight > pathBounds.fRight) {
1429 rect.iset(pathBounds.fRight, pathBounds.fTop,
1430 clipBounds.fRight, pathBounds.fBottom);
1431 target->drawSimpleRect(rect, NULL, stageMask);
1432 }
1433 if (clipBounds.fBottom > pathBounds.fBottom) {
1434 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1435 clipBounds.fRight, clipBounds.fBottom);
1436 target->drawSimpleRect(rect, NULL, stageMask);
1437 }
1438}
1439
1440}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441
reed@google.com07f3ee12011-05-16 17:21:57 +00001442void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1443 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001444
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001445 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001446 if (GrIsFillInverted(fill)) {
1447 this->drawPaint(paint);
1448 }
1449 return;
1450 }
1451
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001452 // Note that below we may sw-rasterize the path into a scratch texture.
1453 // Scratch textures can be recycled after they are returned to the texture
1454 // cache. This presents a potential hazard for buffered drawing. However,
1455 // the writePixels that uploads to the scratch will perform a flush so we're
1456 // OK.
1457 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1458 kUnbuffered_DrawCategory;
1459 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001460 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001461
bsalomon@google.com289533a2011-10-27 12:34:25 +00001462 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1463
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001464 // An Assumption here is that path renderer would use some form of tweaking
1465 // the src color (either the input alpha or in the frag shader) to implement
1466 // aa. If we have some future driver-mojo path AA that can do the right
1467 // thing WRT to the blend then we'll need some query on the PR.
1468 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001469#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001470 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001471#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001472 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001473 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001474
bsalomon@google.com289533a2011-10-27 12:34:25 +00001475 GrPathRenderer* pr = NULL;
1476 if (prAA) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001477 pr = this->getPathRenderer(path, fill, target, true);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001478 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001479 GrAutoScratchTexture ast;
1480 GrIRect pathBounds, clipBounds;
1481 if (!get_path_and_clip_bounds(target, path, translate,
1482 &pathBounds, &clipBounds)) {
1483 return;
1484 }
bsalomon@google.com150d2842012-01-12 20:19:56 +00001485 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1486 fill, this,
1487 translate, &ast)) {
1488 GrTexture* texture = ast.texture();
1489 GrAssert(NULL != texture);
1490 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1491 enum {
1492 kPathMaskStage = GrPaint::kTotalStages,
1493 };
1494 target->drawState()->setTexture(kPathMaskStage, texture);
1495 target->drawState()->sampler(kPathMaskStage)->reset();
1496 GrScalar w = GrIntToScalar(pathBounds.width());
1497 GrScalar h = GrIntToScalar(pathBounds.height());
1498 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1499 h / texture->height());
1500 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1501 srcRects[kPathMaskStage] = &maskRect;
1502 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001503 GrRect dstRect = GrRect::MakeLTRB(
1504 SK_Scalar1* pathBounds.fLeft,
1505 SK_Scalar1* pathBounds.fTop,
1506 SK_Scalar1* pathBounds.fRight,
1507 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001508 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1509 target->drawState()->setTexture(kPathMaskStage, NULL);
1510 if (GrIsFillInverted(fill)) {
1511 draw_around_inv_path(target, stageMask,
1512 clipBounds, pathBounds);
1513 }
1514 return;
1515 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001516 }
1517 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001518 pr = this->getPathRenderer(path, fill, target, false);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001519 }
1520
bsalomon@google.com30085192011-08-19 15:42:31 +00001521 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001522#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001523 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001524#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001525 return;
1526 }
1527
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001528 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001529}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001530
bsalomon@google.com27847de2011-02-22 20:59:41 +00001531////////////////////////////////////////////////////////////////////////////////
1532
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001533void GrContext::flush(int flagsBitfield) {
1534 if (kDiscard_FlushBit & flagsBitfield) {
1535 fDrawBuffer->reset();
1536 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001537 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001538 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001539 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001540 fGpu->forceRenderTargetFlush();
1541 }
1542}
1543
1544void GrContext::flushText() {
1545 if (kText_DrawCategory == fLastDrawCategory) {
1546 flushDrawBuffer();
1547 }
1548}
1549
1550void GrContext::flushDrawBuffer() {
1551#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001552 if (fDrawBuffer) {
bsalomon@google.com97805382012-03-13 14:32:07 +00001553 fDrawBuffer->flushTo(fGpu);
junov@google.com53a55842011-06-08 22:55:10 +00001554 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001555#endif
1556}
1557
bsalomon@google.com6f379512011-11-16 20:36:03 +00001558void GrContext::internalWriteTexturePixels(GrTexture* texture,
1559 int left, int top,
1560 int width, int height,
1561 GrPixelConfig config,
1562 const void* buffer,
1563 size_t rowBytes,
1564 uint32_t flags) {
1565 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001566 ASSERT_OWNED_RESOURCE(texture);
1567
bsalomon@google.com6f379512011-11-16 20:36:03 +00001568 if (!(kDontFlush_PixelOpsFlag & flags)) {
1569 this->flush();
1570 }
1571 // TODO: use scratch texture to perform conversion
1572 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1573 GrPixelConfigIsUnpremultiplied(config)) {
1574 return;
1575 }
1576
1577 fGpu->writeTexturePixels(texture, left, top, width, height,
1578 config, buffer, rowBytes);
1579}
1580
1581bool GrContext::internalReadTexturePixels(GrTexture* texture,
1582 int left, int top,
1583 int width, int height,
1584 GrPixelConfig config,
1585 void* buffer,
1586 size_t rowBytes,
1587 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001588 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001589 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001590
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001591 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001592 GrRenderTarget* target = texture->asRenderTarget();
1593 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001594 return this->internalReadRenderTargetPixels(target,
1595 left, top, width, height,
1596 config, buffer, rowBytes,
1597 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001598 } else {
1599 return false;
1600 }
1601}
1602
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001603#include "SkConfig8888.h"
1604
1605namespace {
1606/**
1607 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1608 * formats are representable as Config8888 and so the function returns false
1609 * if the GrPixelConfig has no equivalent Config8888.
1610 */
1611bool grconfig_to_config8888(GrPixelConfig config,
1612 SkCanvas::Config8888* config8888) {
1613 switch (config) {
1614 case kRGBA_8888_PM_GrPixelConfig:
1615 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1616 return true;
1617 case kRGBA_8888_UPM_GrPixelConfig:
1618 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1619 return true;
1620 case kBGRA_8888_PM_GrPixelConfig:
1621 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1622 return true;
1623 case kBGRA_8888_UPM_GrPixelConfig:
1624 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1625 return true;
1626 default:
1627 return false;
1628 }
1629}
1630}
1631
bsalomon@google.com6f379512011-11-16 20:36:03 +00001632bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1633 int left, int top,
1634 int width, int height,
1635 GrPixelConfig config,
1636 void* buffer,
1637 size_t rowBytes,
1638 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001639 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001640 ASSERT_OWNED_RESOURCE(target);
1641
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001642 if (NULL == target) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001643 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001644 if (NULL == target) {
1645 return false;
1646 }
1647 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001648
bsalomon@google.com6f379512011-11-16 20:36:03 +00001649 if (!(kDontFlush_PixelOpsFlag & flags)) {
1650 this->flush();
1651 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001652
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001653 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1654 GrPixelConfigIsUnpremultiplied(config) &&
1655 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1656 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1657 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1658 !grconfig_to_config8888(config, &dstConfig8888)) {
1659 return false;
1660 }
1661 // do read back using target's own config
1662 this->internalReadRenderTargetPixels(target,
1663 left, top,
1664 width, height,
1665 target->config(),
1666 buffer, rowBytes,
1667 kDontFlush_PixelOpsFlag);
1668 // sw convert the pixels to unpremul config
1669 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1670 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1671 pixels, rowBytes, srcConfig8888,
1672 width, height);
1673 return true;
1674 }
1675
bsalomon@google.comc4364992011-11-07 15:54:49 +00001676 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001677 bool swapRAndB = NULL != src &&
1678 fGpu->preferredReadPixelsConfig(config) ==
1679 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001680
1681 bool flipY = NULL != src &&
1682 fGpu->readPixelsWillPayForYFlip(target, left, top,
1683 width, height, config,
1684 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001685 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1686 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001687
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001688 if (NULL == src && alphaConversion) {
1689 // we should fallback to cpu conversion here. This could happen when
1690 // we were given an external render target by the client that is not
1691 // also a texture (e.g. FBO 0 in GL)
1692 return false;
1693 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001694 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001695 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001696 if (flipY || swapRAndB || alphaConversion) {
1697 GrAssert(NULL != src);
1698 if (swapRAndB) {
1699 config = GrPixelConfigSwapRAndB(config);
1700 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001701 }
1702 // Make the scratch a render target because we don't have a robust
1703 // readTexturePixels as of yet (it calls this function).
1704 const GrTextureDesc desc = {
1705 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001706 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001707 config,
1708 {0}, // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001709 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001710
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001711 // When a full readback is faster than a partial we could always make
1712 // the scratch exactly match the passed rect. However, if we see many
1713 // different size rectangles we will trash our texture cache and pay the
1714 // cost of creating and destroying many textures. So, we only request
1715 // an exact match when the caller is reading an entire RT.
1716 ScratchTexMatch match = kApprox_ScratchTexMatch;
1717 if (0 == left &&
1718 0 == top &&
1719 target->width() == width &&
1720 target->height() == height &&
1721 fGpu->fullReadPixelsIsFasterThanPartial()) {
1722 match = kExact_ScratchTexMatch;
1723 }
1724 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001725 GrTexture* texture = ast.texture();
1726 if (!texture) {
1727 return false;
1728 }
1729 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001730 GrAssert(NULL != target);
1731
1732 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001733 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001734 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001735 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001736
bsalomon@google.comc4364992011-11-07 15:54:49 +00001737 GrMatrix matrix;
1738 if (flipY) {
1739 matrix.setTranslate(SK_Scalar1 * left,
1740 SK_Scalar1 * (top + height));
1741 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1742 } else {
1743 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1744 }
1745 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001746 drawState->sampler(0)->reset(matrix);
1747 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001748 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001749 GrRect rect;
1750 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1751 fGpu->drawSimpleRect(rect, NULL, 0x1);
1752 left = 0;
1753 top = 0;
1754 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001755 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001756 left, top, width, height,
1757 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001758}
1759
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001760void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1761 GrAssert(target);
1762 ASSERT_OWNED_RESOURCE(target);
1763 // In the future we may track whether there are any pending draws to this
1764 // target. We don't today so we always perform a flush. We don't promise
1765 // this to our clients, though.
1766 this->flush();
1767 fGpu->resolveRenderTarget(target);
1768}
1769
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001770void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1771 if (NULL == src || NULL == dst) {
1772 return;
1773 }
1774 ASSERT_OWNED_RESOURCE(src);
1775
1776 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001777 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001778 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001779 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001780 GrMatrix sampleM;
1781 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001782 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001783 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001784 SkRect rect = SkRect::MakeXYWH(0, 0,
1785 SK_Scalar1 * src->width(),
1786 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001787 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1788}
1789
bsalomon@google.com6f379512011-11-16 20:36:03 +00001790void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1791 int left, int top,
1792 int width, int height,
1793 GrPixelConfig config,
1794 const void* buffer,
1795 size_t rowBytes,
1796 uint32_t flags) {
1797 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001798 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001799
1800 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001801 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001802 if (NULL == target) {
1803 return;
1804 }
1805 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001806
1807 // TODO: when underlying api has a direct way to do this we should use it
1808 // (e.g. glDrawPixels on desktop GL).
1809
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001810 // If the RT is also a texture and we don't have to do PM/UPM conversion
1811 // then take the texture path, which we expect to be at least as fast or
1812 // faster since it doesn't use an intermediate texture as we do below.
1813
1814#if !GR_MAC_BUILD
1815 // At least some drivers on the Mac get confused when glTexImage2D is called
1816 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1817 // determine what OS versions and/or HW is affected.
1818 if (NULL != target->asTexture() &&
1819 GrPixelConfigIsUnpremultiplied(target->config()) ==
1820 GrPixelConfigIsUnpremultiplied(config)) {
1821
1822 this->internalWriteTexturePixels(target->asTexture(),
1823 left, top, width, height,
1824 config, buffer, rowBytes, flags);
1825 return;
1826 }
1827#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001828 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1829 GrPixelConfigIsUnpremultiplied(config) &&
1830 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1831 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1832 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1833 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1834 return;
1835 }
1836 // allocate a tmp buffer and sw convert the pixels to premul
1837 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1838 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1839 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1840 src, rowBytes, srcConfig8888,
1841 width, height);
1842 // upload the already premul pixels
1843 this->internalWriteRenderTargetPixels(target,
1844 left, top,
1845 width, height,
1846 target->config(),
1847 tmpPixels, 4 * width, flags);
1848 return;
1849 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001850
1851 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1852 GrPixelConfigSwapRAndB(config);
1853 if (swapRAndB) {
1854 config = GrPixelConfigSwapRAndB(config);
1855 }
1856
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001857 const GrTextureDesc desc = {
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001858 kNone_GrTextureFlags, width, height, config, {0}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001859 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001860 GrAutoScratchTexture ast(this, desc);
1861 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001862 if (NULL == texture) {
1863 return;
1864 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001865 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1866 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001867
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001869 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001870 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871
1872 GrMatrix matrix;
1873 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001874 drawState->setViewMatrix(matrix);
1875 drawState->setRenderTarget(target);
1876 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001877
bsalomon@google.com5c638652011-07-18 19:31:59 +00001878 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001879 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1880 GrSamplerState::kNearest_Filter,
1881 matrix);
1882 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001883
1884 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1885 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001886 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001887 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1888 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001889 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001890 return;
1891 }
1892 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1893 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1894}
1895////////////////////////////////////////////////////////////////////////////////
1896
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001897void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001898
1899 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1900 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001901 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001902 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001903 if (paint.getTexture(i)) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001904 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001905 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001906 }
1907
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001908 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001909
1910 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1911 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001912 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001913 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001914 if (paint.getMask(i)) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001915 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001916 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001917 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001918
1919 // disable all stages not accessible via the paint
1920 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001921 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001922 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001923
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001924 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001925
1926 if (paint.fDither) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001927 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001928 } else {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001929 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001930 }
1931 if (paint.fAntiAlias) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001932 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001933 } else {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001934 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001935 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001936 if (paint.fColorMatrixEnabled) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001937 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1938 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001939 } else {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001940 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001941 }
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001942 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1943 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1944 fDrawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001945
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001946#if GR_DEBUG
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001947 if ((paint.getActiveMaskStageMask() || 0xffffffff != paint.fCoverage) &&
1948 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001949 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1950 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001951#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001952}
1953
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001954GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001955 DrawCategory category) {
1956 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001957 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001958 fLastDrawCategory = category;
1959 }
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001960 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001961 GrDrawTarget* target = fGpu;
1962 switch (category) {
1963 case kText_DrawCategory:
1964#if DEFER_TEXT_RENDERING
1965 target = fDrawBuffer;
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001966 fDrawBuffer->setClip(fGpu->getClip());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001967#else
1968 target = fGpu;
1969#endif
1970 break;
1971 case kUnbuffered_DrawCategory:
1972 target = fGpu;
1973 break;
1974 case kBuffered_DrawCategory:
1975 target = fDrawBuffer;
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001976 fDrawBuffer->setClip(fGpu->getClip());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001977 break;
1978 }
1979 return target;
1980}
1981
bsalomon@google.com289533a2011-10-27 12:34:25 +00001982GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1983 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001984 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001985 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001986 if (NULL == fPathRendererChain) {
1987 fPathRendererChain =
1988 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1989 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001990 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001991}
1992
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993////////////////////////////////////////////////////////////////////////////////
1994
bsalomon@google.com27847de2011-02-22 20:59:41 +00001995void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001996 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001997 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001998 this->flush(false);
bsalomon@google.coma5d22032012-03-27 17:40:15 +00001999 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002000 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001}
2002
2003GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002004 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005}
2006
2007const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002008 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002009}
2010
2011const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002012 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002013}
2014
2015void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002016 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002017}
2018
2019void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002020 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002021}
2022
2023static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2024 intptr_t mask = 1 << shift;
2025 if (pred) {
2026 bits |= mask;
2027 } else {
2028 bits &= ~mask;
2029 }
2030 return bits;
2031}
2032
2033void GrContext::resetStats() {
2034 fGpu->resetStats();
2035}
2036
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002037const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002038 return fGpu->getStats();
2039}
2040
2041void GrContext::printStats() const {
2042 fGpu->printStats();
2043}
2044
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002045GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002046 fGpu = gpu;
2047 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002048 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002049
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002050 fDrawState = new GrDrawState();
2051 fGpu->setDrawState(fDrawState);
2052
bsalomon@google.com30085192011-08-19 15:42:31 +00002053 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002054
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002055 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2056 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002057 fFontCache = new GrFontCache(fGpu);
2058
2059 fLastDrawCategory = kUnbuffered_DrawCategory;
2060
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002061 fDrawBuffer = NULL;
2062 fDrawBufferVBAllocPool = NULL;
2063 fDrawBufferIBAllocPool = NULL;
2064
bsalomon@google.com205d4602011-04-25 12:43:45 +00002065 fAAFillRectIndexBuffer = NULL;
2066 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002067
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002068 this->setupDrawBuffer();
2069}
2070
2071void GrContext::setupDrawBuffer() {
2072
2073 GrAssert(NULL == fDrawBuffer);
2074 GrAssert(NULL == fDrawBufferVBAllocPool);
2075 GrAssert(NULL == fDrawBufferIBAllocPool);
2076
bsalomon@google.com27847de2011-02-22 20:59:41 +00002077#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002078 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002079 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002080 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2081 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002082 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002083 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002084 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002085 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2086
bsalomon@google.com471d4712011-08-23 15:45:25 +00002087 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2088 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002089 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002090#endif
2091
2092#if BATCH_RECT_TO_RECT
2093 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2094#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002095 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002096 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002097}
2098
bsalomon@google.com27847de2011-02-22 20:59:41 +00002099GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002100#if DEFER_TEXT_RENDERING
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002101 return prepareToDraw(paint, kText_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002102#else
bsalomon@google.coma5d22032012-03-27 17:40:15 +00002103 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002104#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002105}
2106
2107const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2108 return fGpu->getQuadIndexBuffer();
2109}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002110
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002111GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2112 GrAutoScratchTexture* temp1,
2113 GrAutoScratchTexture* temp2,
2114 const SkRect& rect,
2115 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002116 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002117 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2118 GrClip oldClip = this->getClip();
2119 GrTexture* origTexture = srcTexture;
2120 GrAutoMatrix avm(this, GrMatrix::I());
2121 SkIRect clearRect;
2122 int scaleFactorX, halfWidthX, kernelWidthX;
2123 int scaleFactorY, halfWidthY, kernelWidthY;
2124 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2125 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002126
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002127 SkRect srcRect(rect);
2128 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2129 srcRect.roundOut();
2130 scale_rect(&srcRect, scaleFactorX, scaleFactorY);
2131 this->setClip(srcRect);
2132
2133 const GrTextureDesc desc = {
2134 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002135 SkScalarFloorToInt(srcRect.width()),
2136 SkScalarFloorToInt(srcRect.height()),
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002137 kRGBA_8888_GrPixelConfig,
2138 {0} // samples
2139 };
2140
2141 temp1->set(this, desc);
2142 if (temp2) temp2->set(this, desc);
2143
2144 GrTexture* dstTexture = temp1->texture();
2145 GrPaint paint;
2146 paint.reset();
2147 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2148
2149 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2150 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2151 srcTexture->height());
2152 this->setRenderTarget(dstTexture->asRenderTarget());
2153 SkRect dstRect(srcRect);
2154 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2155 i < scaleFactorY ? 0.5f : 1.0f);
2156 paint.setTexture(0, srcTexture);
2157 this->drawRectToRect(paint, dstRect, srcRect);
2158 srcRect = dstRect;
2159 SkTSwap(srcTexture, dstTexture);
2160 // If temp2 is non-NULL, don't render back to origTexture
2161 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2162 }
2163
2164 if (sigmaX > 0.0f) {
2165 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2166 float* kernelX = kernelStorageX.get();
2167 build_kernel(sigmaX, kernelX, kernelWidthX);
2168
2169 if (scaleFactorX > 1) {
2170 // Clear out a halfWidth to the right of the srcRect to prevent the
2171 // X convolution from reading garbage.
2172 clearRect = SkIRect::MakeXYWH(
2173 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2174 this->clear(&clearRect, 0x0);
2175 }
2176
2177 this->setRenderTarget(dstTexture->asRenderTarget());
2178 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2179 GrSamplerState::kX_FilterDirection);
2180 SkTSwap(srcTexture, dstTexture);
2181 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2182 }
2183
2184 if (sigmaY > 0.0f) {
2185 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2186 float* kernelY = kernelStorageY.get();
2187 build_kernel(sigmaY, kernelY, kernelWidthY);
2188
2189 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2190 // Clear out a halfWidth below the srcRect to prevent the Y
2191 // convolution from reading garbage.
2192 clearRect = SkIRect::MakeXYWH(
2193 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2194 this->clear(&clearRect, 0x0);
2195 }
2196
2197 this->setRenderTarget(dstTexture->asRenderTarget());
2198 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2199 GrSamplerState::kY_FilterDirection);
2200 SkTSwap(srcTexture, dstTexture);
2201 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2202 }
2203
2204 if (scaleFactorX > 1 || scaleFactorY > 1) {
2205 // Clear one pixel to the right and below, to accommodate bilinear
2206 // upsampling.
2207 clearRect = SkIRect::MakeXYWH(
2208 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2209 this->clear(&clearRect, 0x0);
2210 clearRect = SkIRect::MakeXYWH(
2211 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2212 this->clear(&clearRect, 0x0);
2213 // FIXME: This should be mitchell, not bilinear.
2214 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2215 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2216 srcTexture->height());
2217 this->setRenderTarget(dstTexture->asRenderTarget());
2218 paint.setTexture(0, srcTexture);
2219 SkRect dstRect(srcRect);
2220 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2221 this->drawRectToRect(paint, dstRect, srcRect);
2222 srcRect = dstRect;
2223 SkTSwap(srcTexture, dstTexture);
2224 }
2225 this->setRenderTarget(oldRenderTarget);
2226 this->setClip(oldClip);
2227 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002228}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002229
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002230GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2231 const GrRect& rect,
2232 GrTexture* temp1, GrTexture* temp2,
2233 GrSamplerState::Filter filter,
2234 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002235 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002236 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2237 GrAutoMatrix avm(this, GrMatrix::I());
2238 GrClip oldClip = this->getClip();
2239 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2240 if (radius.fWidth > 0) {
2241 this->setRenderTarget(temp1->asRenderTarget());
2242 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2243 GrSamplerState::kX_FilterDirection);
2244 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2245 rect.width(), radius.fHeight);
2246 this->clear(&clearRect, 0x0);
2247 srcTexture = temp1;
2248 }
2249 if (radius.fHeight > 0) {
2250 this->setRenderTarget(temp2->asRenderTarget());
2251 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2252 GrSamplerState::kY_FilterDirection);
2253 srcTexture = temp2;
2254 }
2255 this->setRenderTarget(oldRenderTarget);
2256 this->setClip(oldClip);
2257 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002258}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002259
2260///////////////////////////////////////////////////////////////////////////////