blob: 64ae1a5e4c6b92f256f93b58148f344395f80596 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
25#define DEFER_TEXT_RENDERING 1
26
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000027#define DEFER_PATHS 1
28
bsalomon@google.com27847de2011-02-22 20:59:41 +000029#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
30
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000031#define MAX_BLUR_SIGMA 4.0f
32
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000033
bsalomon@google.comd46e2422011-09-23 17:40:07 +000034// When we're using coverage AA but the blend is incompatible (given gpu
35// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000036#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000037
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000038static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
39static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000040
bsalomon@google.com60361492012-03-15 17:47:06 +000041static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000042static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
43
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000044// path rendering is the only thing we defer today that uses non-static indices
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000047
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.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
270 GrDrawTarget::AutoStateRestore asr(gpu);
271 GrDrawState* drawState = gpu->drawState();
272 GrRenderTarget* target = drawState->getRenderTarget();
273 drawState->reset();
274 drawState->setRenderTarget(target);
275 GrMatrix sampleM;
276 sampleM.setIDiv(texture->width(), texture->height());
277 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
278 sampleM);
279 drawState->sampler(0)->setMorphologyRadius(radius);
280 drawState->sampler(0)->setFilterDirection(direction);
281 drawState->setTexture(0, texture);
282 gpu->drawSimpleRect(rect, NULL, 1 << 0);
283}
284
285void convolve(GrGpu* gpu,
286 GrTexture* texture,
287 const SkRect& rect,
288 const float* kernel,
289 int kernelWidth,
290 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000291 GrDrawTarget::AutoStateRestore asr(gpu);
292 GrDrawState* drawState = gpu->drawState();
293 GrRenderTarget* target = drawState->getRenderTarget();
294 drawState->reset();
295 drawState->setRenderTarget(target);
296 GrMatrix sampleM;
297 sampleM.setIDiv(texture->width(), texture->height());
298 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
299 GrSamplerState::kConvolution_Filter,
300 sampleM);
301 drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel);
302 drawState->sampler(0)->setFilterDirection(direction);
303 drawState->setTexture(0, texture);
304 gpu->drawSimpleRect(rect, NULL, 1 << 0);
305}
306
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000307}
308
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000309GrContext::TextureCacheEntry GrContext::findAndLockTexture(
310 TextureKey key,
311 int width,
312 int height,
313 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000314 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000315 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000316 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000317 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
318 GrResourceCache::kNested_LockType));
319}
320
bsalomon@google.comfb309512011-11-30 14:13:48 +0000321bool GrContext::isTextureInCache(TextureKey key,
322 int width,
323 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000324 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000325 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000326 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000327 GrResourceKey resourceKey(v);
328 return fTextureCache->hasKey(resourceKey);
329}
330
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000331GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000332 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000333 uint32_t v[4];
334 gen_stencil_key_values(sb, v);
335 GrResourceKey resourceKey(v);
336 return fTextureCache->createAndLock(resourceKey, sb);
337}
338
339GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
340 int sampleCnt) {
341 uint32_t v[4];
342 gen_stencil_key_values(width, height, sampleCnt, v);
343 GrResourceKey resourceKey(v);
344 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
345 GrResourceCache::kSingle_LockType);
346 if (NULL != entry) {
347 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
348 return sb;
349 } else {
350 return NULL;
351 }
352}
353
354void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000355 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000356 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000357}
358
359static void stretchImage(void* dst,
360 int dstW,
361 int dstH,
362 void* src,
363 int srcW,
364 int srcH,
365 int bpp) {
366 GrFixed dx = (srcW << 16) / dstW;
367 GrFixed dy = (srcH << 16) / dstH;
368
369 GrFixed y = dy >> 1;
370
371 int dstXLimit = dstW*bpp;
372 for (int j = 0; j < dstH; ++j) {
373 GrFixed x = dx >> 1;
374 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
375 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
376 for (int i = 0; i < dstXLimit; i += bpp) {
377 memcpy((uint8_t*) dstRow + i,
378 (uint8_t*) srcRow + (x>>16)*bpp,
379 bpp);
380 x += dx;
381 }
382 y += dy;
383 }
384}
385
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000386GrContext::TextureCacheEntry GrContext::createAndLockTexture(
387 TextureKey key,
388 const GrSamplerState* sampler,
389 const GrTextureDesc& desc,
390 void* srcData,
391 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000392 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000393
394#if GR_DUMP_TEXTURE_UPLOAD
395 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
396#endif
397
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000398 TextureCacheEntry entry;
399 uint32_t v[4];
400 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000401 desc.fWidth, desc.fHeight,
402 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000404
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000405 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000406 GrAssert(NULL != sampler);
407 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
408 desc.fWidth,
409 desc.fHeight,
410 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000411
412 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000413 clampEntry = this->createAndLockTexture(key, NULL, desc,
414 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000415 GrAssert(NULL != clampEntry.texture());
416 if (NULL == clampEntry.texture()) {
417 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418 }
419 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000420 GrTextureDesc rtDesc = desc;
421 rtDesc.fFlags = rtDesc.fFlags |
422 kRenderTarget_GrTextureFlagBit |
423 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000424 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
425 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000426
427 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
428
429 if (NULL != texture) {
430 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000431 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000432 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000433 drawState->setRenderTarget(texture->asRenderTarget());
434 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000435
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000436 GrSamplerState::Filter filter;
437 // if filtering is not desired then we want to ensure all
438 // texels in the resampled image are copies of texels from
439 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000440 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000441 filter = GrSamplerState::kNearest_Filter;
442 } else {
443 filter = GrSamplerState::kBilinear_Filter;
444 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000445 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
446 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000447
448 static const GrVertexLayout layout =
449 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
450 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
451
452 if (arg.succeeded()) {
453 GrPoint* verts = (GrPoint*) arg.vertices();
454 verts[0].setIRectFan(0, 0,
455 texture->width(),
456 texture->height(),
457 2*sizeof(GrPoint));
458 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
459 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
460 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000461 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000462 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000463 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000464 } else {
465 // TODO: Our CPU stretch doesn't filter. But we create separate
466 // stretched textures when the sampler state is either filtered or
467 // not. Either implement filtered stretch blit on CPU or just create
468 // one when FBO case fails.
469
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000470 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000471 // no longer need to clamp at min RT size.
472 rtDesc.fWidth = GrNextPow2(desc.fWidth);
473 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000474 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000475 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000476 rtDesc.fWidth *
477 rtDesc.fHeight);
478 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
479 srcData, desc.fWidth, desc.fHeight, bpp);
480
481 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
482
483 GrTexture* texture = fGpu->createTexture(rtDesc,
484 stretchedPixels.get(),
485 stretchedRowBytes);
486 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000487 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000488 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000489 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000490
491 } else {
492 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
493 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000494 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000495 }
496 }
497 return entry;
498}
499
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500namespace {
501inline void gen_scratch_tex_key_values(const GrGpu* gpu,
502 const GrTextureDesc& desc,
503 uint32_t v[4]) {
504 // Instead of a client-provided key of the texture contents
505 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000506 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000507 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000508 // this code path isn't friendly to tiling with NPOT restricitons
509 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000510 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000511 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000512}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000513}
514
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000515GrContext::TextureCacheEntry GrContext::lockScratchTexture(
516 const GrTextureDesc& inDesc,
517 ScratchTexMatch match) {
518
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000519 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000520 if (kExact_ScratchTexMatch != match) {
521 // bin by pow2 with a reasonable min
522 static const int MIN_SIZE = 256;
523 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
524 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
525 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000526
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000527 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000528 int origWidth = desc.fWidth;
529 int origHeight = desc.fHeight;
530 bool doubledW = false;
531 bool doubledH = false;
532
533 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000534 uint32_t v[4];
535 gen_scratch_tex_key_values(fGpu, desc, v);
536 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000537 entry = fTextureCache->findAndLock(key,
538 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000539 // if we miss, relax the fit of the flags...
540 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000541 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000542 break;
543 }
544 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
545 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
546 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
547 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
548 } else if (!doubledW) {
549 desc.fFlags = inDesc.fFlags;
550 desc.fWidth *= 2;
551 doubledW = true;
552 } else if (!doubledH) {
553 desc.fFlags = inDesc.fFlags;
554 desc.fWidth = origWidth;
555 desc.fHeight *= 2;
556 doubledH = true;
557 } else {
558 break;
559 }
560
561 } while (true);
562
563 if (NULL == entry) {
564 desc.fFlags = inDesc.fFlags;
565 desc.fWidth = origWidth;
566 desc.fHeight = origHeight;
567 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
568 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000569 uint32_t v[4];
570 gen_scratch_tex_key_values(fGpu, desc, v);
571 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000572 entry = fTextureCache->createAndLock(key, texture);
573 }
574 }
575
576 // If the caller gives us the same desc/sampler twice we don't want
577 // to return the same texture the second time (unless it was previously
578 // released). So we detach the entry from the cache and reattach at release.
579 if (NULL != entry) {
580 fTextureCache->detach(entry);
581 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000582 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000583}
584
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000585void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000586 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000587 // If this is a scratch texture we detached it from the cache
588 // while it was locked (to avoid two callers simultaneously getting
589 // the same texture).
590 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
591 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000592 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000593 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000594 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595}
596
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000597GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000598 void* srcData,
599 size_t rowBytes) {
600 return fGpu->createTexture(desc, srcData, rowBytes);
601}
602
603void GrContext::getTextureCacheLimits(int* maxTextures,
604 size_t* maxTextureBytes) const {
605 fTextureCache->getLimits(maxTextures, maxTextureBytes);
606}
607
608void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
609 fTextureCache->setLimits(maxTextures, maxTextureBytes);
610}
611
bsalomon@google.com91958362011-06-13 17:58:13 +0000612int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000613 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000614}
615
616int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000617 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000618}
619
620///////////////////////////////////////////////////////////////////////////////
621
bsalomon@google.come269f212011-11-07 13:29:52 +0000622GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
623 return fGpu->createPlatformTexture(desc);
624}
625
626GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
627 return fGpu->createPlatformRenderTarget(desc);
628}
629
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000630///////////////////////////////////////////////////////////////////////////////
631
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000632bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000633 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000634 const GrDrawTarget::Caps& caps = fGpu->getCaps();
635 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000636 return false;
637 }
638
bsalomon@google.com27847de2011-02-22 20:59:41 +0000639 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
640
641 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000642 bool tiled = NULL != sampler &&
643 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
644 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000645 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000646 return false;
647 }
648 }
649 return true;
650}
651
652////////////////////////////////////////////////////////////////////////////////
653
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000654const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
655
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656void GrContext::setClip(const GrClip& clip) {
657 fGpu->setClip(clip);
bsalomon@google.com5b819c12012-03-28 21:34:22 +0000658 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000659}
660
661void GrContext::setClip(const GrIRect& rect) {
662 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000663 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000664 fGpu->setClip(clip);
665}
666
667////////////////////////////////////////////////////////////////////////////////
668
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000669void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000670 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000671 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000672}
673
674void GrContext::drawPaint(const GrPaint& paint) {
675 // set rect to be big enough to fill the space, but not super-huge, so we
676 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000677 GrRect r;
678 r.setLTRB(0, 0,
679 GrIntToScalar(getRenderTarget()->width()),
680 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000681 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000682 SkTLazy<GrPaint> tmpPaint;
683 const GrPaint* p = &paint;
bsalomon@google.com5b819c12012-03-28 21:34:22 +0000684 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000685 GrAutoMatrix am;
686
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000687 // We attempt to map r by the inverse matrix and draw that. mapRect will
688 // map the four corners and bound them with a new rect. This will not
689 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000690 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +0000691 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000692 GrPrintf("Could not invert matrix");
693 return;
694 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000695 inverse.mapRect(&r);
696 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000697 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +0000698 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000699 GrPrintf("Could not invert matrix");
700 return;
701 }
702 tmpPaint.set(paint);
703 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
704 p = tmpPaint.get();
705 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000706 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000707 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000708 // by definition this fills the entire clip, no need for AA
709 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000710 if (!tmpPaint.isValid()) {
711 tmpPaint.set(paint);
712 p = tmpPaint.get();
713 }
714 GrAssert(p == tmpPaint.get());
715 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000716 }
717 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000718}
719
bsalomon@google.com205d4602011-04-25 12:43:45 +0000720////////////////////////////////////////////////////////////////////////////////
721
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000722namespace {
723inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
724 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
725}
726}
727
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000728////////////////////////////////////////////////////////////////////////////////
729
bsalomon@google.com27847de2011-02-22 20:59:41 +0000730/* create a triangle strip that strokes the specified triangle. There are 8
731 unique vertices, but we repreat the last 2 to close up. Alternatively we
732 could use an indices array, and then only send 8 verts, but not sure that
733 would be faster.
734 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000735static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000736 GrScalar width) {
737 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000738 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000739
740 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
741 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
742 verts[2].set(rect.fRight - rad, rect.fTop + rad);
743 verts[3].set(rect.fRight + rad, rect.fTop - rad);
744 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
745 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
746 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
747 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
748 verts[8] = verts[0];
749 verts[9] = verts[1];
750}
751
bsalomon@google.com205d4602011-04-25 12:43:45 +0000752static void setInsetFan(GrPoint* pts, size_t stride,
753 const GrRect& r, GrScalar dx, GrScalar dy) {
754 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
755}
756
757static const uint16_t gFillAARectIdx[] = {
758 0, 1, 5, 5, 4, 0,
759 1, 2, 6, 6, 5, 1,
760 2, 3, 7, 7, 6, 2,
761 3, 0, 4, 4, 7, 3,
762 4, 5, 6, 6, 7, 4,
763};
764
765int GrContext::aaFillRectIndexCount() const {
766 return GR_ARRAY_COUNT(gFillAARectIdx);
767}
768
769GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
770 if (NULL == fAAFillRectIndexBuffer) {
771 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
772 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000773 if (NULL != fAAFillRectIndexBuffer) {
774 #if GR_DEBUG
775 bool updated =
776 #endif
777 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
778 sizeof(gFillAARectIdx));
779 GR_DEBUGASSERT(updated);
780 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000781 }
782 return fAAFillRectIndexBuffer;
783}
784
785static const uint16_t gStrokeAARectIdx[] = {
786 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
787 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
788 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
789 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
790
791 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
792 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
793 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
794 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
795
796 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
797 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
798 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
799 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
800};
801
802int GrContext::aaStrokeRectIndexCount() const {
803 return GR_ARRAY_COUNT(gStrokeAARectIdx);
804}
805
806GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
807 if (NULL == fAAStrokeRectIndexBuffer) {
808 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
809 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000810 if (NULL != fAAStrokeRectIndexBuffer) {
811 #if GR_DEBUG
812 bool updated =
813 #endif
814 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
815 sizeof(gStrokeAARectIdx));
816 GR_DEBUGASSERT(updated);
817 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000818 }
819 return fAAStrokeRectIndexBuffer;
820}
821
bsalomon@google.coma3108262011-10-10 14:08:47 +0000822static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
823 bool useCoverage) {
824 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000825 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000826 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000827 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
828 }
829 }
830 if (useCoverage) {
831 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
832 } else {
833 layout |= GrDrawTarget::kColor_VertexLayoutBit;
834 }
835 return layout;
836}
837
bsalomon@google.com205d4602011-04-25 12:43:45 +0000838void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000839 const GrRect& devRect,
840 bool useVertexCoverage) {
841 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000842
843 size_t vsize = GrDrawTarget::VertexSize(layout);
844
845 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000846 if (!geo.succeeded()) {
847 GrPrintf("Failed to get space for vertices!\n");
848 return;
849 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000850 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
851 if (NULL == indexBuffer) {
852 GrPrintf("Failed to create index buffer!\n");
853 return;
854 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000855
856 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
857
858 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
859 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
860
861 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
862 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
863
864 verts += sizeof(GrPoint);
865 for (int i = 0; i < 4; ++i) {
866 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
867 }
868
bsalomon@google.coma3108262011-10-10 14:08:47 +0000869 GrColor innerColor;
870 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000871 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000872 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000873 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000874 }
875
bsalomon@google.com205d4602011-04-25 12:43:45 +0000876 verts += 4 * vsize;
877 for (int i = 0; i < 4; ++i) {
878 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
879 }
880
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000881 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000882
883 target->drawIndexed(kTriangles_PrimitiveType, 0,
884 0, 8, this->aaFillRectIndexCount());
885}
886
bsalomon@google.coma3108262011-10-10 14:08:47 +0000887void GrContext::strokeAARect(GrDrawTarget* target,
888 const GrRect& devRect,
889 const GrVec& devStrokeSize,
890 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000891 const GrScalar& dx = devStrokeSize.fX;
892 const GrScalar& dy = devStrokeSize.fY;
893 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
894 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
895
bsalomon@google.com205d4602011-04-25 12:43:45 +0000896 GrScalar spare;
897 {
898 GrScalar w = devRect.width() - dx;
899 GrScalar h = devRect.height() - dy;
900 spare = GrMin(w, h);
901 }
902
903 if (spare <= 0) {
904 GrRect r(devRect);
905 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000906 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000907 return;
908 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000909 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000910 size_t vsize = GrDrawTarget::VertexSize(layout);
911
912 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000913 if (!geo.succeeded()) {
914 GrPrintf("Failed to get space for vertices!\n");
915 return;
916 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000917 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
918 if (NULL == indexBuffer) {
919 GrPrintf("Failed to create index buffer!\n");
920 return;
921 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922
923 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
924
925 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
926 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
927 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
928 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
929
930 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
931 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
932 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
933 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
934
935 verts += sizeof(GrPoint);
936 for (int i = 0; i < 4; ++i) {
937 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
938 }
939
bsalomon@google.coma3108262011-10-10 14:08:47 +0000940 GrColor innerColor;
941 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000942 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000943 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000944 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000945 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000946 verts += 4 * vsize;
947 for (int i = 0; i < 8; ++i) {
948 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
949 }
950
951 verts += 8 * vsize;
952 for (int i = 0; i < 8; ++i) {
953 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
954 }
955
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000956 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000957 target->drawIndexed(kTriangles_PrimitiveType,
958 0, 0, 16, aaStrokeRectIndexCount());
959}
960
reed@google.com20efde72011-05-09 17:00:02 +0000961/**
962 * Returns true if the rects edges are integer-aligned.
963 */
964static bool isIRect(const GrRect& r) {
965 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
966 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
967}
968
bsalomon@google.com205d4602011-04-25 12:43:45 +0000969static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000970 const GrRect& rect,
971 GrScalar width,
972 const GrMatrix* matrix,
973 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000974 GrRect* devRect,
975 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000976 // we use a simple coverage ramp to do aa on axis-aligned rects
977 // we check if the rect will be axis-aligned, and the rect won't land on
978 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000979
bsalomon@google.coma3108262011-10-10 14:08:47 +0000980 // we are keeping around the "tweak the alpha" trick because
981 // it is our only hope for the fixed-pipe implementation.
982 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000983 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000984 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000985 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000986 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000987#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000988 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000989#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000990 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000991 } else {
992 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000993 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000994 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000995 const GrDrawState& drawState = target->getDrawState();
996 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000997 return false;
998 }
999
bsalomon@google.com471d4712011-08-23 15:45:25 +00001000 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001001 return false;
1002 }
1003
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001004 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001005 return false;
1006 }
1007
1008 if (NULL != matrix &&
1009 !matrix->preservesAxisAlignment()) {
1010 return false;
1011 }
1012
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001013 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001014 if (NULL != matrix) {
1015 combinedMatrix->preConcat(*matrix);
1016 GrAssert(combinedMatrix->preservesAxisAlignment());
1017 }
1018
1019 combinedMatrix->mapRect(devRect, rect);
1020 devRect->sort();
1021
1022 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001023 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001024 } else {
1025 return true;
1026 }
1027}
1028
bsalomon@google.com27847de2011-02-22 20:59:41 +00001029void GrContext::drawRect(const GrPaint& paint,
1030 const GrRect& rect,
1031 GrScalar width,
1032 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001033 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001034
1035 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001036 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001037
bsalomon@google.com205d4602011-04-25 12:43:45 +00001038 GrRect devRect = rect;
1039 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001040 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001041 bool needAA = paint.fAntiAlias &&
1042 !this->getRenderTarget()->isMultisampled();
1043 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1044 &combinedMatrix, &devRect,
1045 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001046
1047 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001048 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001049 if (width >= 0) {
1050 GrVec strokeSize;;
1051 if (width > 0) {
1052 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001053 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054 strokeSize.setAbs(strokeSize);
1055 } else {
1056 strokeSize.set(GR_Scalar1, GR_Scalar1);
1057 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001060 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061 }
1062 return;
1063 }
1064
bsalomon@google.com27847de2011-02-22 20:59:41 +00001065 if (width >= 0) {
1066 // TODO: consider making static vertex buffers for these cases.
1067 // Hairline could be done by just adding closing vertex to
1068 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001069 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1070
bsalomon@google.com27847de2011-02-22 20:59:41 +00001071 static const int worstCaseVertCount = 10;
1072 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1073
1074 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001075 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001076 return;
1077 }
1078
1079 GrPrimitiveType primType;
1080 int vertCount;
1081 GrPoint* vertex = geo.positions();
1082
1083 if (width > 0) {
1084 vertCount = 10;
1085 primType = kTriangleStrip_PrimitiveType;
1086 setStrokeRectStrip(vertex, rect, width);
1087 } else {
1088 // hairline
1089 vertCount = 5;
1090 primType = kLineStrip_PrimitiveType;
1091 vertex[0].set(rect.fLeft, rect.fTop);
1092 vertex[1].set(rect.fRight, rect.fTop);
1093 vertex[2].set(rect.fRight, rect.fBottom);
1094 vertex[3].set(rect.fLeft, rect.fBottom);
1095 vertex[4].set(rect.fLeft, rect.fTop);
1096 }
1097
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001098 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001099 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001100 GrDrawState* drawState = target->drawState();
1101 avmr.set(drawState);
1102 drawState->preConcatViewMatrix(*matrix);
1103 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001104 }
1105
1106 target->drawNonIndexed(primType, 0, vertCount);
1107 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001108#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001109 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001110 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1111 if (NULL == sqVB) {
1112 GrPrintf("Failed to create static rect vb.\n");
1113 return;
1114 }
1115 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001116 GrDrawState* drawState = target->drawState();
1117 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001118 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001119 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001120 0, rect.height(), rect.fTop,
1121 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001122
1123 if (NULL != matrix) {
1124 m.postConcat(*matrix);
1125 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001126 drawState->preConcatViewMatrix(m);
1127 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001128
bsalomon@google.com27847de2011-02-22 20:59:41 +00001129 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001130#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001131 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001132#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001133 }
1134}
1135
1136void GrContext::drawRectToRect(const GrPaint& paint,
1137 const GrRect& dstRect,
1138 const GrRect& srcRect,
1139 const GrMatrix* dstMatrix,
1140 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001141 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001142
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001143 // srcRect refers to paint's first texture
1144 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001145 drawRect(paint, dstRect, -1, dstMatrix);
1146 return;
1147 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001148
bsalomon@google.com27847de2011-02-22 20:59:41 +00001149 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1150
1151#if GR_STATIC_RECT_VB
1152 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001153 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001154 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001155 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001156
1157 GrMatrix m;
1158
1159 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1160 0, dstRect.height(), dstRect.fTop,
1161 0, 0, GrMatrix::I()[8]);
1162 if (NULL != dstMatrix) {
1163 m.postConcat(*dstMatrix);
1164 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001165 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001166
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001167 // srcRect refers to first stage
1168 int otherStageMask = paint.getActiveStageMask() &
1169 (~(1 << GrPaint::kFirstTextureStage));
1170 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001171 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001172 }
1173
bsalomon@google.com27847de2011-02-22 20:59:41 +00001174 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1175 0, srcRect.height(), srcRect.fTop,
1176 0, 0, GrMatrix::I()[8]);
1177 if (NULL != srcMatrix) {
1178 m.postConcat(*srcMatrix);
1179 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001180 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001181
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001182 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1183 if (NULL == sqVB) {
1184 GrPrintf("Failed to create static rect vb.\n");
1185 return;
1186 }
1187 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001188 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1189#else
1190
1191 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001192#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001194#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001195 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1196#endif
1197
tomhudson@google.com93813632011-10-27 20:21:16 +00001198 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1199 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001200 srcRects[0] = &srcRect;
1201 srcMatrices[0] = srcMatrix;
1202
1203 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1204#endif
1205}
1206
1207void GrContext::drawVertices(const GrPaint& paint,
1208 GrPrimitiveType primitiveType,
1209 int vertexCount,
1210 const GrPoint positions[],
1211 const GrPoint texCoords[],
1212 const GrColor colors[],
1213 const uint16_t indices[],
1214 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001215 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001216
1217 GrDrawTarget::AutoReleaseGeometry geo;
1218
1219 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1220
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001221 bool hasTexCoords[GrPaint::kTotalStages] = {
1222 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1223 0 // remaining stages use positions
1224 };
1225
1226 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227
1228 if (NULL != colors) {
1229 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001230 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001231 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001232
1233 if (sizeof(GrPoint) != vertexSize) {
1234 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001235 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001236 return;
1237 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001238 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001239 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001240 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1241 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001242 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001243 NULL,
1244 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001245 void* curVertex = geo.vertices();
1246
1247 for (int i = 0; i < vertexCount; ++i) {
1248 *((GrPoint*)curVertex) = positions[i];
1249
1250 if (texOffsets[0] > 0) {
1251 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1252 }
1253 if (colorOffset > 0) {
1254 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1255 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001256 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001257 }
1258 } else {
1259 target->setVertexSourceToArray(layout, positions, vertexCount);
1260 }
1261
bsalomon@google.com91958362011-06-13 17:58:13 +00001262 // we don't currently apply offscreen AA to this path. Need improved
1263 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001264
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001265 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001266 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001267 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001268 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001269 target->drawNonIndexed(primitiveType, 0, vertexCount);
1270 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001271}
1272
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001273///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001274#include "SkDraw.h"
1275#include "SkRasterClip.h"
1276
1277namespace {
1278
1279SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1280 switch (fill) {
1281 case kWinding_PathFill:
1282 return SkPath::kWinding_FillType;
1283 case kEvenOdd_PathFill:
1284 return SkPath::kEvenOdd_FillType;
1285 case kInverseWinding_PathFill:
1286 return SkPath::kInverseWinding_FillType;
1287 case kInverseEvenOdd_PathFill:
1288 return SkPath::kInverseEvenOdd_FillType;
1289 default:
1290 GrCrash("Unexpected fill.");
1291 return SkPath::kWinding_FillType;
1292 }
1293}
1294
1295// gets device coord bounds of path (not considering the fill) and clip. The
1296// path bounds will be a subset of the clip bounds. returns false if path bounds
1297// would be empty.
1298bool get_path_and_clip_bounds(const GrDrawTarget* target,
1299 const GrPath& path,
1300 const GrVec* translate,
1301 GrIRect* pathBounds,
1302 GrIRect* clipBounds) {
1303 // compute bounds as intersection of rt size, clip, and path
1304 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1305 if (NULL == rt) {
1306 return false;
1307 }
1308 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1309 const GrClip& clip = target->getClip();
1310 if (clip.hasConservativeBounds()) {
1311 clip.getConservativeBounds().roundOut(clipBounds);
1312 if (!pathBounds->intersect(*clipBounds)) {
1313 return false;
1314 }
1315 } else {
1316 // pathBounds is currently the rt extent, set clip bounds to that rect.
1317 *clipBounds = *pathBounds;
1318 }
1319 GrRect pathSBounds = path.getBounds();
1320 if (!pathSBounds.isEmpty()) {
1321 if (NULL != translate) {
1322 pathSBounds.offset(*translate);
1323 }
1324 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1325 pathSBounds);
1326 GrIRect pathIBounds;
1327 pathSBounds.roundOut(&pathIBounds);
1328 if (!pathBounds->intersect(pathIBounds)) {
1329 return false;
1330 }
1331 } else {
1332 return false;
1333 }
1334 return true;
1335}
1336
1337/**
1338 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1339 * scratch texture.
1340 */
1341
1342bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1343 const GrIRect& pathDevBounds,
1344 GrPathFill fill,
1345 GrContext* context,
1346 const GrPoint* translate,
1347 GrAutoScratchTexture* tex) {
1348 SkPaint paint;
1349 SkPath tmpPath;
1350 const SkPath* pathToDraw = &clientPath;
1351 if (kHairLine_PathFill == fill) {
1352 paint.setStyle(SkPaint::kStroke_Style);
1353 paint.setStrokeWidth(SK_Scalar1);
1354 } else {
1355 paint.setStyle(SkPaint::kFill_Style);
1356 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1357 if (skfill != pathToDraw->getFillType()) {
1358 tmpPath = *pathToDraw;
1359 tmpPath.setFillType(skfill);
1360 pathToDraw = &tmpPath;
1361 }
1362 }
1363 paint.setAntiAlias(true);
1364 paint.setColor(SK_ColorWHITE);
1365
1366 GrMatrix matrix = context->getMatrix();
1367 if (NULL != translate) {
1368 matrix.postTranslate(translate->fX, translate->fY);
1369 }
1370
1371 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1372 -pathDevBounds.fTop * SK_Scalar1);
1373 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1374 pathDevBounds.height());
1375
1376 SkBitmap bm;
1377 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1378 if (!bm.allocPixels()) {
1379 return false;
1380 }
1381 sk_bzero(bm.getPixels(), bm.getSafeSize());
1382
1383 SkDraw draw;
1384 sk_bzero(&draw, sizeof(draw));
1385 SkRasterClip rc(bounds);
1386 draw.fRC = &rc;
1387 draw.fClip = &rc.bwRgn();
1388 draw.fMatrix = &matrix;
1389 draw.fBitmap = &bm;
1390 draw.drawPath(*pathToDraw, paint);
1391
1392 const GrTextureDesc desc = {
1393 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001394 bounds.fRight,
1395 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001396 kAlpha_8_GrPixelConfig,
1397 {0} // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001398 };
1399
1400 tex->set(context, desc);
1401 GrTexture* texture = tex->texture();
1402
1403 if (NULL == texture) {
1404 return false;
1405 }
1406 SkAutoLockPixels alp(bm);
1407 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1408 bm.getPixels(), bm.rowBytes());
1409 return true;
1410}
1411
1412void draw_around_inv_path(GrDrawTarget* target,
1413 GrDrawState::StageMask stageMask,
1414 const GrIRect& clipBounds,
1415 const GrIRect& pathBounds) {
1416 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1417 GrRect rect;
1418 if (clipBounds.fTop < pathBounds.fTop) {
1419 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1420 clipBounds.fRight, pathBounds.fTop);
1421 target->drawSimpleRect(rect, NULL, stageMask);
1422 }
1423 if (clipBounds.fLeft < pathBounds.fLeft) {
1424 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1425 pathBounds.fLeft, pathBounds.fBottom);
1426 target->drawSimpleRect(rect, NULL, stageMask);
1427 }
1428 if (clipBounds.fRight > pathBounds.fRight) {
1429 rect.iset(pathBounds.fRight, pathBounds.fTop,
1430 clipBounds.fRight, pathBounds.fBottom);
1431 target->drawSimpleRect(rect, NULL, stageMask);
1432 }
1433 if (clipBounds.fBottom > pathBounds.fBottom) {
1434 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1435 clipBounds.fRight, clipBounds.fBottom);
1436 target->drawSimpleRect(rect, NULL, stageMask);
1437 }
1438}
1439
1440}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441
reed@google.com07f3ee12011-05-16 17:21:57 +00001442void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1443 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001444
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001445 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001446 if (GrIsFillInverted(fill)) {
1447 this->drawPaint(paint);
1448 }
1449 return;
1450 }
1451
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001452 // Note that below we may sw-rasterize the path into a scratch texture.
1453 // Scratch textures can be recycled after they are returned to the texture
1454 // cache. This presents a potential hazard for buffered drawing. However,
1455 // the writePixels that uploads to the scratch will perform a flush so we're
1456 // OK.
1457 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1458 kUnbuffered_DrawCategory;
1459 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001460 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001461
bsalomon@google.com289533a2011-10-27 12:34:25 +00001462 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1463
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001464 // An Assumption here is that path renderer would use some form of tweaking
1465 // the src color (either the input alpha or in the frag shader) to implement
1466 // aa. If we have some future driver-mojo path AA that can do the right
1467 // thing WRT to the blend then we'll need some query on the PR.
1468 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001469#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001470 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001471#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001472 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001473 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001474
bsalomon@google.com289533a2011-10-27 12:34:25 +00001475 GrPathRenderer* pr = NULL;
1476 if (prAA) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001477 pr = this->getPathRenderer(path, fill, target, true);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001478 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001479 GrAutoScratchTexture ast;
1480 GrIRect pathBounds, clipBounds;
1481 if (!get_path_and_clip_bounds(target, path, translate,
1482 &pathBounds, &clipBounds)) {
1483 return;
1484 }
bsalomon@google.com150d2842012-01-12 20:19:56 +00001485 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1486 fill, this,
1487 translate, &ast)) {
1488 GrTexture* texture = ast.texture();
1489 GrAssert(NULL != texture);
1490 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1491 enum {
1492 kPathMaskStage = GrPaint::kTotalStages,
1493 };
1494 target->drawState()->setTexture(kPathMaskStage, texture);
1495 target->drawState()->sampler(kPathMaskStage)->reset();
1496 GrScalar w = GrIntToScalar(pathBounds.width());
1497 GrScalar h = GrIntToScalar(pathBounds.height());
1498 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1499 h / texture->height());
1500 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1501 srcRects[kPathMaskStage] = &maskRect;
1502 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001503 GrRect dstRect = GrRect::MakeLTRB(
1504 SK_Scalar1* pathBounds.fLeft,
1505 SK_Scalar1* pathBounds.fTop,
1506 SK_Scalar1* pathBounds.fRight,
1507 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001508 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1509 target->drawState()->setTexture(kPathMaskStage, NULL);
1510 if (GrIsFillInverted(fill)) {
1511 draw_around_inv_path(target, stageMask,
1512 clipBounds, pathBounds);
1513 }
1514 return;
1515 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001516 }
1517 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001518 pr = this->getPathRenderer(path, fill, target, false);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001519 }
1520
bsalomon@google.com30085192011-08-19 15:42:31 +00001521 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001522#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001523 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001524#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001525 return;
1526 }
1527
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001528 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001529}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001530
bsalomon@google.com27847de2011-02-22 20:59:41 +00001531////////////////////////////////////////////////////////////////////////////////
1532
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001533void GrContext::flush(int flagsBitfield) {
1534 if (kDiscard_FlushBit & flagsBitfield) {
1535 fDrawBuffer->reset();
1536 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001537 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001538 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001539 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001540 fGpu->forceRenderTargetFlush();
1541 }
1542}
1543
1544void GrContext::flushText() {
1545 if (kText_DrawCategory == fLastDrawCategory) {
1546 flushDrawBuffer();
1547 }
1548}
1549
1550void GrContext::flushDrawBuffer() {
1551#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001552 if (fDrawBuffer) {
bsalomon@google.com97805382012-03-13 14:32:07 +00001553 fDrawBuffer->flushTo(fGpu);
junov@google.com53a55842011-06-08 22:55:10 +00001554 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001555#endif
1556}
1557
bsalomon@google.com6f379512011-11-16 20:36:03 +00001558void GrContext::internalWriteTexturePixels(GrTexture* texture,
1559 int left, int top,
1560 int width, int height,
1561 GrPixelConfig config,
1562 const void* buffer,
1563 size_t rowBytes,
1564 uint32_t flags) {
1565 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001566 ASSERT_OWNED_RESOURCE(texture);
1567
bsalomon@google.com6f379512011-11-16 20:36:03 +00001568 if (!(kDontFlush_PixelOpsFlag & flags)) {
1569 this->flush();
1570 }
1571 // TODO: use scratch texture to perform conversion
1572 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1573 GrPixelConfigIsUnpremultiplied(config)) {
1574 return;
1575 }
1576
1577 fGpu->writeTexturePixels(texture, left, top, width, height,
1578 config, buffer, rowBytes);
1579}
1580
1581bool GrContext::internalReadTexturePixels(GrTexture* texture,
1582 int left, int top,
1583 int width, int height,
1584 GrPixelConfig config,
1585 void* buffer,
1586 size_t rowBytes,
1587 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001588 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001589 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001590
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001591 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001592 GrRenderTarget* target = texture->asRenderTarget();
1593 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001594 return this->internalReadRenderTargetPixels(target,
1595 left, top, width, height,
1596 config, buffer, rowBytes,
1597 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001598 } else {
1599 return false;
1600 }
1601}
1602
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001603#include "SkConfig8888.h"
1604
1605namespace {
1606/**
1607 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1608 * formats are representable as Config8888 and so the function returns false
1609 * if the GrPixelConfig has no equivalent Config8888.
1610 */
1611bool grconfig_to_config8888(GrPixelConfig config,
1612 SkCanvas::Config8888* config8888) {
1613 switch (config) {
1614 case kRGBA_8888_PM_GrPixelConfig:
1615 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1616 return true;
1617 case kRGBA_8888_UPM_GrPixelConfig:
1618 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1619 return true;
1620 case kBGRA_8888_PM_GrPixelConfig:
1621 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1622 return true;
1623 case kBGRA_8888_UPM_GrPixelConfig:
1624 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1625 return true;
1626 default:
1627 return false;
1628 }
1629}
1630}
1631
bsalomon@google.com6f379512011-11-16 20:36:03 +00001632bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1633 int left, int top,
1634 int width, int height,
1635 GrPixelConfig config,
1636 void* buffer,
1637 size_t rowBytes,
1638 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001639 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001640 ASSERT_OWNED_RESOURCE(target);
1641
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001642 if (NULL == target) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001643 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001644 if (NULL == target) {
1645 return false;
1646 }
1647 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001648
bsalomon@google.com6f379512011-11-16 20:36:03 +00001649 if (!(kDontFlush_PixelOpsFlag & flags)) {
1650 this->flush();
1651 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001652
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001653 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1654 GrPixelConfigIsUnpremultiplied(config) &&
1655 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1656 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1657 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1658 !grconfig_to_config8888(config, &dstConfig8888)) {
1659 return false;
1660 }
1661 // do read back using target's own config
1662 this->internalReadRenderTargetPixels(target,
1663 left, top,
1664 width, height,
1665 target->config(),
1666 buffer, rowBytes,
1667 kDontFlush_PixelOpsFlag);
1668 // sw convert the pixels to unpremul config
1669 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1670 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1671 pixels, rowBytes, srcConfig8888,
1672 width, height);
1673 return true;
1674 }
1675
bsalomon@google.comc4364992011-11-07 15:54:49 +00001676 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001677 bool swapRAndB = NULL != src &&
1678 fGpu->preferredReadPixelsConfig(config) ==
1679 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001680
1681 bool flipY = NULL != src &&
1682 fGpu->readPixelsWillPayForYFlip(target, left, top,
1683 width, height, config,
1684 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001685 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1686 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001687
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001688 if (NULL == src && alphaConversion) {
1689 // we should fallback to cpu conversion here. This could happen when
1690 // we were given an external render target by the client that is not
1691 // also a texture (e.g. FBO 0 in GL)
1692 return false;
1693 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001694 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001695 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001696 if (flipY || swapRAndB || alphaConversion) {
1697 GrAssert(NULL != src);
1698 if (swapRAndB) {
1699 config = GrPixelConfigSwapRAndB(config);
1700 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001701 }
1702 // Make the scratch a render target because we don't have a robust
1703 // readTexturePixels as of yet (it calls this function).
1704 const GrTextureDesc desc = {
1705 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001706 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001707 config,
1708 {0}, // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001709 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001710
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001711 // When a full readback is faster than a partial we could always make
1712 // the scratch exactly match the passed rect. However, if we see many
1713 // different size rectangles we will trash our texture cache and pay the
1714 // cost of creating and destroying many textures. So, we only request
1715 // an exact match when the caller is reading an entire RT.
1716 ScratchTexMatch match = kApprox_ScratchTexMatch;
1717 if (0 == left &&
1718 0 == top &&
1719 target->width() == width &&
1720 target->height() == height &&
1721 fGpu->fullReadPixelsIsFasterThanPartial()) {
1722 match = kExact_ScratchTexMatch;
1723 }
1724 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001725 GrTexture* texture = ast.texture();
1726 if (!texture) {
1727 return false;
1728 }
1729 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001730 GrAssert(NULL != target);
1731
1732 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001733 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001734 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001735 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001736
bsalomon@google.comc4364992011-11-07 15:54:49 +00001737 GrMatrix matrix;
1738 if (flipY) {
1739 matrix.setTranslate(SK_Scalar1 * left,
1740 SK_Scalar1 * (top + height));
1741 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1742 } else {
1743 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1744 }
1745 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001746 drawState->sampler(0)->reset(matrix);
1747 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001748 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001749 GrRect rect;
1750 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1751 fGpu->drawSimpleRect(rect, NULL, 0x1);
1752 left = 0;
1753 top = 0;
1754 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001755 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001756 left, top, width, height,
1757 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001758}
1759
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001760void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1761 GrAssert(target);
1762 ASSERT_OWNED_RESOURCE(target);
1763 // In the future we may track whether there are any pending draws to this
1764 // target. We don't today so we always perform a flush. We don't promise
1765 // this to our clients, though.
1766 this->flush();
1767 fGpu->resolveRenderTarget(target);
1768}
1769
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001770void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1771 if (NULL == src || NULL == dst) {
1772 return;
1773 }
1774 ASSERT_OWNED_RESOURCE(src);
1775
1776 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001777 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001778 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001779 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001780 GrMatrix sampleM;
1781 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001782 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001783 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001784 SkRect rect = SkRect::MakeXYWH(0, 0,
1785 SK_Scalar1 * src->width(),
1786 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001787 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1788}
1789
bsalomon@google.com6f379512011-11-16 20:36:03 +00001790void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1791 int left, int top,
1792 int width, int height,
1793 GrPixelConfig config,
1794 const void* buffer,
1795 size_t rowBytes,
1796 uint32_t flags) {
1797 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001798 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001799
1800 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001801 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001802 if (NULL == target) {
1803 return;
1804 }
1805 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001806
1807 // TODO: when underlying api has a direct way to do this we should use it
1808 // (e.g. glDrawPixels on desktop GL).
1809
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001810 // If the RT is also a texture and we don't have to do PM/UPM conversion
1811 // then take the texture path, which we expect to be at least as fast or
1812 // faster since it doesn't use an intermediate texture as we do below.
1813
1814#if !GR_MAC_BUILD
1815 // At least some drivers on the Mac get confused when glTexImage2D is called
1816 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1817 // determine what OS versions and/or HW is affected.
1818 if (NULL != target->asTexture() &&
1819 GrPixelConfigIsUnpremultiplied(target->config()) ==
1820 GrPixelConfigIsUnpremultiplied(config)) {
1821
1822 this->internalWriteTexturePixels(target->asTexture(),
1823 left, top, width, height,
1824 config, buffer, rowBytes, flags);
1825 return;
1826 }
1827#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001828 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1829 GrPixelConfigIsUnpremultiplied(config) &&
1830 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1831 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1832 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1833 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1834 return;
1835 }
1836 // allocate a tmp buffer and sw convert the pixels to premul
1837 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1838 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1839 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1840 src, rowBytes, srcConfig8888,
1841 width, height);
1842 // upload the already premul pixels
1843 this->internalWriteRenderTargetPixels(target,
1844 left, top,
1845 width, height,
1846 target->config(),
1847 tmpPixels, 4 * width, flags);
1848 return;
1849 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001850
1851 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1852 GrPixelConfigSwapRAndB(config);
1853 if (swapRAndB) {
1854 config = GrPixelConfigSwapRAndB(config);
1855 }
1856
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001857 const GrTextureDesc desc = {
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001858 kNone_GrTextureFlags, width, height, config, {0}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001859 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001860 GrAutoScratchTexture ast(this, desc);
1861 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001862 if (NULL == texture) {
1863 return;
1864 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001865 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1866 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001867
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001869 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001870 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871
1872 GrMatrix matrix;
1873 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001874 drawState->setViewMatrix(matrix);
1875 drawState->setRenderTarget(target);
1876 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001877
bsalomon@google.com5c638652011-07-18 19:31:59 +00001878 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001879 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1880 GrSamplerState::kNearest_Filter,
1881 matrix);
1882 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001883
1884 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1885 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001886 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001887 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1888 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001889 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001890 return;
1891 }
1892 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1893 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1894}
1895////////////////////////////////////////////////////////////////////////////////
1896
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001897void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
1898 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001899
1900 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1901 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001902 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001903 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001904 if (paint.getTexture(i)) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001905 *drawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001906 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001907 }
1908
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001909 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001910
1911 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1912 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001913 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001914 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001915 if (paint.getMask(i)) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001916 *drawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001917 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001918 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001919
1920 // disable all stages not accessible via the paint
1921 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001922 drawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001923 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001924
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001925 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001926
1927 if (paint.fDither) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001928 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001929 } else {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001930 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001931 }
1932 if (paint.fAntiAlias) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001933 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001934 } else {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001935 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001936 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001937 if (paint.fColorMatrixEnabled) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001938 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
1939 drawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001940 } else {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001941 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001942 }
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001943 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1944 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1945 drawState->setCoverage(paint.fCoverage);
bsalomon@google.come79c8152012-03-29 19:07:12 +00001946#if GR_DEBUG
1947 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
1948 !target->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001949 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1950 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001951#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001952}
1953
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001954GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001955 DrawCategory category) {
1956 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001957 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001958 fLastDrawCategory = category;
1959 }
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001960 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001961 GrDrawTarget* target = fGpu;
1962 switch (category) {
1963 case kText_DrawCategory:
1964#if DEFER_TEXT_RENDERING
1965 target = fDrawBuffer;
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001966 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001967#else
1968 target = fGpu;
1969#endif
1970 break;
1971 case kUnbuffered_DrawCategory:
1972 target = fGpu;
1973 break;
1974 case kBuffered_DrawCategory:
1975 target = fDrawBuffer;
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001976 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001977 break;
1978 }
1979 return target;
1980}
1981
bsalomon@google.com289533a2011-10-27 12:34:25 +00001982GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1983 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001984 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001985 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001986 if (NULL == fPathRendererChain) {
1987 fPathRendererChain =
1988 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1989 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001990 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001991}
1992
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993////////////////////////////////////////////////////////////////////////////////
1994
bsalomon@google.com27847de2011-02-22 20:59:41 +00001995void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001996 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001997 if (fGpu->drawState()->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001998 this->flush(false);
bsalomon@google.com5b819c12012-03-28 21:34:22 +00001999 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002000 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001}
2002
2003GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002004 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005}
2006
2007const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002008 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002009}
2010
2011const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002012 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002013}
2014
2015void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002016 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002017}
2018
2019void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002020 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002021}
2022
2023static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2024 intptr_t mask = 1 << shift;
2025 if (pred) {
2026 bits |= mask;
2027 } else {
2028 bits &= ~mask;
2029 }
2030 return bits;
2031}
2032
2033void GrContext::resetStats() {
2034 fGpu->resetStats();
2035}
2036
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002037const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002038 return fGpu->getStats();
2039}
2040
2041void GrContext::printStats() const {
2042 fGpu->printStats();
2043}
2044
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002045GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002046 fGpu = gpu;
2047 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002048 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002049
bsalomon@google.com30085192011-08-19 15:42:31 +00002050 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002051
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002052 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2053 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002054 fFontCache = new GrFontCache(fGpu);
2055
2056 fLastDrawCategory = kUnbuffered_DrawCategory;
2057
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002058 fDrawBuffer = NULL;
2059 fDrawBufferVBAllocPool = NULL;
2060 fDrawBufferIBAllocPool = NULL;
2061
bsalomon@google.com205d4602011-04-25 12:43:45 +00002062 fAAFillRectIndexBuffer = NULL;
2063 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002064
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002065 this->setupDrawBuffer();
2066}
2067
2068void GrContext::setupDrawBuffer() {
2069
2070 GrAssert(NULL == fDrawBuffer);
2071 GrAssert(NULL == fDrawBufferVBAllocPool);
2072 GrAssert(NULL == fDrawBufferIBAllocPool);
2073
bsalomon@google.com27847de2011-02-22 20:59:41 +00002074#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002075 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002076 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002077 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2078 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002079 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002080 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002081 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002082 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2083
bsalomon@google.com471d4712011-08-23 15:45:25 +00002084 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2085 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002086 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002087#endif
2088
2089#if BATCH_RECT_TO_RECT
2090 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2091#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002092 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002093}
2094
bsalomon@google.com27847de2011-02-22 20:59:41 +00002095GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002096 GrDrawTarget* target;
bsalomon@google.com27847de2011-02-22 20:59:41 +00002097#if DEFER_TEXT_RENDERING
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002098 target = prepareToDraw(paint, kText_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002099#else
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002100 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002101#endif
bsalomon@google.com5b819c12012-03-28 21:34:22 +00002102 this->setPaint(paint, target);
2103 return target;
bsalomon@google.com27847de2011-02-22 20:59:41 +00002104}
2105
2106const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2107 return fGpu->getQuadIndexBuffer();
2108}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002109
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002110GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2111 GrAutoScratchTexture* temp1,
2112 GrAutoScratchTexture* temp2,
2113 const SkRect& rect,
2114 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002115 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002116 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2117 GrClip oldClip = this->getClip();
2118 GrTexture* origTexture = srcTexture;
2119 GrAutoMatrix avm(this, GrMatrix::I());
2120 SkIRect clearRect;
2121 int scaleFactorX, halfWidthX, kernelWidthX;
2122 int scaleFactorY, halfWidthY, kernelWidthY;
2123 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2124 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002125
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002126 SkRect srcRect(rect);
2127 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2128 srcRect.roundOut();
2129 scale_rect(&srcRect, scaleFactorX, scaleFactorY);
2130 this->setClip(srcRect);
2131
2132 const GrTextureDesc desc = {
2133 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002134 SkScalarFloorToInt(srcRect.width()),
2135 SkScalarFloorToInt(srcRect.height()),
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002136 kRGBA_8888_GrPixelConfig,
2137 {0} // samples
2138 };
2139
2140 temp1->set(this, desc);
2141 if (temp2) temp2->set(this, desc);
2142
2143 GrTexture* dstTexture = temp1->texture();
2144 GrPaint paint;
2145 paint.reset();
2146 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2147
2148 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2149 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2150 srcTexture->height());
2151 this->setRenderTarget(dstTexture->asRenderTarget());
2152 SkRect dstRect(srcRect);
2153 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2154 i < scaleFactorY ? 0.5f : 1.0f);
2155 paint.setTexture(0, srcTexture);
2156 this->drawRectToRect(paint, dstRect, srcRect);
2157 srcRect = dstRect;
2158 SkTSwap(srcTexture, dstTexture);
2159 // If temp2 is non-NULL, don't render back to origTexture
2160 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2161 }
2162
2163 if (sigmaX > 0.0f) {
2164 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2165 float* kernelX = kernelStorageX.get();
2166 build_kernel(sigmaX, kernelX, kernelWidthX);
2167
2168 if (scaleFactorX > 1) {
2169 // Clear out a halfWidth to the right of the srcRect to prevent the
2170 // X convolution from reading garbage.
2171 clearRect = SkIRect::MakeXYWH(
2172 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2173 this->clear(&clearRect, 0x0);
2174 }
2175
2176 this->setRenderTarget(dstTexture->asRenderTarget());
2177 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2178 GrSamplerState::kX_FilterDirection);
2179 SkTSwap(srcTexture, dstTexture);
2180 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2181 }
2182
2183 if (sigmaY > 0.0f) {
2184 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2185 float* kernelY = kernelStorageY.get();
2186 build_kernel(sigmaY, kernelY, kernelWidthY);
2187
2188 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2189 // Clear out a halfWidth below the srcRect to prevent the Y
2190 // convolution from reading garbage.
2191 clearRect = SkIRect::MakeXYWH(
2192 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2193 this->clear(&clearRect, 0x0);
2194 }
2195
2196 this->setRenderTarget(dstTexture->asRenderTarget());
2197 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2198 GrSamplerState::kY_FilterDirection);
2199 SkTSwap(srcTexture, dstTexture);
2200 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2201 }
2202
2203 if (scaleFactorX > 1 || scaleFactorY > 1) {
2204 // Clear one pixel to the right and below, to accommodate bilinear
2205 // upsampling.
2206 clearRect = SkIRect::MakeXYWH(
2207 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2208 this->clear(&clearRect, 0x0);
2209 clearRect = SkIRect::MakeXYWH(
2210 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2211 this->clear(&clearRect, 0x0);
2212 // FIXME: This should be mitchell, not bilinear.
2213 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2214 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2215 srcTexture->height());
2216 this->setRenderTarget(dstTexture->asRenderTarget());
2217 paint.setTexture(0, srcTexture);
2218 SkRect dstRect(srcRect);
2219 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2220 this->drawRectToRect(paint, dstRect, srcRect);
2221 srcRect = dstRect;
2222 SkTSwap(srcTexture, dstTexture);
2223 }
2224 this->setRenderTarget(oldRenderTarget);
2225 this->setClip(oldClip);
2226 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002227}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002228
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002229GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2230 const GrRect& rect,
2231 GrTexture* temp1, GrTexture* temp2,
2232 GrSamplerState::Filter filter,
2233 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002234 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002235 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2236 GrAutoMatrix avm(this, GrMatrix::I());
2237 GrClip oldClip = this->getClip();
2238 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2239 if (radius.fWidth > 0) {
2240 this->setRenderTarget(temp1->asRenderTarget());
2241 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2242 GrSamplerState::kX_FilterDirection);
2243 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2244 rect.width(), radius.fHeight);
2245 this->clear(&clearRect, 0x0);
2246 srcTexture = temp1;
2247 }
2248 if (radius.fHeight > 0) {
2249 this->setRenderTarget(temp2->asRenderTarget());
2250 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2251 GrSamplerState::kY_FilterDirection);
2252 srcTexture = temp2;
2253 }
2254 this->setRenderTarget(oldRenderTarget);
2255 this->setClip(oldClip);
2256 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002257}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002258
2259///////////////////////////////////////////////////////////////////////////////