blob: 8e45e15a0ab0743773624005e112fd7ebc37802f [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) {
243 rect->fLeft *= xScale;
244 rect->fTop *= yScale;
245 rect->fRight *= xScale;
246 rect->fBottom *= yScale;
247}
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 +00001271#include "SkDraw.h"
1272#include "SkRasterClip.h"
1273
1274namespace {
1275
1276SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1277 switch (fill) {
1278 case kWinding_PathFill:
1279 return SkPath::kWinding_FillType;
1280 case kEvenOdd_PathFill:
1281 return SkPath::kEvenOdd_FillType;
1282 case kInverseWinding_PathFill:
1283 return SkPath::kInverseWinding_FillType;
1284 case kInverseEvenOdd_PathFill:
1285 return SkPath::kInverseEvenOdd_FillType;
1286 default:
1287 GrCrash("Unexpected fill.");
1288 return SkPath::kWinding_FillType;
1289 }
1290}
1291
1292// gets device coord bounds of path (not considering the fill) and clip. The
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001293// path bounds will be a subset of the clip bounds. returns false if
1294// path bounds would be empty.
bsalomon@google.com150d2842012-01-12 20:19:56 +00001295bool get_path_and_clip_bounds(const GrDrawTarget* target,
1296 const GrPath& path,
1297 const GrVec* translate,
1298 GrIRect* pathBounds,
1299 GrIRect* clipBounds) {
1300 // compute bounds as intersection of rt size, clip, and path
1301 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1302 if (NULL == rt) {
1303 return false;
1304 }
1305 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1306 const GrClip& clip = target->getClip();
1307 if (clip.hasConservativeBounds()) {
1308 clip.getConservativeBounds().roundOut(clipBounds);
1309 if (!pathBounds->intersect(*clipBounds)) {
1310 return false;
1311 }
1312 } else {
1313 // pathBounds is currently the rt extent, set clip bounds to that rect.
1314 *clipBounds = *pathBounds;
1315 }
1316 GrRect pathSBounds = path.getBounds();
1317 if (!pathSBounds.isEmpty()) {
1318 if (NULL != translate) {
1319 pathSBounds.offset(*translate);
1320 }
1321 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1322 pathSBounds);
1323 GrIRect pathIBounds;
1324 pathSBounds.roundOut(&pathIBounds);
1325 if (!pathBounds->intersect(pathIBounds)) {
1326 return false;
1327 }
1328 } else {
1329 return false;
1330 }
1331 return true;
1332}
1333
1334/**
1335 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1336 * scratch texture.
1337 */
1338
1339bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1340 const GrIRect& pathDevBounds,
1341 GrPathFill fill,
1342 GrContext* context,
1343 const GrPoint* translate,
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001344 GrAutoScratchTexture* tex,
1345 bool antiAlias) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001346 SkPaint paint;
1347 SkPath tmpPath;
1348 const SkPath* pathToDraw = &clientPath;
1349 if (kHairLine_PathFill == fill) {
1350 paint.setStyle(SkPaint::kStroke_Style);
1351 paint.setStrokeWidth(SK_Scalar1);
1352 } else {
1353 paint.setStyle(SkPaint::kFill_Style);
1354 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1355 if (skfill != pathToDraw->getFillType()) {
1356 tmpPath = *pathToDraw;
1357 tmpPath.setFillType(skfill);
1358 pathToDraw = &tmpPath;
1359 }
1360 }
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001361 paint.setAntiAlias(antiAlias);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001362 paint.setColor(SK_ColorWHITE);
1363
1364 GrMatrix matrix = context->getMatrix();
1365 if (NULL != translate) {
1366 matrix.postTranslate(translate->fX, translate->fY);
1367 }
1368
1369 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1370 -pathDevBounds.fTop * SK_Scalar1);
1371 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1372 pathDevBounds.height());
1373
1374 SkBitmap bm;
1375 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1376 if (!bm.allocPixels()) {
1377 return false;
1378 }
1379 sk_bzero(bm.getPixels(), bm.getSafeSize());
1380
1381 SkDraw draw;
1382 sk_bzero(&draw, sizeof(draw));
1383 SkRasterClip rc(bounds);
1384 draw.fRC = &rc;
1385 draw.fClip = &rc.bwRgn();
1386 draw.fMatrix = &matrix;
1387 draw.fBitmap = &bm;
1388 draw.drawPath(*pathToDraw, paint);
1389
1390 const GrTextureDesc desc = {
1391 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001392 bounds.fRight,
1393 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001394 kAlpha_8_GrPixelConfig,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001395 0 // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001396 };
1397
1398 tex->set(context, desc);
1399 GrTexture* texture = tex->texture();
1400
1401 if (NULL == texture) {
1402 return false;
1403 }
1404 SkAutoLockPixels alp(bm);
1405 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1406 bm.getPixels(), bm.rowBytes());
1407 return true;
1408}
1409
1410void draw_around_inv_path(GrDrawTarget* target,
1411 GrDrawState::StageMask stageMask,
1412 const GrIRect& clipBounds,
1413 const GrIRect& pathBounds) {
1414 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1415 GrRect rect;
1416 if (clipBounds.fTop < pathBounds.fTop) {
1417 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1418 clipBounds.fRight, pathBounds.fTop);
1419 target->drawSimpleRect(rect, NULL, stageMask);
1420 }
1421 if (clipBounds.fLeft < pathBounds.fLeft) {
1422 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1423 pathBounds.fLeft, pathBounds.fBottom);
1424 target->drawSimpleRect(rect, NULL, stageMask);
1425 }
1426 if (clipBounds.fRight > pathBounds.fRight) {
1427 rect.iset(pathBounds.fRight, pathBounds.fTop,
1428 clipBounds.fRight, pathBounds.fBottom);
1429 target->drawSimpleRect(rect, NULL, stageMask);
1430 }
1431 if (clipBounds.fBottom > pathBounds.fBottom) {
1432 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1433 clipBounds.fRight, clipBounds.fBottom);
1434 target->drawSimpleRect(rect, NULL, stageMask);
1435 }
1436}
1437
1438}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001439
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001440
1441
1442// return true on success; false on failure
1443bool onDrawPath(const SkPath& path,
1444 GrPathFill fill,
1445 const GrVec* translate,
1446 GrDrawTarget* target,
1447 GrDrawState::StageMask stageMask,
1448 bool antiAlias,
1449 GrContext* context) {
1450
1451 GrAutoScratchTexture ast;
1452 GrIRect pathBounds, clipBounds;
1453 if (!get_path_and_clip_bounds(target, path, translate,
1454 &pathBounds, &clipBounds)) {
1455 return true; // path is empty so there is nothing to do
1456 }
1457 if (sw_draw_path_to_mask_texture(path, pathBounds,
1458 fill, context,
1459 translate, &ast, antiAlias)) {
1460 GrTexture* texture = ast.texture();
1461 GrAssert(NULL != texture);
1462 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1463 enum {
1464 kPathMaskStage = GrPaint::kTotalStages,
1465 };
1466 target->drawState()->setTexture(kPathMaskStage, texture);
1467 target->drawState()->sampler(kPathMaskStage)->reset();
1468 GrScalar w = GrIntToScalar(pathBounds.width());
1469 GrScalar h = GrIntToScalar(pathBounds.height());
1470 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1471 h / texture->height());
1472 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1473 srcRects[kPathMaskStage] = &maskRect;
1474 stageMask |= 1 << kPathMaskStage;
1475 GrRect dstRect = GrRect::MakeLTRB(
1476 SK_Scalar1* pathBounds.fLeft,
1477 SK_Scalar1* pathBounds.fTop,
1478 SK_Scalar1* pathBounds.fRight,
1479 SK_Scalar1* pathBounds.fBottom);
1480 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1481 target->drawState()->setTexture(kPathMaskStage, NULL);
1482 if (GrIsFillInverted(fill)) {
1483 draw_around_inv_path(target, stageMask,
1484 clipBounds, pathBounds);
1485 }
1486 return true;
1487 }
1488
1489 return false;
1490}
1491
reed@google.com07f3ee12011-05-16 17:21:57 +00001492void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1493 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001495 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001496 if (GrIsFillInverted(fill)) {
1497 this->drawPaint(paint);
1498 }
1499 return;
1500 }
1501
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001502 // Note that below we may sw-rasterize the path into a scratch texture.
1503 // Scratch textures can be recycled after they are returned to the texture
1504 // cache. This presents a potential hazard for buffered drawing. However,
1505 // the writePixels that uploads to the scratch will perform a flush so we're
1506 // OK.
1507 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1508 kUnbuffered_DrawCategory;
1509 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001510 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001511
bsalomon@google.com289533a2011-10-27 12:34:25 +00001512 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1513
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001514 // An Assumption here is that path renderer would use some form of tweaking
1515 // the src color (either the input alpha or in the frag shader) to implement
1516 // aa. If we have some future driver-mojo path AA that can do the right
1517 // thing WRT to the blend then we'll need some query on the PR.
1518 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001519#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001520 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001521#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001522 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001523 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001524
bsalomon@google.com289533a2011-10-27 12:34:25 +00001525 GrPathRenderer* pr = NULL;
1526 if (prAA) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001527 pr = this->getPathRenderer(path, fill, target, true);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001528 if (NULL == pr) {
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001529 if (onDrawPath(path, fill, translate,
1530 target, stageMask, prAA, this)) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001531 return;
1532 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001533 }
1534 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001535 pr = this->getPathRenderer(path, fill, target, false);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001536 }
1537
bsalomon@google.com30085192011-08-19 15:42:31 +00001538 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001539#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001540 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001541#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001542 return;
1543 }
1544
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001545 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001547
bsalomon@google.com27847de2011-02-22 20:59:41 +00001548////////////////////////////////////////////////////////////////////////////////
1549
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001550void GrContext::flush(int flagsBitfield) {
1551 if (kDiscard_FlushBit & flagsBitfield) {
1552 fDrawBuffer->reset();
1553 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001554 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001555 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001556 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001557 fGpu->forceRenderTargetFlush();
1558 }
1559}
1560
bsalomon@google.com27847de2011-02-22 20:59:41 +00001561void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001562 if (fDrawBuffer) {
bsalomon@google.com97805382012-03-13 14:32:07 +00001563 fDrawBuffer->flushTo(fGpu);
junov@google.com53a55842011-06-08 22:55:10 +00001564 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001565}
1566
bsalomon@google.com6f379512011-11-16 20:36:03 +00001567void GrContext::internalWriteTexturePixels(GrTexture* texture,
1568 int left, int top,
1569 int width, int height,
1570 GrPixelConfig config,
1571 const void* buffer,
1572 size_t rowBytes,
1573 uint32_t flags) {
1574 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001575 ASSERT_OWNED_RESOURCE(texture);
1576
bsalomon@google.com6f379512011-11-16 20:36:03 +00001577 if (!(kDontFlush_PixelOpsFlag & flags)) {
1578 this->flush();
1579 }
1580 // TODO: use scratch texture to perform conversion
1581 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1582 GrPixelConfigIsUnpremultiplied(config)) {
1583 return;
1584 }
1585
1586 fGpu->writeTexturePixels(texture, left, top, width, height,
1587 config, buffer, rowBytes);
1588}
1589
1590bool GrContext::internalReadTexturePixels(GrTexture* texture,
1591 int left, int top,
1592 int width, int height,
1593 GrPixelConfig config,
1594 void* buffer,
1595 size_t rowBytes,
1596 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001597 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001598 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001599
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001600 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001601 GrRenderTarget* target = texture->asRenderTarget();
1602 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001603 return this->internalReadRenderTargetPixels(target,
1604 left, top, width, height,
1605 config, buffer, rowBytes,
1606 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001607 } else {
1608 return false;
1609 }
1610}
1611
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001612#include "SkConfig8888.h"
1613
1614namespace {
1615/**
1616 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1617 * formats are representable as Config8888 and so the function returns false
1618 * if the GrPixelConfig has no equivalent Config8888.
1619 */
1620bool grconfig_to_config8888(GrPixelConfig config,
1621 SkCanvas::Config8888* config8888) {
1622 switch (config) {
1623 case kRGBA_8888_PM_GrPixelConfig:
1624 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1625 return true;
1626 case kRGBA_8888_UPM_GrPixelConfig:
1627 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1628 return true;
1629 case kBGRA_8888_PM_GrPixelConfig:
1630 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1631 return true;
1632 case kBGRA_8888_UPM_GrPixelConfig:
1633 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1634 return true;
1635 default:
1636 return false;
1637 }
1638}
1639}
1640
bsalomon@google.com6f379512011-11-16 20:36:03 +00001641bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1642 int left, int top,
1643 int width, int height,
1644 GrPixelConfig config,
1645 void* buffer,
1646 size_t rowBytes,
1647 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001648 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001649 ASSERT_OWNED_RESOURCE(target);
1650
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001651 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001652 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001653 if (NULL == target) {
1654 return false;
1655 }
1656 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001657
bsalomon@google.com6f379512011-11-16 20:36:03 +00001658 if (!(kDontFlush_PixelOpsFlag & flags)) {
1659 this->flush();
1660 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001661
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001662 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1663 GrPixelConfigIsUnpremultiplied(config) &&
1664 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1665 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1666 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1667 !grconfig_to_config8888(config, &dstConfig8888)) {
1668 return false;
1669 }
1670 // do read back using target's own config
1671 this->internalReadRenderTargetPixels(target,
1672 left, top,
1673 width, height,
1674 target->config(),
1675 buffer, rowBytes,
1676 kDontFlush_PixelOpsFlag);
1677 // sw convert the pixels to unpremul config
1678 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1679 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1680 pixels, rowBytes, srcConfig8888,
1681 width, height);
1682 return true;
1683 }
1684
bsalomon@google.comc4364992011-11-07 15:54:49 +00001685 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001686 bool swapRAndB = NULL != src &&
1687 fGpu->preferredReadPixelsConfig(config) ==
1688 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001689
1690 bool flipY = NULL != src &&
1691 fGpu->readPixelsWillPayForYFlip(target, left, top,
1692 width, height, config,
1693 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001694 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1695 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001696
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001697 if (NULL == src && alphaConversion) {
1698 // we should fallback to cpu conversion here. This could happen when
1699 // we were given an external render target by the client that is not
1700 // also a texture (e.g. FBO 0 in GL)
1701 return false;
1702 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001703 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001704 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001705 if (flipY || swapRAndB || alphaConversion) {
1706 GrAssert(NULL != src);
1707 if (swapRAndB) {
1708 config = GrPixelConfigSwapRAndB(config);
1709 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001710 }
1711 // Make the scratch a render target because we don't have a robust
1712 // readTexturePixels as of yet (it calls this function).
1713 const GrTextureDesc desc = {
1714 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001715 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001716 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001717 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001718 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001719
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001720 // When a full readback is faster than a partial we could always make
1721 // the scratch exactly match the passed rect. However, if we see many
1722 // different size rectangles we will trash our texture cache and pay the
1723 // cost of creating and destroying many textures. So, we only request
1724 // an exact match when the caller is reading an entire RT.
1725 ScratchTexMatch match = kApprox_ScratchTexMatch;
1726 if (0 == left &&
1727 0 == top &&
1728 target->width() == width &&
1729 target->height() == height &&
1730 fGpu->fullReadPixelsIsFasterThanPartial()) {
1731 match = kExact_ScratchTexMatch;
1732 }
1733 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001734 GrTexture* texture = ast.texture();
1735 if (!texture) {
1736 return false;
1737 }
1738 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001739 GrAssert(NULL != target);
1740
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001741 GrDrawTarget::AutoStateRestore asr(fGpu,
1742 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001743 GrDrawState* drawState = fGpu->drawState();
1744 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001745
bsalomon@google.comc4364992011-11-07 15:54:49 +00001746 GrMatrix matrix;
1747 if (flipY) {
1748 matrix.setTranslate(SK_Scalar1 * left,
1749 SK_Scalar1 * (top + height));
1750 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1751 } else {
1752 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1753 }
1754 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001755 drawState->sampler(0)->reset(matrix);
1756 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001757 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001758 GrRect rect;
1759 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1760 fGpu->drawSimpleRect(rect, NULL, 0x1);
1761 left = 0;
1762 top = 0;
1763 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001764 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001765 left, top, width, height,
1766 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001767}
1768
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001769void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1770 GrAssert(target);
1771 ASSERT_OWNED_RESOURCE(target);
1772 // In the future we may track whether there are any pending draws to this
1773 // target. We don't today so we always perform a flush. We don't promise
1774 // this to our clients, though.
1775 this->flush();
1776 fGpu->resolveRenderTarget(target);
1777}
1778
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001779void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1780 if (NULL == src || NULL == dst) {
1781 return;
1782 }
1783 ASSERT_OWNED_RESOURCE(src);
1784
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001785 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001786 GrDrawState* drawState = fGpu->drawState();
1787 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001788 GrMatrix sampleM;
1789 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001790 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001791 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001792 SkRect rect = SkRect::MakeXYWH(0, 0,
1793 SK_Scalar1 * src->width(),
1794 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001795 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1796}
1797
bsalomon@google.com6f379512011-11-16 20:36:03 +00001798void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1799 int left, int top,
1800 int width, int height,
1801 GrPixelConfig config,
1802 const void* buffer,
1803 size_t rowBytes,
1804 uint32_t flags) {
1805 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001806 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001807
1808 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001809 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001810 if (NULL == target) {
1811 return;
1812 }
1813 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001814
1815 // TODO: when underlying api has a direct way to do this we should use it
1816 // (e.g. glDrawPixels on desktop GL).
1817
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001818 // If the RT is also a texture and we don't have to do PM/UPM conversion
1819 // then take the texture path, which we expect to be at least as fast or
1820 // faster since it doesn't use an intermediate texture as we do below.
1821
1822#if !GR_MAC_BUILD
1823 // At least some drivers on the Mac get confused when glTexImage2D is called
1824 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1825 // determine what OS versions and/or HW is affected.
1826 if (NULL != target->asTexture() &&
1827 GrPixelConfigIsUnpremultiplied(target->config()) ==
1828 GrPixelConfigIsUnpremultiplied(config)) {
1829
1830 this->internalWriteTexturePixels(target->asTexture(),
1831 left, top, width, height,
1832 config, buffer, rowBytes, flags);
1833 return;
1834 }
1835#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001836 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1837 GrPixelConfigIsUnpremultiplied(config) &&
1838 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1839 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1840 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1841 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1842 return;
1843 }
1844 // allocate a tmp buffer and sw convert the pixels to premul
1845 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1846 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1847 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1848 src, rowBytes, srcConfig8888,
1849 width, height);
1850 // upload the already premul pixels
1851 this->internalWriteRenderTargetPixels(target,
1852 left, top,
1853 width, height,
1854 target->config(),
1855 tmpPixels, 4 * width, flags);
1856 return;
1857 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001858
1859 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1860 GrPixelConfigSwapRAndB(config);
1861 if (swapRAndB) {
1862 config = GrPixelConfigSwapRAndB(config);
1863 }
1864
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001865 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001866 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001867 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001868 GrAutoScratchTexture ast(this, desc);
1869 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001870 if (NULL == texture) {
1871 return;
1872 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001873 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1874 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001875
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001876 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001877 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001878
1879 GrMatrix matrix;
1880 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001881 drawState->setViewMatrix(matrix);
1882 drawState->setRenderTarget(target);
1883 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001884
bsalomon@google.com5c638652011-07-18 19:31:59 +00001885 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001886 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1887 GrSamplerState::kNearest_Filter,
1888 matrix);
1889 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001890
1891 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1892 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001893 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001894 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1895 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001896 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001897 return;
1898 }
1899 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1900 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1901}
1902////////////////////////////////////////////////////////////////////////////////
1903
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001904void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001905
1906 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1907 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001908 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001909 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001910 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001911 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001912 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001913 }
1914
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001915 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001916
1917 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1918 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001919 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001920 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001921 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001922 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001923 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001924 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001925
1926 // disable all stages not accessible via the paint
1927 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001928 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001929 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001930
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001931 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001932
1933 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001934 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001935 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001936 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001937 }
1938 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001939 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001940 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001941 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001942 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001943 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001944 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1945 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001946 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001947 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001948 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001949 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1950 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1951 fDrawState->setCoverage(paint.fCoverage);
bsalomon@google.come79c8152012-03-29 19:07:12 +00001952#if GR_DEBUG
1953 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001954 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001955 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1956 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001957#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001958}
1959
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001960GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001961 DrawCategory category) {
1962 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001963 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001964 fLastDrawCategory = category;
1965 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001966 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001967 GrDrawTarget* target = fGpu;
1968 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001969 case kUnbuffered_DrawCategory:
1970 target = fGpu;
1971 break;
1972 case kBuffered_DrawCategory:
1973 target = fDrawBuffer;
1974 fDrawBuffer->setClip(fGpu->getClip());
1975 break;
1976 default:
1977 GrCrash("Unexpected DrawCategory.");
1978 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001979 }
1980 return target;
1981}
1982
bsalomon@google.com289533a2011-10-27 12:34:25 +00001983GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1984 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001985 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001986 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001987 if (NULL == fPathRendererChain) {
1988 fPathRendererChain =
1989 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1990 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001991 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001992}
1993
bsalomon@google.com27847de2011-02-22 20:59:41 +00001994////////////////////////////////////////////////////////////////////////////////
1995
bsalomon@google.com27847de2011-02-22 20:59:41 +00001996void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001997 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001998 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001999 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002000 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002001 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002002}
2003
2004GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002005 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002006}
2007
2008const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002009 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002010}
2011
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002012bool GrContext::isConfigRenderable(GrPixelConfig config) const {
2013 return fGpu->isConfigRenderable(config);
2014}
2015
bsalomon@google.com27847de2011-02-22 20:59:41 +00002016const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002017 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002018}
2019
2020void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002021 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002022}
2023
2024void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002025 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002026}
2027
2028static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2029 intptr_t mask = 1 << shift;
2030 if (pred) {
2031 bits |= mask;
2032 } else {
2033 bits &= ~mask;
2034 }
2035 return bits;
2036}
2037
2038void GrContext::resetStats() {
2039 fGpu->resetStats();
2040}
2041
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002042const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002043 return fGpu->getStats();
2044}
2045
2046void GrContext::printStats() const {
2047 fGpu->printStats();
2048}
2049
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002050GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002051 fGpu = gpu;
2052 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002053 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002054
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002055 fDrawState = new GrDrawState();
2056 fGpu->setDrawState(fDrawState);
2057
bsalomon@google.com30085192011-08-19 15:42:31 +00002058 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002059
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002060 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2061 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002062 fFontCache = new GrFontCache(fGpu);
2063
2064 fLastDrawCategory = kUnbuffered_DrawCategory;
2065
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002066 fDrawBuffer = NULL;
2067 fDrawBufferVBAllocPool = NULL;
2068 fDrawBufferIBAllocPool = NULL;
2069
bsalomon@google.com205d4602011-04-25 12:43:45 +00002070 fAAFillRectIndexBuffer = NULL;
2071 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002072
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002073 this->setupDrawBuffer();
2074}
2075
2076void GrContext::setupDrawBuffer() {
2077
2078 GrAssert(NULL == fDrawBuffer);
2079 GrAssert(NULL == fDrawBufferVBAllocPool);
2080 GrAssert(NULL == fDrawBufferIBAllocPool);
2081
bsalomon@google.com92edd312012-04-04 21:40:21 +00002082#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002083 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002084 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002085 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2086 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002087 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002088 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002089 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002090 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2091
bsalomon@google.com471d4712011-08-23 15:45:25 +00002092 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2093 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002094 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002095#endif
2096
2097#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002098 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002099#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002100 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002101 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002102}
2103
bsalomon@google.com27847de2011-02-22 20:59:41 +00002104GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002105#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002106 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002107#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002108 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002109#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002110}
2111
2112const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2113 return fGpu->getQuadIndexBuffer();
2114}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002115
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002116GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2117 GrAutoScratchTexture* temp1,
2118 GrAutoScratchTexture* temp2,
2119 const SkRect& rect,
2120 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002121 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002122 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2123 GrClip oldClip = this->getClip();
2124 GrTexture* origTexture = srcTexture;
2125 GrAutoMatrix avm(this, GrMatrix::I());
2126 SkIRect clearRect;
2127 int scaleFactorX, halfWidthX, kernelWidthX;
2128 int scaleFactorY, halfWidthY, kernelWidthY;
2129 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2130 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002131
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002132 SkRect srcRect(rect);
2133 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2134 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002135 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2136 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002137 this->setClip(srcRect);
2138
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002139 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2140 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2141 kAlpha_8_GrPixelConfig == srcTexture->config());
2142
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002143 const GrTextureDesc desc = {
2144 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002145 SkScalarFloorToInt(srcRect.width()),
2146 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002147 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002148 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002149 };
2150
2151 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002152 if (temp2) {
2153 temp2->set(this, desc);
2154 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002155
2156 GrTexture* dstTexture = temp1->texture();
2157 GrPaint paint;
2158 paint.reset();
2159 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2160
2161 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2162 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2163 srcTexture->height());
2164 this->setRenderTarget(dstTexture->asRenderTarget());
2165 SkRect dstRect(srcRect);
2166 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2167 i < scaleFactorY ? 0.5f : 1.0f);
2168 paint.setTexture(0, srcTexture);
2169 this->drawRectToRect(paint, dstRect, srcRect);
2170 srcRect = dstRect;
2171 SkTSwap(srcTexture, dstTexture);
2172 // If temp2 is non-NULL, don't render back to origTexture
2173 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2174 }
2175
2176 if (sigmaX > 0.0f) {
2177 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2178 float* kernelX = kernelStorageX.get();
2179 build_kernel(sigmaX, kernelX, kernelWidthX);
2180
2181 if (scaleFactorX > 1) {
2182 // Clear out a halfWidth to the right of the srcRect to prevent the
2183 // X convolution from reading garbage.
2184 clearRect = SkIRect::MakeXYWH(
2185 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2186 this->clear(&clearRect, 0x0);
2187 }
2188
2189 this->setRenderTarget(dstTexture->asRenderTarget());
2190 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2191 GrSamplerState::kX_FilterDirection);
2192 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002193 if (temp2 && dstTexture == origTexture) {
2194 dstTexture = temp2->texture();
2195 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002196 }
2197
2198 if (sigmaY > 0.0f) {
2199 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2200 float* kernelY = kernelStorageY.get();
2201 build_kernel(sigmaY, kernelY, kernelWidthY);
2202
2203 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2204 // Clear out a halfWidth below the srcRect to prevent the Y
2205 // convolution from reading garbage.
2206 clearRect = SkIRect::MakeXYWH(
2207 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2208 this->clear(&clearRect, 0x0);
2209 }
2210
2211 this->setRenderTarget(dstTexture->asRenderTarget());
2212 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2213 GrSamplerState::kY_FilterDirection);
2214 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002215 if (temp2 && dstTexture == origTexture) {
2216 dstTexture = temp2->texture();
2217 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002218 }
2219
2220 if (scaleFactorX > 1 || scaleFactorY > 1) {
2221 // Clear one pixel to the right and below, to accommodate bilinear
2222 // upsampling.
2223 clearRect = SkIRect::MakeXYWH(
2224 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2225 this->clear(&clearRect, 0x0);
2226 clearRect = SkIRect::MakeXYWH(
2227 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2228 this->clear(&clearRect, 0x0);
2229 // FIXME: This should be mitchell, not bilinear.
2230 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2231 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2232 srcTexture->height());
2233 this->setRenderTarget(dstTexture->asRenderTarget());
2234 paint.setTexture(0, srcTexture);
2235 SkRect dstRect(srcRect);
2236 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2237 this->drawRectToRect(paint, dstRect, srcRect);
2238 srcRect = dstRect;
2239 SkTSwap(srcTexture, dstTexture);
2240 }
2241 this->setRenderTarget(oldRenderTarget);
2242 this->setClip(oldClip);
2243 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002244}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002245
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002246GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2247 const GrRect& rect,
2248 GrTexture* temp1, GrTexture* temp2,
2249 GrSamplerState::Filter filter,
2250 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002251 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002252 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2253 GrAutoMatrix avm(this, GrMatrix::I());
2254 GrClip oldClip = this->getClip();
2255 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2256 if (radius.fWidth > 0) {
2257 this->setRenderTarget(temp1->asRenderTarget());
2258 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2259 GrSamplerState::kX_FilterDirection);
2260 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2261 rect.width(), radius.fHeight);
2262 this->clear(&clearRect, 0x0);
2263 srcTexture = temp1;
2264 }
2265 if (radius.fHeight > 0) {
2266 this->setRenderTarget(temp2->asRenderTarget());
2267 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2268 GrSamplerState::kY_FilterDirection);
2269 srcTexture = temp2;
2270 }
2271 this->setRenderTarget(oldRenderTarget);
2272 this->setClip(oldClip);
2273 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002274}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002275
2276///////////////////////////////////////////////////////////////////////////////