blob: 58f84404fa9d3f348347fbd475194ae943e0df0b [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
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000025#define DEFER_TEXT_RENDERING 1
bsalomon@google.com27847de2011-02-22 20:59:41 +000026
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000027#define DEFER_PATHS 1
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000028
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000029#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
bsalomon@google.com27847de2011-02-22 20:59:41 +000030
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000031#define MAX_BLUR_SIGMA 4.0f
32
bsalomon@google.comd46e2422011-09-23 17:40:07 +000033// When we're using coverage AA but the blend is incompatible (given gpu
34// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000035#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000036
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000037static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000039
bsalomon@google.com60361492012-03-15 17:47:06 +000040static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000041static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000043// path rendering is the only thing we defer today that uses non-static indices
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000046
bsalomon@google.combc4b6542011-11-19 13:56:11 +000047#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
48
bsalomon@google.com05ef5102011-05-02 21:14:59 +000049GrContext* GrContext::Create(GrEngine engine,
50 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000051 GrContext* ctx = NULL;
52 GrGpu* fGpu = GrGpu::Create(engine, context3D);
53 if (NULL != fGpu) {
54 ctx = new GrContext(fGpu);
55 fGpu->unref();
56 }
57 return ctx;
58}
59
bsalomon@google.com27847de2011-02-22 20:59:41 +000060GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000061 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 delete fTextureCache;
63 delete fFontCache;
64 delete fDrawBuffer;
65 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000066 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000067
bsalomon@google.com205d4602011-04-25 12:43:45 +000068 GrSafeUnref(fAAFillRectIndexBuffer);
69 GrSafeUnref(fAAStrokeRectIndexBuffer);
70 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000071 GrSafeUnref(fPathRendererChain);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000072 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com30085192011-08-19 15:42:31 +000085 // a path renderer may be holding onto resources that
86 // are now unusable
87 GrSafeSetNull(fPathRendererChain);
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBuffer;
90 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferVBAllocPool;
93 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000094
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 delete fDrawBufferIBAllocPool;
96 fDrawBufferIBAllocPool = NULL;
97
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 GrSafeSetNull(fAAFillRectIndexBuffer);
99 GrSafeSetNull(fAAStrokeRectIndexBuffer);
100
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101 fTextureCache->removeAll();
102 fFontCache->freeAll();
103 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000104}
105
106void GrContext::resetContext() {
107 fGpu->markContextDirty();
108}
109
110void GrContext::freeGpuResources() {
111 this->flush();
112 fTextureCache->removeAll();
113 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000114 // a path renderer may be holding onto resources
115 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000116}
117
twiz@google.com05e70242012-01-27 19:12:00 +0000118size_t GrContext::getGpuTextureCacheBytes() const {
119 return fTextureCache->getCachedResourceBytes();
120}
121
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000122////////////////////////////////////////////////////////////////////////////////
123
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000124int GrContext::PaintStageVertexLayoutBits(
125 const GrPaint& paint,
126 const bool hasTexCoords[GrPaint::kTotalStages]) {
127 int stageMask = paint.getActiveStageMask();
128 int layout = 0;
129 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
130 if ((1 << i) & stageMask) {
131 if (NULL != hasTexCoords && hasTexCoords[i]) {
132 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
133 } else {
134 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
135 }
136 }
137 }
138 return layout;
139}
140
141
142////////////////////////////////////////////////////////////////////////////////
143
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000144enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000145 // flags for textures
146 kNPOTBit = 0x1,
147 kFilterBit = 0x2,
148 kScratchBit = 0x4,
149
150 // resource type
151 kTextureBit = 0x8,
152 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000153};
154
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000155GrTexture* GrContext::TextureCacheEntry::texture() const {
156 if (NULL == fEntry) {
157 return NULL;
158 } else {
159 return (GrTexture*) fEntry->resource();
160 }
161}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000162
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163namespace {
164// returns true if this is a "special" texture because of gpu NPOT limitations
165bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000166 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000167 GrContext::TextureKey clientKey,
168 int width,
169 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000170 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000171 bool scratch,
172 uint32_t v[4]) {
173 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
174 // we assume we only need 16 bits of width and height
175 // assert that texture creation will fail anyway if this assumption
176 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000177 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000178 v[0] = clientKey & 0xffffffffUL;
179 v[1] = (clientKey >> 32) & 0xffffffffUL;
180 v[2] = width | (height << 16);
181
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000182 v[3] = (sampleCnt << 24);
183 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
184
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000185 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000186 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
187
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000188 bool tiled = NULL != sampler &&
189 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
190 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000191
192 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000194 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000195 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000196 }
197 }
198 }
199
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000200 if (scratch) {
201 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000202 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000203
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000204 v[3] |= kTextureBit;
205
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000206 return v[3] & kNPOTBit;
207}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000208
209// we should never have more than one stencil buffer with same combo of
210// (width,height,samplecount)
211void gen_stencil_key_values(int width, int height,
212 int sampleCnt, uint32_t v[4]) {
213 v[0] = width;
214 v[1] = height;
215 v[2] = sampleCnt;
216 v[3] = kStencilBufferBit;
217}
218
219void gen_stencil_key_values(const GrStencilBuffer* sb,
220 uint32_t v[4]) {
221 gen_stencil_key_values(sb->width(), sb->height(),
222 sb->numSamples(), v);
223}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000224
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000225void build_kernel(float sigma, float* kernel, int kernelWidth) {
226 int halfWidth = (kernelWidth - 1) / 2;
227 float sum = 0.0f;
228 float denom = 1.0f / (2.0f * sigma * sigma);
229 for (int i = 0; i < kernelWidth; ++i) {
230 float x = static_cast<float>(i - halfWidth);
231 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
232 // is dropped here, since we renormalize the kernel below.
233 kernel[i] = sk_float_exp(- x * x * denom);
234 sum += kernel[i];
235 }
236 // Normalize the kernel
237 float scale = 1.0f / sum;
238 for (int i = 0; i < kernelWidth; ++i)
239 kernel[i] *= scale;
240}
241
242void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000243 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
244 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
245 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
246 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000247}
248
249float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
250 int *kernelWidth) {
251 *scaleFactor = 1;
252 while (sigma > MAX_BLUR_SIGMA) {
253 *scaleFactor *= 2;
254 sigma *= 0.5f;
255 }
256 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
257 *kernelWidth = *halfWidth * 2 + 1;
258 return sigma;
259}
260
261void apply_morphology(GrGpu* gpu,
262 GrTexture* texture,
263 const SkRect& rect,
264 int radius,
265 GrSamplerState::Filter filter,
266 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000267 GrAssert(filter == GrSamplerState::kErode_Filter ||
268 filter == GrSamplerState::kDilate_Filter);
269
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000270 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
271 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000272 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000273 drawState->setRenderTarget(target);
274 GrMatrix sampleM;
275 sampleM.setIDiv(texture->width(), texture->height());
276 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
277 sampleM);
278 drawState->sampler(0)->setMorphologyRadius(radius);
279 drawState->sampler(0)->setFilterDirection(direction);
280 drawState->setTexture(0, texture);
281 gpu->drawSimpleRect(rect, NULL, 1 << 0);
282}
283
284void convolve(GrGpu* gpu,
285 GrTexture* texture,
286 const SkRect& rect,
287 const float* kernel,
288 int kernelWidth,
289 GrSamplerState::FilterDirection direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000290 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
291 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000292 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000293 drawState->setRenderTarget(target);
294 GrMatrix sampleM;
295 sampleM.setIDiv(texture->width(), texture->height());
296 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
297 GrSamplerState::kConvolution_Filter,
298 sampleM);
299 drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel);
300 drawState->sampler(0)->setFilterDirection(direction);
301 drawState->setTexture(0, texture);
302 gpu->drawSimpleRect(rect, NULL, 1 << 0);
303}
304
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000305}
306
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000307GrContext::TextureCacheEntry GrContext::findAndLockTexture(
308 TextureKey key,
309 int width,
310 int height,
311 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000312 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000313 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000314 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000315 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
316 GrResourceCache::kNested_LockType));
317}
318
bsalomon@google.comfb309512011-11-30 14:13:48 +0000319bool GrContext::isTextureInCache(TextureKey key,
320 int width,
321 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000322 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000323 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000324 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000325 GrResourceKey resourceKey(v);
326 return fTextureCache->hasKey(resourceKey);
327}
328
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000329GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000330 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000331 uint32_t v[4];
332 gen_stencil_key_values(sb, v);
333 GrResourceKey resourceKey(v);
334 return fTextureCache->createAndLock(resourceKey, sb);
335}
336
337GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
338 int sampleCnt) {
339 uint32_t v[4];
340 gen_stencil_key_values(width, height, sampleCnt, v);
341 GrResourceKey resourceKey(v);
342 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
343 GrResourceCache::kSingle_LockType);
344 if (NULL != entry) {
345 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
346 return sb;
347 } else {
348 return NULL;
349 }
350}
351
352void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000353 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000354 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000355}
356
357static void stretchImage(void* dst,
358 int dstW,
359 int dstH,
360 void* src,
361 int srcW,
362 int srcH,
363 int bpp) {
364 GrFixed dx = (srcW << 16) / dstW;
365 GrFixed dy = (srcH << 16) / dstH;
366
367 GrFixed y = dy >> 1;
368
369 int dstXLimit = dstW*bpp;
370 for (int j = 0; j < dstH; ++j) {
371 GrFixed x = dx >> 1;
372 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
373 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
374 for (int i = 0; i < dstXLimit; i += bpp) {
375 memcpy((uint8_t*) dstRow + i,
376 (uint8_t*) srcRow + (x>>16)*bpp,
377 bpp);
378 x += dx;
379 }
380 y += dy;
381 }
382}
383
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000384GrContext::TextureCacheEntry GrContext::createAndLockTexture(
385 TextureKey key,
386 const GrSamplerState* sampler,
387 const GrTextureDesc& desc,
388 void* srcData,
389 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000390 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391
392#if GR_DUMP_TEXTURE_UPLOAD
393 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
394#endif
395
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000396 TextureCacheEntry entry;
397 uint32_t v[4];
398 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000399 desc.fWidth, desc.fHeight,
400 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000401 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000404 GrAssert(NULL != sampler);
405 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
406 desc.fWidth,
407 desc.fHeight,
408 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000409
410 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000411 clampEntry = this->createAndLockTexture(key, NULL, desc,
412 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000413 GrAssert(NULL != clampEntry.texture());
414 if (NULL == clampEntry.texture()) {
415 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000416 }
417 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000418 GrTextureDesc rtDesc = desc;
419 rtDesc.fFlags = rtDesc.fFlags |
420 kRenderTarget_GrTextureFlagBit |
421 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000422 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
423 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000424
425 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
426
427 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000428 GrDrawTarget::AutoStateRestore asr(fGpu,
429 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000430 GrDrawState* drawState = fGpu->drawState();
431 drawState->setRenderTarget(texture->asRenderTarget());
432 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000433
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000434 GrSamplerState::Filter filter;
435 // if filtering is not desired then we want to ensure all
436 // texels in the resampled image are copies of texels from
437 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000438 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000439 filter = GrSamplerState::kNearest_Filter;
440 } else {
441 filter = GrSamplerState::kBilinear_Filter;
442 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000443 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
444 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000445
446 static const GrVertexLayout layout =
447 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
448 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
449
450 if (arg.succeeded()) {
451 GrPoint* verts = (GrPoint*) arg.vertices();
452 verts[0].setIRectFan(0, 0,
453 texture->width(),
454 texture->height(),
455 2*sizeof(GrPoint));
456 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
457 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
458 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000459 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000460 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000461 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000462 } else {
463 // TODO: Our CPU stretch doesn't filter. But we create separate
464 // stretched textures when the sampler state is either filtered or
465 // not. Either implement filtered stretch blit on CPU or just create
466 // one when FBO case fails.
467
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000468 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000469 // no longer need to clamp at min RT size.
470 rtDesc.fWidth = GrNextPow2(desc.fWidth);
471 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000472 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000473 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000474 rtDesc.fWidth *
475 rtDesc.fHeight);
476 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
477 srcData, desc.fWidth, desc.fHeight, bpp);
478
479 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
480
481 GrTexture* texture = fGpu->createTexture(rtDesc,
482 stretchedPixels.get(),
483 stretchedRowBytes);
484 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000486 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000487 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000488
489 } else {
490 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
491 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000493 }
494 }
495 return entry;
496}
497
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000498namespace {
499inline void gen_scratch_tex_key_values(const GrGpu* gpu,
500 const GrTextureDesc& desc,
501 uint32_t v[4]) {
502 // Instead of a client-provided key of the texture contents
503 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000504 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000505 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000506 // this code path isn't friendly to tiling with NPOT restricitons
507 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000508 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000509 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000510}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000511}
512
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513GrContext::TextureCacheEntry GrContext::lockScratchTexture(
514 const GrTextureDesc& inDesc,
515 ScratchTexMatch match) {
516
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000517 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 if (kExact_ScratchTexMatch != match) {
519 // bin by pow2 with a reasonable min
520 static const int MIN_SIZE = 256;
521 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
522 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
523 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000524
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000525 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000526 int origWidth = desc.fWidth;
527 int origHeight = desc.fHeight;
528 bool doubledW = false;
529 bool doubledH = false;
530
531 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000532 uint32_t v[4];
533 gen_scratch_tex_key_values(fGpu, desc, v);
534 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000535 entry = fTextureCache->findAndLock(key,
536 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000537 // if we miss, relax the fit of the flags...
538 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000539 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000540 break;
541 }
542 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
543 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
544 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
545 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
546 } else if (!doubledW) {
547 desc.fFlags = inDesc.fFlags;
548 desc.fWidth *= 2;
549 doubledW = true;
550 } else if (!doubledH) {
551 desc.fFlags = inDesc.fFlags;
552 desc.fWidth = origWidth;
553 desc.fHeight *= 2;
554 doubledH = true;
555 } else {
556 break;
557 }
558
559 } while (true);
560
561 if (NULL == entry) {
562 desc.fFlags = inDesc.fFlags;
563 desc.fWidth = origWidth;
564 desc.fHeight = origHeight;
565 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
566 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000567 uint32_t v[4];
568 gen_scratch_tex_key_values(fGpu, desc, v);
569 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000570 entry = fTextureCache->createAndLock(key, texture);
571 }
572 }
573
574 // If the caller gives us the same desc/sampler twice we don't want
575 // to return the same texture the second time (unless it was previously
576 // released). So we detach the entry from the cache and reattach at release.
577 if (NULL != entry) {
578 fTextureCache->detach(entry);
579 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000580 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000581}
582
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000583void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000584 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000585 // If this is a scratch texture we detached it from the cache
586 // while it was locked (to avoid two callers simultaneously getting
587 // the same texture).
588 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
589 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000590 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000591 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000592 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000593}
594
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000595GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596 void* srcData,
597 size_t rowBytes) {
598 return fGpu->createTexture(desc, srcData, rowBytes);
599}
600
601void GrContext::getTextureCacheLimits(int* maxTextures,
602 size_t* maxTextureBytes) const {
603 fTextureCache->getLimits(maxTextures, maxTextureBytes);
604}
605
606void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
607 fTextureCache->setLimits(maxTextures, maxTextureBytes);
608}
609
bsalomon@google.com91958362011-06-13 17:58:13 +0000610int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000611 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000612}
613
614int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000615 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000616}
617
618///////////////////////////////////////////////////////////////////////////////
619
bsalomon@google.come269f212011-11-07 13:29:52 +0000620GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
621 return fGpu->createPlatformTexture(desc);
622}
623
624GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
625 return fGpu->createPlatformRenderTarget(desc);
626}
627
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000628///////////////////////////////////////////////////////////////////////////////
629
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000630bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000631 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000632 const GrDrawTarget::Caps& caps = fGpu->getCaps();
633 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000634 return false;
635 }
636
bsalomon@google.com27847de2011-02-22 20:59:41 +0000637 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
638
639 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000640 bool tiled = NULL != sampler &&
641 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
642 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000643 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644 return false;
645 }
646 }
647 return true;
648}
649
650////////////////////////////////////////////////////////////////////////////////
651
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000652const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
653
bsalomon@google.com27847de2011-02-22 20:59:41 +0000654void GrContext::setClip(const GrClip& clip) {
655 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000656 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000657}
658
659void GrContext::setClip(const GrIRect& rect) {
660 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000661 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000662 fGpu->setClip(clip);
663}
664
665////////////////////////////////////////////////////////////////////////////////
666
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000667void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000668 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000669 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000670}
671
672void GrContext::drawPaint(const GrPaint& paint) {
673 // set rect to be big enough to fill the space, but not super-huge, so we
674 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000675 GrRect r;
676 r.setLTRB(0, 0,
677 GrIntToScalar(getRenderTarget()->width()),
678 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000679 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000680 SkTLazy<GrPaint> tmpPaint;
681 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000682 GrAutoMatrix am;
683
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000684 // We attempt to map r by the inverse matrix and draw that. mapRect will
685 // map the four corners and bound them with a new rect. This will not
686 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000687 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000688 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000689 GrPrintf("Could not invert matrix");
690 return;
691 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000692 inverse.mapRect(&r);
693 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000694 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000695 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000696 GrPrintf("Could not invert matrix");
697 return;
698 }
699 tmpPaint.set(paint);
700 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
701 p = tmpPaint.get();
702 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000703 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000704 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000705 // by definition this fills the entire clip, no need for AA
706 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000707 if (!tmpPaint.isValid()) {
708 tmpPaint.set(paint);
709 p = tmpPaint.get();
710 }
711 GrAssert(p == tmpPaint.get());
712 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000713 }
714 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000715}
716
bsalomon@google.com205d4602011-04-25 12:43:45 +0000717////////////////////////////////////////////////////////////////////////////////
718
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000719namespace {
720inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
721 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
722}
723}
724
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000725////////////////////////////////////////////////////////////////////////////////
726
bsalomon@google.com27847de2011-02-22 20:59:41 +0000727/* create a triangle strip that strokes the specified triangle. There are 8
728 unique vertices, but we repreat the last 2 to close up. Alternatively we
729 could use an indices array, and then only send 8 verts, but not sure that
730 would be faster.
731 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000732static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000733 GrScalar width) {
734 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000735 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000736
737 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
738 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
739 verts[2].set(rect.fRight - rad, rect.fTop + rad);
740 verts[3].set(rect.fRight + rad, rect.fTop - rad);
741 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
742 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
743 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
744 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
745 verts[8] = verts[0];
746 verts[9] = verts[1];
747}
748
bsalomon@google.com205d4602011-04-25 12:43:45 +0000749static void setInsetFan(GrPoint* pts, size_t stride,
750 const GrRect& r, GrScalar dx, GrScalar dy) {
751 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
752}
753
754static const uint16_t gFillAARectIdx[] = {
755 0, 1, 5, 5, 4, 0,
756 1, 2, 6, 6, 5, 1,
757 2, 3, 7, 7, 6, 2,
758 3, 0, 4, 4, 7, 3,
759 4, 5, 6, 6, 7, 4,
760};
761
762int GrContext::aaFillRectIndexCount() const {
763 return GR_ARRAY_COUNT(gFillAARectIdx);
764}
765
766GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
767 if (NULL == fAAFillRectIndexBuffer) {
768 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
769 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000770 if (NULL != fAAFillRectIndexBuffer) {
771 #if GR_DEBUG
772 bool updated =
773 #endif
774 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
775 sizeof(gFillAARectIdx));
776 GR_DEBUGASSERT(updated);
777 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000778 }
779 return fAAFillRectIndexBuffer;
780}
781
782static const uint16_t gStrokeAARectIdx[] = {
783 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
784 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
785 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
786 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
787
788 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
789 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
790 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
791 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
792
793 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
794 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
795 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
796 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
797};
798
799int GrContext::aaStrokeRectIndexCount() const {
800 return GR_ARRAY_COUNT(gStrokeAARectIdx);
801}
802
803GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
804 if (NULL == fAAStrokeRectIndexBuffer) {
805 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
806 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000807 if (NULL != fAAStrokeRectIndexBuffer) {
808 #if GR_DEBUG
809 bool updated =
810 #endif
811 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
812 sizeof(gStrokeAARectIdx));
813 GR_DEBUGASSERT(updated);
814 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000815 }
816 return fAAStrokeRectIndexBuffer;
817}
818
bsalomon@google.coma3108262011-10-10 14:08:47 +0000819static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
820 bool useCoverage) {
821 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000822 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000823 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000824 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
825 }
826 }
827 if (useCoverage) {
828 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
829 } else {
830 layout |= GrDrawTarget::kColor_VertexLayoutBit;
831 }
832 return layout;
833}
834
bsalomon@google.com205d4602011-04-25 12:43:45 +0000835void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000836 const GrRect& devRect,
837 bool useVertexCoverage) {
838 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000839
840 size_t vsize = GrDrawTarget::VertexSize(layout);
841
842 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000843 if (!geo.succeeded()) {
844 GrPrintf("Failed to get space for vertices!\n");
845 return;
846 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000847 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
848 if (NULL == indexBuffer) {
849 GrPrintf("Failed to create index buffer!\n");
850 return;
851 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000852
853 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
854
855 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
856 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
857
858 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
859 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
860
861 verts += sizeof(GrPoint);
862 for (int i = 0; i < 4; ++i) {
863 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
864 }
865
bsalomon@google.coma3108262011-10-10 14:08:47 +0000866 GrColor innerColor;
867 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000868 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000869 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000870 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000871 }
872
bsalomon@google.com205d4602011-04-25 12:43:45 +0000873 verts += 4 * vsize;
874 for (int i = 0; i < 4; ++i) {
875 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
876 }
877
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000878 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000879
880 target->drawIndexed(kTriangles_PrimitiveType, 0,
881 0, 8, this->aaFillRectIndexCount());
882}
883
bsalomon@google.coma3108262011-10-10 14:08:47 +0000884void GrContext::strokeAARect(GrDrawTarget* target,
885 const GrRect& devRect,
886 const GrVec& devStrokeSize,
887 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000888 const GrScalar& dx = devStrokeSize.fX;
889 const GrScalar& dy = devStrokeSize.fY;
890 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
891 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
892
bsalomon@google.com205d4602011-04-25 12:43:45 +0000893 GrScalar spare;
894 {
895 GrScalar w = devRect.width() - dx;
896 GrScalar h = devRect.height() - dy;
897 spare = GrMin(w, h);
898 }
899
900 if (spare <= 0) {
901 GrRect r(devRect);
902 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000903 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000904 return;
905 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000906 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000907 size_t vsize = GrDrawTarget::VertexSize(layout);
908
909 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000910 if (!geo.succeeded()) {
911 GrPrintf("Failed to get space for vertices!\n");
912 return;
913 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000914 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
915 if (NULL == indexBuffer) {
916 GrPrintf("Failed to create index buffer!\n");
917 return;
918 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000919
920 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
921
922 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
923 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
924 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
925 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
926
927 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
928 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
929 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
930 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
931
932 verts += sizeof(GrPoint);
933 for (int i = 0; i < 4; ++i) {
934 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
935 }
936
bsalomon@google.coma3108262011-10-10 14:08:47 +0000937 GrColor innerColor;
938 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000939 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000940 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000941 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000942 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000943 verts += 4 * vsize;
944 for (int i = 0; i < 8; ++i) {
945 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
946 }
947
948 verts += 8 * vsize;
949 for (int i = 0; i < 8; ++i) {
950 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
951 }
952
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000953 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000954 target->drawIndexed(kTriangles_PrimitiveType,
955 0, 0, 16, aaStrokeRectIndexCount());
956}
957
reed@google.com20efde72011-05-09 17:00:02 +0000958/**
959 * Returns true if the rects edges are integer-aligned.
960 */
961static bool isIRect(const GrRect& r) {
962 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
963 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
964}
965
bsalomon@google.com205d4602011-04-25 12:43:45 +0000966static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000967 const GrRect& rect,
968 GrScalar width,
969 const GrMatrix* matrix,
970 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000971 GrRect* devRect,
972 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000973 // we use a simple coverage ramp to do aa on axis-aligned rects
974 // we check if the rect will be axis-aligned, and the rect won't land on
975 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000976
bsalomon@google.coma3108262011-10-10 14:08:47 +0000977 // we are keeping around the "tweak the alpha" trick because
978 // it is our only hope for the fixed-pipe implementation.
979 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000980 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000981 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000982 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000983 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000984#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000985 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000986#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000987 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000988 } else {
989 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000990 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000991 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000992 const GrDrawState& drawState = target->getDrawState();
993 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000994 return false;
995 }
996
bsalomon@google.com471d4712011-08-23 15:45:25 +0000997 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000998 return false;
999 }
1000
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001001 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002 return false;
1003 }
1004
1005 if (NULL != matrix &&
1006 !matrix->preservesAxisAlignment()) {
1007 return false;
1008 }
1009
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001010 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001011 if (NULL != matrix) {
1012 combinedMatrix->preConcat(*matrix);
1013 GrAssert(combinedMatrix->preservesAxisAlignment());
1014 }
1015
1016 combinedMatrix->mapRect(devRect, rect);
1017 devRect->sort();
1018
1019 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001020 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001021 } else {
1022 return true;
1023 }
1024}
1025
bsalomon@google.com27847de2011-02-22 20:59:41 +00001026void GrContext::drawRect(const GrPaint& paint,
1027 const GrRect& rect,
1028 GrScalar width,
1029 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001030 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001031
1032 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001033 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001034
bsalomon@google.com205d4602011-04-25 12:43:45 +00001035 GrRect devRect = rect;
1036 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001037 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001038 bool needAA = paint.fAntiAlias &&
1039 !this->getRenderTarget()->isMultisampled();
1040 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1041 &combinedMatrix, &devRect,
1042 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001043
1044 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001045 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001046 if (width >= 0) {
1047 GrVec strokeSize;;
1048 if (width > 0) {
1049 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001050 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001051 strokeSize.setAbs(strokeSize);
1052 } else {
1053 strokeSize.set(GR_Scalar1, GR_Scalar1);
1054 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001055 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001056 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001057 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001058 }
1059 return;
1060 }
1061
bsalomon@google.com27847de2011-02-22 20:59:41 +00001062 if (width >= 0) {
1063 // TODO: consider making static vertex buffers for these cases.
1064 // Hairline could be done by just adding closing vertex to
1065 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001066 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1067
bsalomon@google.com27847de2011-02-22 20:59:41 +00001068 static const int worstCaseVertCount = 10;
1069 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1070
1071 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001072 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001073 return;
1074 }
1075
1076 GrPrimitiveType primType;
1077 int vertCount;
1078 GrPoint* vertex = geo.positions();
1079
1080 if (width > 0) {
1081 vertCount = 10;
1082 primType = kTriangleStrip_PrimitiveType;
1083 setStrokeRectStrip(vertex, rect, width);
1084 } else {
1085 // hairline
1086 vertCount = 5;
1087 primType = kLineStrip_PrimitiveType;
1088 vertex[0].set(rect.fLeft, rect.fTop);
1089 vertex[1].set(rect.fRight, rect.fTop);
1090 vertex[2].set(rect.fRight, rect.fBottom);
1091 vertex[3].set(rect.fLeft, rect.fBottom);
1092 vertex[4].set(rect.fLeft, rect.fTop);
1093 }
1094
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001095 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001096 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001097 GrDrawState* drawState = target->drawState();
1098 avmr.set(drawState);
1099 drawState->preConcatViewMatrix(*matrix);
1100 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001101 }
1102
1103 target->drawNonIndexed(primType, 0, vertCount);
1104 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001105#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001106 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001107 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1108 if (NULL == sqVB) {
1109 GrPrintf("Failed to create static rect vb.\n");
1110 return;
1111 }
1112 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001113 GrDrawState* drawState = target->drawState();
1114 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001115 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001116 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001117 0, rect.height(), rect.fTop,
1118 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119
1120 if (NULL != matrix) {
1121 m.postConcat(*matrix);
1122 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001123 drawState->preConcatViewMatrix(m);
1124 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001125
bsalomon@google.com27847de2011-02-22 20:59:41 +00001126 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001127#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001128 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001129#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130 }
1131}
1132
1133void GrContext::drawRectToRect(const GrPaint& paint,
1134 const GrRect& dstRect,
1135 const GrRect& srcRect,
1136 const GrMatrix* dstMatrix,
1137 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001138 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001139
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001140 // srcRect refers to paint's first texture
1141 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001142 drawRect(paint, dstRect, -1, dstMatrix);
1143 return;
1144 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001145
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1147
1148#if GR_STATIC_RECT_VB
1149 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001150 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001151 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001152 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001153
1154 GrMatrix m;
1155
1156 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1157 0, dstRect.height(), dstRect.fTop,
1158 0, 0, GrMatrix::I()[8]);
1159 if (NULL != dstMatrix) {
1160 m.postConcat(*dstMatrix);
1161 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001162 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001163
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001164 // srcRect refers to first stage
1165 int otherStageMask = paint.getActiveStageMask() &
1166 (~(1 << GrPaint::kFirstTextureStage));
1167 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001168 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001169 }
1170
bsalomon@google.com27847de2011-02-22 20:59:41 +00001171 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1172 0, srcRect.height(), srcRect.fTop,
1173 0, 0, GrMatrix::I()[8]);
1174 if (NULL != srcMatrix) {
1175 m.postConcat(*srcMatrix);
1176 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001177 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001178
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001179 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1180 if (NULL == sqVB) {
1181 GrPrintf("Failed to create static rect vb.\n");
1182 return;
1183 }
1184 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001185 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1186#else
1187
1188 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001189#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001190 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001191#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001192 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1193#endif
1194
tomhudson@google.com93813632011-10-27 20:21:16 +00001195 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1196 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001197 srcRects[0] = &srcRect;
1198 srcMatrices[0] = srcMatrix;
1199
1200 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1201#endif
1202}
1203
1204void GrContext::drawVertices(const GrPaint& paint,
1205 GrPrimitiveType primitiveType,
1206 int vertexCount,
1207 const GrPoint positions[],
1208 const GrPoint texCoords[],
1209 const GrColor colors[],
1210 const uint16_t indices[],
1211 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001212 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001213
1214 GrDrawTarget::AutoReleaseGeometry geo;
1215
1216 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1217
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001218 bool hasTexCoords[GrPaint::kTotalStages] = {
1219 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1220 0 // remaining stages use positions
1221 };
1222
1223 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001224
1225 if (NULL != colors) {
1226 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001228 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229
1230 if (sizeof(GrPoint) != vertexSize) {
1231 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001232 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233 return;
1234 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001235 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001236 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001237 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1238 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001239 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001240 NULL,
1241 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001242 void* curVertex = geo.vertices();
1243
1244 for (int i = 0; i < vertexCount; ++i) {
1245 *((GrPoint*)curVertex) = positions[i];
1246
1247 if (texOffsets[0] > 0) {
1248 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1249 }
1250 if (colorOffset > 0) {
1251 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1252 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001254 }
1255 } else {
1256 target->setVertexSourceToArray(layout, positions, vertexCount);
1257 }
1258
bsalomon@google.com91958362011-06-13 17:58:13 +00001259 // we don't currently apply offscreen AA to this path. Need improved
1260 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001261
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001262 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001263 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001264 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001266 target->drawNonIndexed(primitiveType, 0, vertexCount);
1267 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001268}
1269
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001270///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001271namespace {
1272
bsalomon@google.com93c96602012-04-27 13:05:21 +00001273struct CircleVertex {
1274 GrPoint fPos;
1275 GrPoint fCenter;
1276 GrScalar fOuterRadius;
1277 GrScalar fInnerRadius;
1278};
1279
1280/* Returns true if will map a circle to another circle. This can be true
1281 * if the matrix only includes square-scale, rotation, translation.
1282 */
1283inline bool isSimilarityTransformation(const SkMatrix& matrix,
1284 SkScalar tol = SK_ScalarNearlyZero) {
1285 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1286 return true;
1287 }
1288 if (matrix.hasPerspective()) {
1289 return false;
1290 }
1291
1292 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1293 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1294 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1295 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1296
1297 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1298 return false;
1299 }
1300
1301 // it has scales or skews, but it could also be rotation, check it out.
1302 SkVector vec[2];
1303 vec[0].set(mx, sx);
1304 vec[1].set(sy, my);
1305
1306 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1307 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1308 SkScalarSquare(tol));
1309}
1310
1311}
1312
1313// TODO: strokeWidth can't be larger than zero right now.
1314// It will be fixed when drawPath() can handle strokes.
1315void GrContext::drawOval(const GrPaint& paint,
1316 const GrRect& rect,
1317 SkScalar strokeWidth) {
1318 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1319 kUnbuffered_DrawCategory;
1320 GrDrawTarget* target = this->prepareToDraw(paint, category);
1321 GrDrawState* drawState = target->drawState();
1322 GrMatrix vm = drawState->getViewMatrix();
1323
1324 if (!isSimilarityTransformation(vm) ||
1325 !paint.fAntiAlias ||
1326 rect.height() != rect.width()) {
1327 SkPath path;
1328 path.addOval(rect);
1329 GrPathFill fill = (strokeWidth == 0) ?
1330 kHairLine_PathFill : kWinding_PathFill;
1331 this->internalDrawPath(paint, path, fill, NULL);
1332 return;
1333 }
1334
1335 const GrRenderTarget* rt = drawState->getRenderTarget();
1336 if (NULL == rt) {
1337 return;
1338 }
1339
1340 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1341
1342 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1343 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1344 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1345
1346 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1347 GrScalar radius = SkScalarHalf(rect.width());
1348
1349 vm.mapPoints(&center, 1);
1350 radius = vm.mapRadius(radius);
1351
1352 GrScalar outerRadius = radius;
1353 GrScalar innerRadius = 0;
1354 SkScalar halfWidth = 0;
1355 if (strokeWidth == 0) {
1356 halfWidth = SkScalarHalf(SK_Scalar1);
1357
1358 outerRadius += halfWidth;
1359 innerRadius = SkMaxScalar(0, radius - halfWidth);
1360 }
1361
1362 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1363 if (!geo.succeeded()) {
1364 GrPrintf("Failed to get space for vertices!\n");
1365 return;
1366 }
1367
1368 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1369
1370 SkScalar L = center.fX - outerRadius;
1371 SkScalar R = center.fX + outerRadius;
1372 SkScalar T = center.fY - outerRadius;
1373 SkScalar B = center.fY + outerRadius;
1374
1375 verts[0].fPos = SkPoint::Make(L, T);
1376 verts[1].fPos = SkPoint::Make(R, T);
1377 verts[2].fPos = SkPoint::Make(L, B);
1378 verts[3].fPos = SkPoint::Make(R, B);
1379
1380 for (int i = 0; i < 4; ++i) {
1381 // this goes to fragment shader, it should be in y-points-up space.
1382 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1383
1384 verts[i].fOuterRadius = outerRadius;
1385 verts[i].fInnerRadius = innerRadius;
1386 }
1387
1388 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1389 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001390}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001392void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001393 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001394
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001395 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001396 if (GrIsFillInverted(fill)) {
1397 this->drawPaint(paint);
1398 }
1399 return;
1400 }
1401
bsalomon@google.com93c96602012-04-27 13:05:21 +00001402 SkRect ovalRect;
1403 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1404 if (translate) {
1405 ovalRect.offset(*translate);
1406 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001407 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001408 this->drawOval(paint, ovalRect, width);
1409 return;
1410 }
1411
1412 internalDrawPath(paint, path, fill, translate);
1413}
1414
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001415void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001416 GrPathFill fill, const GrPoint* translate) {
1417
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001418 // Note that below we may sw-rasterize the path into a scratch texture.
1419 // Scratch textures can be recycled after they are returned to the texture
1420 // cache. This presents a potential hazard for buffered drawing. However,
1421 // the writePixels that uploads to the scratch will perform a flush so we're
1422 // OK.
1423 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1424 kUnbuffered_DrawCategory;
1425 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001426 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001427
bsalomon@google.com289533a2011-10-27 12:34:25 +00001428 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1429
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001430 // An Assumption here is that path renderer would use some form of tweaking
1431 // the src color (either the input alpha or in the frag shader) to implement
1432 // aa. If we have some future driver-mojo path AA that can do the right
1433 // thing WRT to the blend then we'll need some query on the PR.
1434 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001435#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001436 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001437#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001438 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001439 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001440
robertphillips@google.comed4155d2012-05-01 14:30:24 +00001441 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA);
bsalomon@google.com30085192011-08-19 15:42:31 +00001442 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001443#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001444 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001445#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001446 return;
1447 }
1448
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001449 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001450}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001451
bsalomon@google.com27847de2011-02-22 20:59:41 +00001452////////////////////////////////////////////////////////////////////////////////
1453
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001454void GrContext::flush(int flagsBitfield) {
1455 if (kDiscard_FlushBit & flagsBitfield) {
1456 fDrawBuffer->reset();
1457 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001458 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001459 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001460 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461 fGpu->forceRenderTargetFlush();
1462 }
1463}
1464
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001466 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001467 // With addition of the AA clip path, flushing the draw buffer can
1468 // result in the generation of an AA clip mask. During this
1469 // process the SW path renderer may be invoked which recusively
1470 // calls this method (via internalWriteTexturePixels) creating
1471 // infinite recursion
1472 GrInOrderDrawBuffer* temp = fDrawBuffer;
1473 fDrawBuffer = NULL;
1474
1475 temp->flushTo(fGpu);
1476
1477 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001478 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001479}
1480
bsalomon@google.com6f379512011-11-16 20:36:03 +00001481void GrContext::internalWriteTexturePixels(GrTexture* texture,
1482 int left, int top,
1483 int width, int height,
1484 GrPixelConfig config,
1485 const void* buffer,
1486 size_t rowBytes,
1487 uint32_t flags) {
1488 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001489 ASSERT_OWNED_RESOURCE(texture);
1490
bsalomon@google.com6f379512011-11-16 20:36:03 +00001491 if (!(kDontFlush_PixelOpsFlag & flags)) {
1492 this->flush();
1493 }
1494 // TODO: use scratch texture to perform conversion
1495 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1496 GrPixelConfigIsUnpremultiplied(config)) {
1497 return;
1498 }
1499
1500 fGpu->writeTexturePixels(texture, left, top, width, height,
1501 config, buffer, rowBytes);
1502}
1503
1504bool GrContext::internalReadTexturePixels(GrTexture* texture,
1505 int left, int top,
1506 int width, int height,
1507 GrPixelConfig config,
1508 void* buffer,
1509 size_t rowBytes,
1510 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001511 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001512 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001513
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001514 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001515 GrRenderTarget* target = texture->asRenderTarget();
1516 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001517 return this->internalReadRenderTargetPixels(target,
1518 left, top, width, height,
1519 config, buffer, rowBytes,
1520 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001521 } else {
1522 return false;
1523 }
1524}
1525
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001526#include "SkConfig8888.h"
1527
1528namespace {
1529/**
1530 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1531 * formats are representable as Config8888 and so the function returns false
1532 * if the GrPixelConfig has no equivalent Config8888.
1533 */
1534bool grconfig_to_config8888(GrPixelConfig config,
1535 SkCanvas::Config8888* config8888) {
1536 switch (config) {
1537 case kRGBA_8888_PM_GrPixelConfig:
1538 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1539 return true;
1540 case kRGBA_8888_UPM_GrPixelConfig:
1541 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1542 return true;
1543 case kBGRA_8888_PM_GrPixelConfig:
1544 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1545 return true;
1546 case kBGRA_8888_UPM_GrPixelConfig:
1547 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1548 return true;
1549 default:
1550 return false;
1551 }
1552}
1553}
1554
bsalomon@google.com6f379512011-11-16 20:36:03 +00001555bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1556 int left, int top,
1557 int width, int height,
1558 GrPixelConfig config,
1559 void* buffer,
1560 size_t rowBytes,
1561 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001562 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001563 ASSERT_OWNED_RESOURCE(target);
1564
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001565 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001566 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001567 if (NULL == target) {
1568 return false;
1569 }
1570 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001571
bsalomon@google.com6f379512011-11-16 20:36:03 +00001572 if (!(kDontFlush_PixelOpsFlag & flags)) {
1573 this->flush();
1574 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001575
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001576 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1577 GrPixelConfigIsUnpremultiplied(config) &&
1578 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1579 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1580 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1581 !grconfig_to_config8888(config, &dstConfig8888)) {
1582 return false;
1583 }
1584 // do read back using target's own config
1585 this->internalReadRenderTargetPixels(target,
1586 left, top,
1587 width, height,
1588 target->config(),
1589 buffer, rowBytes,
1590 kDontFlush_PixelOpsFlag);
1591 // sw convert the pixels to unpremul config
1592 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1593 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1594 pixels, rowBytes, srcConfig8888,
1595 width, height);
1596 return true;
1597 }
1598
bsalomon@google.comc4364992011-11-07 15:54:49 +00001599 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001600 bool swapRAndB = NULL != src &&
1601 fGpu->preferredReadPixelsConfig(config) ==
1602 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001603
1604 bool flipY = NULL != src &&
1605 fGpu->readPixelsWillPayForYFlip(target, left, top,
1606 width, height, config,
1607 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001608 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1609 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001610
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001611 if (NULL == src && alphaConversion) {
1612 // we should fallback to cpu conversion here. This could happen when
1613 // we were given an external render target by the client that is not
1614 // also a texture (e.g. FBO 0 in GL)
1615 return false;
1616 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001617 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001618 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001619 if (flipY || swapRAndB || alphaConversion) {
1620 GrAssert(NULL != src);
1621 if (swapRAndB) {
1622 config = GrPixelConfigSwapRAndB(config);
1623 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001624 }
1625 // Make the scratch a render target because we don't have a robust
1626 // readTexturePixels as of yet (it calls this function).
1627 const GrTextureDesc desc = {
1628 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001629 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001630 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001631 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001632 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001633
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001634 // When a full readback is faster than a partial we could always make
1635 // the scratch exactly match the passed rect. However, if we see many
1636 // different size rectangles we will trash our texture cache and pay the
1637 // cost of creating and destroying many textures. So, we only request
1638 // an exact match when the caller is reading an entire RT.
1639 ScratchTexMatch match = kApprox_ScratchTexMatch;
1640 if (0 == left &&
1641 0 == top &&
1642 target->width() == width &&
1643 target->height() == height &&
1644 fGpu->fullReadPixelsIsFasterThanPartial()) {
1645 match = kExact_ScratchTexMatch;
1646 }
1647 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001648 GrTexture* texture = ast.texture();
1649 if (!texture) {
1650 return false;
1651 }
1652 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001653 GrAssert(NULL != target);
1654
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001655 GrDrawTarget::AutoStateRestore asr(fGpu,
1656 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001657 GrDrawState* drawState = fGpu->drawState();
1658 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001659
bsalomon@google.comc4364992011-11-07 15:54:49 +00001660 GrMatrix matrix;
1661 if (flipY) {
1662 matrix.setTranslate(SK_Scalar1 * left,
1663 SK_Scalar1 * (top + height));
1664 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1665 } else {
1666 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1667 }
1668 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001669 drawState->sampler(0)->reset(matrix);
1670 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001671 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001672 GrRect rect;
1673 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1674 fGpu->drawSimpleRect(rect, NULL, 0x1);
1675 left = 0;
1676 top = 0;
1677 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001678 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001679 left, top, width, height,
1680 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001681}
1682
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001683void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1684 GrAssert(target);
1685 ASSERT_OWNED_RESOURCE(target);
1686 // In the future we may track whether there are any pending draws to this
1687 // target. We don't today so we always perform a flush. We don't promise
1688 // this to our clients, though.
1689 this->flush();
1690 fGpu->resolveRenderTarget(target);
1691}
1692
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001693void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1694 if (NULL == src || NULL == dst) {
1695 return;
1696 }
1697 ASSERT_OWNED_RESOURCE(src);
1698
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001699 // Writes pending to the source texture are not tracked, so a flush
1700 // is required to ensure that the copy captures the most recent contents
1701 // of the source texture. See similar behaviour in
1702 // GrContext::resolveRenderTarget.
1703 this->flush();
1704
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001705 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001706 GrDrawState* drawState = fGpu->drawState();
1707 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001708 GrMatrix sampleM;
1709 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001710 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001711 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001712 SkRect rect = SkRect::MakeXYWH(0, 0,
1713 SK_Scalar1 * src->width(),
1714 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001715 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1716}
1717
bsalomon@google.com6f379512011-11-16 20:36:03 +00001718void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1719 int left, int top,
1720 int width, int height,
1721 GrPixelConfig config,
1722 const void* buffer,
1723 size_t rowBytes,
1724 uint32_t flags) {
1725 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001726 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001727
1728 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001729 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001730 if (NULL == target) {
1731 return;
1732 }
1733 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001734
1735 // TODO: when underlying api has a direct way to do this we should use it
1736 // (e.g. glDrawPixels on desktop GL).
1737
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001738 // If the RT is also a texture and we don't have to do PM/UPM conversion
1739 // then take the texture path, which we expect to be at least as fast or
1740 // faster since it doesn't use an intermediate texture as we do below.
1741
1742#if !GR_MAC_BUILD
1743 // At least some drivers on the Mac get confused when glTexImage2D is called
1744 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1745 // determine what OS versions and/or HW is affected.
1746 if (NULL != target->asTexture() &&
1747 GrPixelConfigIsUnpremultiplied(target->config()) ==
1748 GrPixelConfigIsUnpremultiplied(config)) {
1749
1750 this->internalWriteTexturePixels(target->asTexture(),
1751 left, top, width, height,
1752 config, buffer, rowBytes, flags);
1753 return;
1754 }
1755#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001756 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1757 GrPixelConfigIsUnpremultiplied(config) &&
1758 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1759 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1760 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1761 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1762 return;
1763 }
1764 // allocate a tmp buffer and sw convert the pixels to premul
1765 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1766 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1767 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1768 src, rowBytes, srcConfig8888,
1769 width, height);
1770 // upload the already premul pixels
1771 this->internalWriteRenderTargetPixels(target,
1772 left, top,
1773 width, height,
1774 target->config(),
1775 tmpPixels, 4 * width, flags);
1776 return;
1777 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001778
1779 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1780 GrPixelConfigSwapRAndB(config);
1781 if (swapRAndB) {
1782 config = GrPixelConfigSwapRAndB(config);
1783 }
1784
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001785 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001786 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001787 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001788 GrAutoScratchTexture ast(this, desc);
1789 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001790 if (NULL == texture) {
1791 return;
1792 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001793 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1794 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001795
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001796 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001797 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001798
1799 GrMatrix matrix;
1800 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001801 drawState->setViewMatrix(matrix);
1802 drawState->setRenderTarget(target);
1803 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001804
bsalomon@google.com5c638652011-07-18 19:31:59 +00001805 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001806 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1807 GrSamplerState::kNearest_Filter,
1808 matrix);
1809 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001810
1811 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1812 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001813 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001814 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1815 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001816 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001817 return;
1818 }
1819 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1820 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1821}
1822////////////////////////////////////////////////////////////////////////////////
1823
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001824void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001825
1826 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1827 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001828 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001829 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001830 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001831 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001832 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001833 }
1834
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001835 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001836
1837 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1838 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001839 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001840 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001841 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001842 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001843 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001844 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001845
1846 // disable all stages not accessible via the paint
1847 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001848 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001849 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001850
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001851 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001852
1853 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001854 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001855 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001856 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001857 }
1858 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001859 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001860 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001861 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001862 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001863 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001864 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1865 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001866 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001867 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001868 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001869 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1870 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1871 fDrawState->setCoverage(paint.fCoverage);
bsalomon@google.come79c8152012-03-29 19:07:12 +00001872#if GR_DEBUG
1873 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001874 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001875 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1876 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001877#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001878}
1879
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001880GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001881 DrawCategory category) {
1882 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001883 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001884 fLastDrawCategory = category;
1885 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001886 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001887 GrDrawTarget* target = fGpu;
1888 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001889 case kUnbuffered_DrawCategory:
1890 target = fGpu;
1891 break;
1892 case kBuffered_DrawCategory:
1893 target = fDrawBuffer;
1894 fDrawBuffer->setClip(fGpu->getClip());
1895 break;
1896 default:
1897 GrCrash("Unexpected DrawCategory.");
1898 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001899 }
1900 return target;
1901}
1902
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001903GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001904 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001905 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001906 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001907 if (NULL == fPathRendererChain) {
1908 fPathRendererChain =
1909 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1910 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001911 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001912}
1913
bsalomon@google.com27847de2011-02-22 20:59:41 +00001914////////////////////////////////////////////////////////////////////////////////
1915
bsalomon@google.com27847de2011-02-22 20:59:41 +00001916void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001917 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001918 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001919 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001920 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001921 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001922}
1923
1924GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001925 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001926}
1927
1928const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001929 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001930}
1931
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001932bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1933 return fGpu->isConfigRenderable(config);
1934}
1935
bsalomon@google.com27847de2011-02-22 20:59:41 +00001936const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001937 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938}
1939
1940void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001941 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001942}
1943
1944void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001945 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946}
1947
1948static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1949 intptr_t mask = 1 << shift;
1950 if (pred) {
1951 bits |= mask;
1952 } else {
1953 bits &= ~mask;
1954 }
1955 return bits;
1956}
1957
1958void GrContext::resetStats() {
1959 fGpu->resetStats();
1960}
1961
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001962const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001963 return fGpu->getStats();
1964}
1965
1966void GrContext::printStats() const {
1967 fGpu->printStats();
1968}
1969
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001970GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001971 fGpu = gpu;
1972 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001973 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001974
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001975 fDrawState = new GrDrawState();
1976 fGpu->setDrawState(fDrawState);
1977
bsalomon@google.com30085192011-08-19 15:42:31 +00001978 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001979
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001980 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1981 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982 fFontCache = new GrFontCache(fGpu);
1983
1984 fLastDrawCategory = kUnbuffered_DrawCategory;
1985
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001986 fDrawBuffer = NULL;
1987 fDrawBufferVBAllocPool = NULL;
1988 fDrawBufferIBAllocPool = NULL;
1989
bsalomon@google.com205d4602011-04-25 12:43:45 +00001990 fAAFillRectIndexBuffer = NULL;
1991 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001992
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001993 this->setupDrawBuffer();
1994}
1995
1996void GrContext::setupDrawBuffer() {
1997
1998 GrAssert(NULL == fDrawBuffer);
1999 GrAssert(NULL == fDrawBufferVBAllocPool);
2000 GrAssert(NULL == fDrawBufferIBAllocPool);
2001
bsalomon@google.com92edd312012-04-04 21:40:21 +00002002#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002003 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002004 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2006 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002007 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002008 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002009 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002010 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2011
bsalomon@google.com471d4712011-08-23 15:45:25 +00002012 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2013 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002014 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002015#endif
2016
2017#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002018 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002019#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002020 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002021 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002022}
2023
bsalomon@google.com27847de2011-02-22 20:59:41 +00002024GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002025#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002026 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002027#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002028 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002029#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002030}
2031
2032const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2033 return fGpu->getQuadIndexBuffer();
2034}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002035
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002036GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2037 GrAutoScratchTexture* temp1,
2038 GrAutoScratchTexture* temp2,
2039 const SkRect& rect,
2040 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002041 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002042 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2043 GrClip oldClip = this->getClip();
2044 GrTexture* origTexture = srcTexture;
2045 GrAutoMatrix avm(this, GrMatrix::I());
2046 SkIRect clearRect;
2047 int scaleFactorX, halfWidthX, kernelWidthX;
2048 int scaleFactorY, halfWidthY, kernelWidthY;
2049 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2050 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002051
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002052 SkRect srcRect(rect);
2053 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2054 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002055 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2056 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002057 this->setClip(srcRect);
2058
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002059 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2060 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2061 kAlpha_8_GrPixelConfig == srcTexture->config());
2062
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002063 const GrTextureDesc desc = {
2064 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002065 SkScalarFloorToInt(srcRect.width()),
2066 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002067 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002068 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002069 };
2070
2071 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002072 if (temp2) {
2073 temp2->set(this, desc);
2074 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002075
2076 GrTexture* dstTexture = temp1->texture();
2077 GrPaint paint;
2078 paint.reset();
2079 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2080
2081 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2082 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2083 srcTexture->height());
2084 this->setRenderTarget(dstTexture->asRenderTarget());
2085 SkRect dstRect(srcRect);
2086 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2087 i < scaleFactorY ? 0.5f : 1.0f);
2088 paint.setTexture(0, srcTexture);
2089 this->drawRectToRect(paint, dstRect, srcRect);
2090 srcRect = dstRect;
2091 SkTSwap(srcTexture, dstTexture);
2092 // If temp2 is non-NULL, don't render back to origTexture
2093 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2094 }
2095
2096 if (sigmaX > 0.0f) {
2097 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2098 float* kernelX = kernelStorageX.get();
2099 build_kernel(sigmaX, kernelX, kernelWidthX);
2100
2101 if (scaleFactorX > 1) {
2102 // Clear out a halfWidth to the right of the srcRect to prevent the
2103 // X convolution from reading garbage.
2104 clearRect = SkIRect::MakeXYWH(
2105 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2106 this->clear(&clearRect, 0x0);
2107 }
2108
2109 this->setRenderTarget(dstTexture->asRenderTarget());
2110 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2111 GrSamplerState::kX_FilterDirection);
2112 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002113 if (temp2 && dstTexture == origTexture) {
2114 dstTexture = temp2->texture();
2115 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002116 }
2117
2118 if (sigmaY > 0.0f) {
2119 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2120 float* kernelY = kernelStorageY.get();
2121 build_kernel(sigmaY, kernelY, kernelWidthY);
2122
2123 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2124 // Clear out a halfWidth below the srcRect to prevent the Y
2125 // convolution from reading garbage.
2126 clearRect = SkIRect::MakeXYWH(
2127 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2128 this->clear(&clearRect, 0x0);
2129 }
2130
2131 this->setRenderTarget(dstTexture->asRenderTarget());
2132 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2133 GrSamplerState::kY_FilterDirection);
2134 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002135 if (temp2 && dstTexture == origTexture) {
2136 dstTexture = temp2->texture();
2137 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002138 }
2139
2140 if (scaleFactorX > 1 || scaleFactorY > 1) {
2141 // Clear one pixel to the right and below, to accommodate bilinear
2142 // upsampling.
2143 clearRect = SkIRect::MakeXYWH(
2144 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2145 this->clear(&clearRect, 0x0);
2146 clearRect = SkIRect::MakeXYWH(
2147 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2148 this->clear(&clearRect, 0x0);
2149 // FIXME: This should be mitchell, not bilinear.
2150 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2151 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2152 srcTexture->height());
2153 this->setRenderTarget(dstTexture->asRenderTarget());
2154 paint.setTexture(0, srcTexture);
2155 SkRect dstRect(srcRect);
2156 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2157 this->drawRectToRect(paint, dstRect, srcRect);
2158 srcRect = dstRect;
2159 SkTSwap(srcTexture, dstTexture);
2160 }
2161 this->setRenderTarget(oldRenderTarget);
2162 this->setClip(oldClip);
2163 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002164}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002165
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002166GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2167 const GrRect& rect,
2168 GrTexture* temp1, GrTexture* temp2,
2169 GrSamplerState::Filter filter,
2170 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002171 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002172 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2173 GrAutoMatrix avm(this, GrMatrix::I());
2174 GrClip oldClip = this->getClip();
2175 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2176 if (radius.fWidth > 0) {
2177 this->setRenderTarget(temp1->asRenderTarget());
2178 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2179 GrSamplerState::kX_FilterDirection);
2180 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2181 rect.width(), radius.fHeight);
2182 this->clear(&clearRect, 0x0);
2183 srcTexture = temp1;
2184 }
2185 if (radius.fHeight > 0) {
2186 this->setRenderTarget(temp2->asRenderTarget());
2187 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2188 GrSamplerState::kY_FilterDirection);
2189 srcTexture = temp2;
2190 }
2191 this->setRenderTarget(oldRenderTarget);
2192 this->setClip(oldClip);
2193 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002194}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002195
2196///////////////////////////////////////////////////////////////////////////////