blob: f044909452c9cc2b780ed61aa341fbb26151f370 [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
1293// path bounds will be a subset of the clip bounds. returns false if path bounds
1294// would be empty.
1295bool 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,
1344 GrAutoScratchTexture* tex) {
1345 SkPaint paint;
1346 SkPath tmpPath;
1347 const SkPath* pathToDraw = &clientPath;
1348 if (kHairLine_PathFill == fill) {
1349 paint.setStyle(SkPaint::kStroke_Style);
1350 paint.setStrokeWidth(SK_Scalar1);
1351 } else {
1352 paint.setStyle(SkPaint::kFill_Style);
1353 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1354 if (skfill != pathToDraw->getFillType()) {
1355 tmpPath = *pathToDraw;
1356 tmpPath.setFillType(skfill);
1357 pathToDraw = &tmpPath;
1358 }
1359 }
1360 paint.setAntiAlias(true);
1361 paint.setColor(SK_ColorWHITE);
1362
1363 GrMatrix matrix = context->getMatrix();
1364 if (NULL != translate) {
1365 matrix.postTranslate(translate->fX, translate->fY);
1366 }
1367
1368 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1369 -pathDevBounds.fTop * SK_Scalar1);
1370 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1371 pathDevBounds.height());
1372
1373 SkBitmap bm;
1374 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1375 if (!bm.allocPixels()) {
1376 return false;
1377 }
1378 sk_bzero(bm.getPixels(), bm.getSafeSize());
1379
1380 SkDraw draw;
1381 sk_bzero(&draw, sizeof(draw));
1382 SkRasterClip rc(bounds);
1383 draw.fRC = &rc;
1384 draw.fClip = &rc.bwRgn();
1385 draw.fMatrix = &matrix;
1386 draw.fBitmap = &bm;
1387 draw.drawPath(*pathToDraw, paint);
1388
1389 const GrTextureDesc desc = {
1390 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001391 bounds.fRight,
1392 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001393 kAlpha_8_GrPixelConfig,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001394 0 // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001395 };
1396
1397 tex->set(context, desc);
1398 GrTexture* texture = tex->texture();
1399
1400 if (NULL == texture) {
1401 return false;
1402 }
1403 SkAutoLockPixels alp(bm);
1404 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1405 bm.getPixels(), bm.rowBytes());
1406 return true;
1407}
1408
1409void draw_around_inv_path(GrDrawTarget* target,
1410 GrDrawState::StageMask stageMask,
1411 const GrIRect& clipBounds,
1412 const GrIRect& pathBounds) {
1413 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1414 GrRect rect;
1415 if (clipBounds.fTop < pathBounds.fTop) {
1416 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1417 clipBounds.fRight, pathBounds.fTop);
1418 target->drawSimpleRect(rect, NULL, stageMask);
1419 }
1420 if (clipBounds.fLeft < pathBounds.fLeft) {
1421 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1422 pathBounds.fLeft, pathBounds.fBottom);
1423 target->drawSimpleRect(rect, NULL, stageMask);
1424 }
1425 if (clipBounds.fRight > pathBounds.fRight) {
1426 rect.iset(pathBounds.fRight, pathBounds.fTop,
1427 clipBounds.fRight, pathBounds.fBottom);
1428 target->drawSimpleRect(rect, NULL, stageMask);
1429 }
1430 if (clipBounds.fBottom > pathBounds.fBottom) {
1431 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1432 clipBounds.fRight, clipBounds.fBottom);
1433 target->drawSimpleRect(rect, NULL, stageMask);
1434 }
1435}
1436
1437}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001438
reed@google.com07f3ee12011-05-16 17:21:57 +00001439void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1440 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001442 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001443 if (GrIsFillInverted(fill)) {
1444 this->drawPaint(paint);
1445 }
1446 return;
1447 }
1448
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001449 // Note that below we may sw-rasterize the path into a scratch texture.
1450 // Scratch textures can be recycled after they are returned to the texture
1451 // cache. This presents a potential hazard for buffered drawing. However,
1452 // the writePixels that uploads to the scratch will perform a flush so we're
1453 // OK.
1454 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1455 kUnbuffered_DrawCategory;
1456 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001457 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001458
bsalomon@google.com289533a2011-10-27 12:34:25 +00001459 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1460
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001461 // An Assumption here is that path renderer would use some form of tweaking
1462 // the src color (either the input alpha or in the frag shader) to implement
1463 // aa. If we have some future driver-mojo path AA that can do the right
1464 // thing WRT to the blend then we'll need some query on the PR.
1465 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001466#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001467 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001468#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001469 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001470 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001471
bsalomon@google.com289533a2011-10-27 12:34:25 +00001472 GrPathRenderer* pr = NULL;
1473 if (prAA) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001474 pr = this->getPathRenderer(path, fill, target, true);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001475 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001476 GrAutoScratchTexture ast;
1477 GrIRect pathBounds, clipBounds;
1478 if (!get_path_and_clip_bounds(target, path, translate,
1479 &pathBounds, &clipBounds)) {
1480 return;
1481 }
bsalomon@google.com150d2842012-01-12 20:19:56 +00001482 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1483 fill, this,
1484 translate, &ast)) {
1485 GrTexture* texture = ast.texture();
1486 GrAssert(NULL != texture);
1487 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1488 enum {
1489 kPathMaskStage = GrPaint::kTotalStages,
1490 };
1491 target->drawState()->setTexture(kPathMaskStage, texture);
1492 target->drawState()->sampler(kPathMaskStage)->reset();
1493 GrScalar w = GrIntToScalar(pathBounds.width());
1494 GrScalar h = GrIntToScalar(pathBounds.height());
1495 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1496 h / texture->height());
1497 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1498 srcRects[kPathMaskStage] = &maskRect;
1499 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001500 GrRect dstRect = GrRect::MakeLTRB(
1501 SK_Scalar1* pathBounds.fLeft,
1502 SK_Scalar1* pathBounds.fTop,
1503 SK_Scalar1* pathBounds.fRight,
1504 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001505 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1506 target->drawState()->setTexture(kPathMaskStage, NULL);
1507 if (GrIsFillInverted(fill)) {
1508 draw_around_inv_path(target, stageMask,
1509 clipBounds, pathBounds);
1510 }
1511 return;
1512 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001513 }
1514 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001515 pr = this->getPathRenderer(path, fill, target, false);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001516 }
1517
bsalomon@google.com30085192011-08-19 15:42:31 +00001518 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001519#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001520 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001521#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001522 return;
1523 }
1524
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001525 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001526}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001527
bsalomon@google.com27847de2011-02-22 20:59:41 +00001528////////////////////////////////////////////////////////////////////////////////
1529
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001530void GrContext::flush(int flagsBitfield) {
1531 if (kDiscard_FlushBit & flagsBitfield) {
1532 fDrawBuffer->reset();
1533 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001534 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001535 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001536 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001537 fGpu->forceRenderTargetFlush();
1538 }
1539}
1540
bsalomon@google.com27847de2011-02-22 20:59:41 +00001541void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001542 if (fDrawBuffer) {
bsalomon@google.com97805382012-03-13 14:32:07 +00001543 fDrawBuffer->flushTo(fGpu);
junov@google.com53a55842011-06-08 22:55:10 +00001544 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001545}
1546
bsalomon@google.com6f379512011-11-16 20:36:03 +00001547void GrContext::internalWriteTexturePixels(GrTexture* texture,
1548 int left, int top,
1549 int width, int height,
1550 GrPixelConfig config,
1551 const void* buffer,
1552 size_t rowBytes,
1553 uint32_t flags) {
1554 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001555 ASSERT_OWNED_RESOURCE(texture);
1556
bsalomon@google.com6f379512011-11-16 20:36:03 +00001557 if (!(kDontFlush_PixelOpsFlag & flags)) {
1558 this->flush();
1559 }
1560 // TODO: use scratch texture to perform conversion
1561 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1562 GrPixelConfigIsUnpremultiplied(config)) {
1563 return;
1564 }
1565
1566 fGpu->writeTexturePixels(texture, left, top, width, height,
1567 config, buffer, rowBytes);
1568}
1569
1570bool GrContext::internalReadTexturePixels(GrTexture* texture,
1571 int left, int top,
1572 int width, int height,
1573 GrPixelConfig config,
1574 void* buffer,
1575 size_t rowBytes,
1576 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001577 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001578 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001579
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001580 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001581 GrRenderTarget* target = texture->asRenderTarget();
1582 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001583 return this->internalReadRenderTargetPixels(target,
1584 left, top, width, height,
1585 config, buffer, rowBytes,
1586 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001587 } else {
1588 return false;
1589 }
1590}
1591
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001592#include "SkConfig8888.h"
1593
1594namespace {
1595/**
1596 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1597 * formats are representable as Config8888 and so the function returns false
1598 * if the GrPixelConfig has no equivalent Config8888.
1599 */
1600bool grconfig_to_config8888(GrPixelConfig config,
1601 SkCanvas::Config8888* config8888) {
1602 switch (config) {
1603 case kRGBA_8888_PM_GrPixelConfig:
1604 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1605 return true;
1606 case kRGBA_8888_UPM_GrPixelConfig:
1607 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1608 return true;
1609 case kBGRA_8888_PM_GrPixelConfig:
1610 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1611 return true;
1612 case kBGRA_8888_UPM_GrPixelConfig:
1613 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1614 return true;
1615 default:
1616 return false;
1617 }
1618}
1619}
1620
bsalomon@google.com6f379512011-11-16 20:36:03 +00001621bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1622 int left, int top,
1623 int width, int height,
1624 GrPixelConfig config,
1625 void* buffer,
1626 size_t rowBytes,
1627 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001628 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001629 ASSERT_OWNED_RESOURCE(target);
1630
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001631 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001632 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001633 if (NULL == target) {
1634 return false;
1635 }
1636 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001637
bsalomon@google.com6f379512011-11-16 20:36:03 +00001638 if (!(kDontFlush_PixelOpsFlag & flags)) {
1639 this->flush();
1640 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001641
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001642 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1643 GrPixelConfigIsUnpremultiplied(config) &&
1644 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1645 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1646 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1647 !grconfig_to_config8888(config, &dstConfig8888)) {
1648 return false;
1649 }
1650 // do read back using target's own config
1651 this->internalReadRenderTargetPixels(target,
1652 left, top,
1653 width, height,
1654 target->config(),
1655 buffer, rowBytes,
1656 kDontFlush_PixelOpsFlag);
1657 // sw convert the pixels to unpremul config
1658 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1659 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1660 pixels, rowBytes, srcConfig8888,
1661 width, height);
1662 return true;
1663 }
1664
bsalomon@google.comc4364992011-11-07 15:54:49 +00001665 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001666 bool swapRAndB = NULL != src &&
1667 fGpu->preferredReadPixelsConfig(config) ==
1668 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001669
1670 bool flipY = NULL != src &&
1671 fGpu->readPixelsWillPayForYFlip(target, left, top,
1672 width, height, config,
1673 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001674 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1675 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001676
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001677 if (NULL == src && alphaConversion) {
1678 // we should fallback to cpu conversion here. This could happen when
1679 // we were given an external render target by the client that is not
1680 // also a texture (e.g. FBO 0 in GL)
1681 return false;
1682 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001683 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001684 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001685 if (flipY || swapRAndB || alphaConversion) {
1686 GrAssert(NULL != src);
1687 if (swapRAndB) {
1688 config = GrPixelConfigSwapRAndB(config);
1689 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001690 }
1691 // Make the scratch a render target because we don't have a robust
1692 // readTexturePixels as of yet (it calls this function).
1693 const GrTextureDesc desc = {
1694 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001695 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001696 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001697 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001698 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001699
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001700 // When a full readback is faster than a partial we could always make
1701 // the scratch exactly match the passed rect. However, if we see many
1702 // different size rectangles we will trash our texture cache and pay the
1703 // cost of creating and destroying many textures. So, we only request
1704 // an exact match when the caller is reading an entire RT.
1705 ScratchTexMatch match = kApprox_ScratchTexMatch;
1706 if (0 == left &&
1707 0 == top &&
1708 target->width() == width &&
1709 target->height() == height &&
1710 fGpu->fullReadPixelsIsFasterThanPartial()) {
1711 match = kExact_ScratchTexMatch;
1712 }
1713 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001714 GrTexture* texture = ast.texture();
1715 if (!texture) {
1716 return false;
1717 }
1718 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001719 GrAssert(NULL != target);
1720
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001721 GrDrawTarget::AutoStateRestore asr(fGpu,
1722 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001723 GrDrawState* drawState = fGpu->drawState();
1724 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001725
bsalomon@google.comc4364992011-11-07 15:54:49 +00001726 GrMatrix matrix;
1727 if (flipY) {
1728 matrix.setTranslate(SK_Scalar1 * left,
1729 SK_Scalar1 * (top + height));
1730 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1731 } else {
1732 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1733 }
1734 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001735 drawState->sampler(0)->reset(matrix);
1736 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001737 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001738 GrRect rect;
1739 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1740 fGpu->drawSimpleRect(rect, NULL, 0x1);
1741 left = 0;
1742 top = 0;
1743 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001744 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001745 left, top, width, height,
1746 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001747}
1748
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001749void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1750 GrAssert(target);
1751 ASSERT_OWNED_RESOURCE(target);
1752 // In the future we may track whether there are any pending draws to this
1753 // target. We don't today so we always perform a flush. We don't promise
1754 // this to our clients, though.
1755 this->flush();
1756 fGpu->resolveRenderTarget(target);
1757}
1758
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001759void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1760 if (NULL == src || NULL == dst) {
1761 return;
1762 }
1763 ASSERT_OWNED_RESOURCE(src);
1764
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001765 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001766 GrDrawState* drawState = fGpu->drawState();
1767 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001768 GrMatrix sampleM;
1769 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001770 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001771 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001772 SkRect rect = SkRect::MakeXYWH(0, 0,
1773 SK_Scalar1 * src->width(),
1774 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001775 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1776}
1777
bsalomon@google.com6f379512011-11-16 20:36:03 +00001778void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1779 int left, int top,
1780 int width, int height,
1781 GrPixelConfig config,
1782 const void* buffer,
1783 size_t rowBytes,
1784 uint32_t flags) {
1785 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001786 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001787
1788 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001789 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001790 if (NULL == target) {
1791 return;
1792 }
1793 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001794
1795 // TODO: when underlying api has a direct way to do this we should use it
1796 // (e.g. glDrawPixels on desktop GL).
1797
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001798 // If the RT is also a texture and we don't have to do PM/UPM conversion
1799 // then take the texture path, which we expect to be at least as fast or
1800 // faster since it doesn't use an intermediate texture as we do below.
1801
1802#if !GR_MAC_BUILD
1803 // At least some drivers on the Mac get confused when glTexImage2D is called
1804 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1805 // determine what OS versions and/or HW is affected.
1806 if (NULL != target->asTexture() &&
1807 GrPixelConfigIsUnpremultiplied(target->config()) ==
1808 GrPixelConfigIsUnpremultiplied(config)) {
1809
1810 this->internalWriteTexturePixels(target->asTexture(),
1811 left, top, width, height,
1812 config, buffer, rowBytes, flags);
1813 return;
1814 }
1815#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001816 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1817 GrPixelConfigIsUnpremultiplied(config) &&
1818 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1819 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1820 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1821 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1822 return;
1823 }
1824 // allocate a tmp buffer and sw convert the pixels to premul
1825 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1826 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1827 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1828 src, rowBytes, srcConfig8888,
1829 width, height);
1830 // upload the already premul pixels
1831 this->internalWriteRenderTargetPixels(target,
1832 left, top,
1833 width, height,
1834 target->config(),
1835 tmpPixels, 4 * width, flags);
1836 return;
1837 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001838
1839 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1840 GrPixelConfigSwapRAndB(config);
1841 if (swapRAndB) {
1842 config = GrPixelConfigSwapRAndB(config);
1843 }
1844
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001845 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001846 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001847 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001848 GrAutoScratchTexture ast(this, desc);
1849 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001850 if (NULL == texture) {
1851 return;
1852 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001853 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1854 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001855
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001856 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001857 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001858
1859 GrMatrix matrix;
1860 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001861 drawState->setViewMatrix(matrix);
1862 drawState->setRenderTarget(target);
1863 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001864
bsalomon@google.com5c638652011-07-18 19:31:59 +00001865 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001866 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1867 GrSamplerState::kNearest_Filter,
1868 matrix);
1869 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001870
1871 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1872 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001873 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001874 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1875 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001876 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001877 return;
1878 }
1879 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1880 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1881}
1882////////////////////////////////////////////////////////////////////////////////
1883
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001884void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001885
1886 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1887 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001888 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001889 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001890 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001891 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001892 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001893 }
1894
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001895 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001896
1897 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1898 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001899 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001900 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001901 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001902 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001903 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001904 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001905
1906 // disable all stages not accessible via the paint
1907 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001908 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001909 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001910
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001911 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001912
1913 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001914 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001915 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001916 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001917 }
1918 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001919 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001920 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001921 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001922 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001923 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001924 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1925 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001926 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001927 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001928 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001929 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1930 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1931 fDrawState->setCoverage(paint.fCoverage);
bsalomon@google.come79c8152012-03-29 19:07:12 +00001932#if GR_DEBUG
1933 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001934 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001935 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1936 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001937#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938}
1939
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001940GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001941 DrawCategory category) {
1942 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001943 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001944 fLastDrawCategory = category;
1945 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001946 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001947 GrDrawTarget* target = fGpu;
1948 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001949 case kUnbuffered_DrawCategory:
1950 target = fGpu;
1951 break;
1952 case kBuffered_DrawCategory:
1953 target = fDrawBuffer;
1954 fDrawBuffer->setClip(fGpu->getClip());
1955 break;
1956 default:
1957 GrCrash("Unexpected DrawCategory.");
1958 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001959 }
1960 return target;
1961}
1962
bsalomon@google.com289533a2011-10-27 12:34:25 +00001963GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1964 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001965 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001966 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001967 if (NULL == fPathRendererChain) {
1968 fPathRendererChain =
1969 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1970 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001971 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001972}
1973
bsalomon@google.com27847de2011-02-22 20:59:41 +00001974////////////////////////////////////////////////////////////////////////////////
1975
bsalomon@google.com27847de2011-02-22 20:59:41 +00001976void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001977 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001978 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001979 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001980 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001981 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982}
1983
1984GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001985 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001986}
1987
1988const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001989 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001990}
1991
1992const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001993 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001994}
1995
1996void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001997 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001998}
1999
2000void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002001 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002002}
2003
2004static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2005 intptr_t mask = 1 << shift;
2006 if (pred) {
2007 bits |= mask;
2008 } else {
2009 bits &= ~mask;
2010 }
2011 return bits;
2012}
2013
2014void GrContext::resetStats() {
2015 fGpu->resetStats();
2016}
2017
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002018const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002019 return fGpu->getStats();
2020}
2021
2022void GrContext::printStats() const {
2023 fGpu->printStats();
2024}
2025
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002026GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002027 fGpu = gpu;
2028 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002029 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002030
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002031 fDrawState = new GrDrawState();
2032 fGpu->setDrawState(fDrawState);
2033
bsalomon@google.com30085192011-08-19 15:42:31 +00002034 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002035
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002036 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2037 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002038 fFontCache = new GrFontCache(fGpu);
2039
2040 fLastDrawCategory = kUnbuffered_DrawCategory;
2041
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002042 fDrawBuffer = NULL;
2043 fDrawBufferVBAllocPool = NULL;
2044 fDrawBufferIBAllocPool = NULL;
2045
bsalomon@google.com205d4602011-04-25 12:43:45 +00002046 fAAFillRectIndexBuffer = NULL;
2047 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002048
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002049 this->setupDrawBuffer();
2050}
2051
2052void GrContext::setupDrawBuffer() {
2053
2054 GrAssert(NULL == fDrawBuffer);
2055 GrAssert(NULL == fDrawBufferVBAllocPool);
2056 GrAssert(NULL == fDrawBufferIBAllocPool);
2057
bsalomon@google.com92edd312012-04-04 21:40:21 +00002058#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002059 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002060 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002061 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2062 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002063 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002064 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002065 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002066 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2067
bsalomon@google.com471d4712011-08-23 15:45:25 +00002068 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2069 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002070 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002071#endif
2072
2073#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002074 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002075#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002076 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002077 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002078}
2079
bsalomon@google.com27847de2011-02-22 20:59:41 +00002080GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002081#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002082 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002083#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002084 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002085#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002086}
2087
2088const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2089 return fGpu->getQuadIndexBuffer();
2090}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002091
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002092GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2093 GrAutoScratchTexture* temp1,
2094 GrAutoScratchTexture* temp2,
2095 const SkRect& rect,
2096 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002097 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002098 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2099 GrClip oldClip = this->getClip();
2100 GrTexture* origTexture = srcTexture;
2101 GrAutoMatrix avm(this, GrMatrix::I());
2102 SkIRect clearRect;
2103 int scaleFactorX, halfWidthX, kernelWidthX;
2104 int scaleFactorY, halfWidthY, kernelWidthY;
2105 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2106 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002107
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002108 SkRect srcRect(rect);
2109 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2110 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002111 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2112 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002113 this->setClip(srcRect);
2114
2115 const GrTextureDesc desc = {
2116 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002117 SkScalarFloorToInt(srcRect.width()),
2118 SkScalarFloorToInt(srcRect.height()),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002119 kRGBA_8888_PM_GrPixelConfig,
2120 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002121 };
2122
2123 temp1->set(this, desc);
2124 if (temp2) temp2->set(this, desc);
2125
2126 GrTexture* dstTexture = temp1->texture();
2127 GrPaint paint;
2128 paint.reset();
2129 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2130
2131 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2132 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2133 srcTexture->height());
2134 this->setRenderTarget(dstTexture->asRenderTarget());
2135 SkRect dstRect(srcRect);
2136 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2137 i < scaleFactorY ? 0.5f : 1.0f);
2138 paint.setTexture(0, srcTexture);
2139 this->drawRectToRect(paint, dstRect, srcRect);
2140 srcRect = dstRect;
2141 SkTSwap(srcTexture, dstTexture);
2142 // If temp2 is non-NULL, don't render back to origTexture
2143 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2144 }
2145
2146 if (sigmaX > 0.0f) {
2147 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2148 float* kernelX = kernelStorageX.get();
2149 build_kernel(sigmaX, kernelX, kernelWidthX);
2150
2151 if (scaleFactorX > 1) {
2152 // Clear out a halfWidth to the right of the srcRect to prevent the
2153 // X convolution from reading garbage.
2154 clearRect = SkIRect::MakeXYWH(
2155 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2156 this->clear(&clearRect, 0x0);
2157 }
2158
2159 this->setRenderTarget(dstTexture->asRenderTarget());
2160 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2161 GrSamplerState::kX_FilterDirection);
2162 SkTSwap(srcTexture, dstTexture);
2163 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2164 }
2165
2166 if (sigmaY > 0.0f) {
2167 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2168 float* kernelY = kernelStorageY.get();
2169 build_kernel(sigmaY, kernelY, kernelWidthY);
2170
2171 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2172 // Clear out a halfWidth below the srcRect to prevent the Y
2173 // convolution from reading garbage.
2174 clearRect = SkIRect::MakeXYWH(
2175 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2176 this->clear(&clearRect, 0x0);
2177 }
2178
2179 this->setRenderTarget(dstTexture->asRenderTarget());
2180 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2181 GrSamplerState::kY_FilterDirection);
2182 SkTSwap(srcTexture, dstTexture);
2183 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2184 }
2185
2186 if (scaleFactorX > 1 || scaleFactorY > 1) {
2187 // Clear one pixel to the right and below, to accommodate bilinear
2188 // upsampling.
2189 clearRect = SkIRect::MakeXYWH(
2190 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2191 this->clear(&clearRect, 0x0);
2192 clearRect = SkIRect::MakeXYWH(
2193 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2194 this->clear(&clearRect, 0x0);
2195 // FIXME: This should be mitchell, not bilinear.
2196 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2197 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2198 srcTexture->height());
2199 this->setRenderTarget(dstTexture->asRenderTarget());
2200 paint.setTexture(0, srcTexture);
2201 SkRect dstRect(srcRect);
2202 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2203 this->drawRectToRect(paint, dstRect, srcRect);
2204 srcRect = dstRect;
2205 SkTSwap(srcTexture, dstTexture);
2206 }
2207 this->setRenderTarget(oldRenderTarget);
2208 this->setClip(oldClip);
2209 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002210}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002211
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002212GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2213 const GrRect& rect,
2214 GrTexture* temp1, GrTexture* temp2,
2215 GrSamplerState::Filter filter,
2216 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002217 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002218 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2219 GrAutoMatrix avm(this, GrMatrix::I());
2220 GrClip oldClip = this->getClip();
2221 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2222 if (radius.fWidth > 0) {
2223 this->setRenderTarget(temp1->asRenderTarget());
2224 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2225 GrSamplerState::kX_FilterDirection);
2226 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2227 rect.width(), radius.fHeight);
2228 this->clear(&clearRect, 0x0);
2229 srcTexture = temp1;
2230 }
2231 if (radius.fHeight > 0) {
2232 this->setRenderTarget(temp2->asRenderTarget());
2233 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2234 GrSamplerState::kY_FilterDirection);
2235 srcTexture = temp2;
2236 }
2237 this->setRenderTarget(oldRenderTarget);
2238 this->setClip(oldClip);
2239 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002240}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002241
2242///////////////////////////////////////////////////////////////////////////////