blob: 97ef8c85fc866d35e55c06e98c7e9a769c30edb1 [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.com8f9cbd62011-12-09 15:55:34 +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.com8f9cbd62011-12-09 15:55:34 +0000684 GrDrawState* drawState = fGpu->drawState();
685 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.com8f9cbd62011-12-09 15:55:34 +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.com8f9cbd62011-12-09 15:55:34 +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.com8f9cbd62011-12-09 15:55:34 +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.combc4b6542011-11-19 13:56:11 +00001897void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001898 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.com8f9cbd62011-12-09 15:55:34 +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)) {
1905 *drawState->sampler(s) = paint.getTextureSampler(i);
1906 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001907 }
1908
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +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.com8f9cbd62011-12-09 15:55:34 +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)) {
1916 *drawState->sampler(s) = paint.getMaskSampler(i);
1917 }
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) {
1922 drawState->setTexture(s, NULL);
1923 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001924
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001925 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001926
1927 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001928 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001929 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001930 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001931 }
1932 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001933 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001934 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +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) {
1938 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
bsalomon@google.com9b1517e2012-03-05 17:58:34 +00001939 drawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001940 } else {
1941 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
1942 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001943 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001944 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comdd1be602012-01-18 20:34:00 +00001945 drawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001946
1947 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1948 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1949 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001950}
1951
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001952GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001953 DrawCategory category) {
1954 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001955 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001956 fLastDrawCategory = category;
1957 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001958 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001959 GrDrawTarget* target = fGpu;
1960 switch (category) {
1961 case kText_DrawCategory:
1962#if DEFER_TEXT_RENDERING
1963 target = fDrawBuffer;
1964 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1965#else
1966 target = fGpu;
1967#endif
1968 break;
1969 case kUnbuffered_DrawCategory:
1970 target = fGpu;
1971 break;
1972 case kBuffered_DrawCategory:
1973 target = fDrawBuffer;
1974 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1975 break;
1976 }
1977 return target;
1978}
1979
bsalomon@google.com289533a2011-10-27 12:34:25 +00001980GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1981 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001982 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001983 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001984 if (NULL == fPathRendererChain) {
1985 fPathRendererChain =
1986 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1987 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001988 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001989}
1990
bsalomon@google.com27847de2011-02-22 20:59:41 +00001991////////////////////////////////////////////////////////////////////////////////
1992
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001994 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001995 if (fGpu->drawState()->getRenderTarget() != target) {
1996 this->flush(false);
1997 fGpu->drawState()->setRenderTarget(target);
1998 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999}
2000
2001GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002002 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002003}
2004
2005const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002006 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002007}
2008
2009const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002010 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002011}
2012
2013void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002014 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002015}
2016
2017void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002018 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002019}
2020
2021static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2022 intptr_t mask = 1 << shift;
2023 if (pred) {
2024 bits |= mask;
2025 } else {
2026 bits &= ~mask;
2027 }
2028 return bits;
2029}
2030
2031void GrContext::resetStats() {
2032 fGpu->resetStats();
2033}
2034
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002035const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002036 return fGpu->getStats();
2037}
2038
2039void GrContext::printStats() const {
2040 fGpu->printStats();
2041}
2042
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002043GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002044 fGpu = gpu;
2045 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002046 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002047
bsalomon@google.com30085192011-08-19 15:42:31 +00002048 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002049
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002050 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2051 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002052 fFontCache = new GrFontCache(fGpu);
2053
2054 fLastDrawCategory = kUnbuffered_DrawCategory;
2055
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002056 fDrawBuffer = NULL;
2057 fDrawBufferVBAllocPool = NULL;
2058 fDrawBufferIBAllocPool = NULL;
2059
bsalomon@google.com205d4602011-04-25 12:43:45 +00002060 fAAFillRectIndexBuffer = NULL;
2061 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002062
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002063 this->setupDrawBuffer();
2064}
2065
2066void GrContext::setupDrawBuffer() {
2067
2068 GrAssert(NULL == fDrawBuffer);
2069 GrAssert(NULL == fDrawBufferVBAllocPool);
2070 GrAssert(NULL == fDrawBufferIBAllocPool);
2071
bsalomon@google.com27847de2011-02-22 20:59:41 +00002072#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002073 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002074 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002075 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2076 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002077 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002078 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002079 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002080 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2081
bsalomon@google.com471d4712011-08-23 15:45:25 +00002082 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2083 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002084 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002085#endif
2086
2087#if BATCH_RECT_TO_RECT
2088 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2089#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002090 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002091}
2092
bsalomon@google.com27847de2011-02-22 20:59:41 +00002093GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2094 GrDrawTarget* target;
2095#if DEFER_TEXT_RENDERING
2096 target = prepareToDraw(paint, kText_DrawCategory);
2097#else
2098 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2099#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002100 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002101 return target;
2102}
2103
2104const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2105 return fGpu->getQuadIndexBuffer();
2106}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002107
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002108GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2109 GrAutoScratchTexture* temp1,
2110 GrAutoScratchTexture* temp2,
2111 const SkRect& rect,
2112 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002113 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002114 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2115 GrClip oldClip = this->getClip();
2116 GrTexture* origTexture = srcTexture;
2117 GrAutoMatrix avm(this, GrMatrix::I());
2118 SkIRect clearRect;
2119 int scaleFactorX, halfWidthX, kernelWidthX;
2120 int scaleFactorY, halfWidthY, kernelWidthY;
2121 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2122 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002123
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002124 SkRect srcRect(rect);
2125 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2126 srcRect.roundOut();
2127 scale_rect(&srcRect, scaleFactorX, scaleFactorY);
2128 this->setClip(srcRect);
2129
2130 const GrTextureDesc desc = {
2131 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002132 SkScalarFloorToInt(srcRect.width()),
2133 SkScalarFloorToInt(srcRect.height()),
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002134 kRGBA_8888_GrPixelConfig,
2135 {0} // samples
2136 };
2137
2138 temp1->set(this, desc);
2139 if (temp2) temp2->set(this, desc);
2140
2141 GrTexture* dstTexture = temp1->texture();
2142 GrPaint paint;
2143 paint.reset();
2144 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2145
2146 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2147 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2148 srcTexture->height());
2149 this->setRenderTarget(dstTexture->asRenderTarget());
2150 SkRect dstRect(srcRect);
2151 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2152 i < scaleFactorY ? 0.5f : 1.0f);
2153 paint.setTexture(0, srcTexture);
2154 this->drawRectToRect(paint, dstRect, srcRect);
2155 srcRect = dstRect;
2156 SkTSwap(srcTexture, dstTexture);
2157 // If temp2 is non-NULL, don't render back to origTexture
2158 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2159 }
2160
2161 if (sigmaX > 0.0f) {
2162 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2163 float* kernelX = kernelStorageX.get();
2164 build_kernel(sigmaX, kernelX, kernelWidthX);
2165
2166 if (scaleFactorX > 1) {
2167 // Clear out a halfWidth to the right of the srcRect to prevent the
2168 // X convolution from reading garbage.
2169 clearRect = SkIRect::MakeXYWH(
2170 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2171 this->clear(&clearRect, 0x0);
2172 }
2173
2174 this->setRenderTarget(dstTexture->asRenderTarget());
2175 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2176 GrSamplerState::kX_FilterDirection);
2177 SkTSwap(srcTexture, dstTexture);
2178 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2179 }
2180
2181 if (sigmaY > 0.0f) {
2182 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2183 float* kernelY = kernelStorageY.get();
2184 build_kernel(sigmaY, kernelY, kernelWidthY);
2185
2186 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2187 // Clear out a halfWidth below the srcRect to prevent the Y
2188 // convolution from reading garbage.
2189 clearRect = SkIRect::MakeXYWH(
2190 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2191 this->clear(&clearRect, 0x0);
2192 }
2193
2194 this->setRenderTarget(dstTexture->asRenderTarget());
2195 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2196 GrSamplerState::kY_FilterDirection);
2197 SkTSwap(srcTexture, dstTexture);
2198 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2199 }
2200
2201 if (scaleFactorX > 1 || scaleFactorY > 1) {
2202 // Clear one pixel to the right and below, to accommodate bilinear
2203 // upsampling.
2204 clearRect = SkIRect::MakeXYWH(
2205 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2206 this->clear(&clearRect, 0x0);
2207 clearRect = SkIRect::MakeXYWH(
2208 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2209 this->clear(&clearRect, 0x0);
2210 // FIXME: This should be mitchell, not bilinear.
2211 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2212 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2213 srcTexture->height());
2214 this->setRenderTarget(dstTexture->asRenderTarget());
2215 paint.setTexture(0, srcTexture);
2216 SkRect dstRect(srcRect);
2217 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2218 this->drawRectToRect(paint, dstRect, srcRect);
2219 srcRect = dstRect;
2220 SkTSwap(srcTexture, dstTexture);
2221 }
2222 this->setRenderTarget(oldRenderTarget);
2223 this->setClip(oldClip);
2224 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002225}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002226
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002227GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2228 const GrRect& rect,
2229 GrTexture* temp1, GrTexture* temp2,
2230 GrSamplerState::Filter filter,
2231 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002232 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002233 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2234 GrAutoMatrix avm(this, GrMatrix::I());
2235 GrClip oldClip = this->getClip();
2236 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2237 if (radius.fWidth > 0) {
2238 this->setRenderTarget(temp1->asRenderTarget());
2239 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2240 GrSamplerState::kX_FilterDirection);
2241 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2242 rect.width(), radius.fHeight);
2243 this->clear(&clearRect, 0x0);
2244 srcTexture = temp1;
2245 }
2246 if (radius.fHeight > 0) {
2247 this->setRenderTarget(temp2->asRenderTarget());
2248 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2249 GrSamplerState::kY_FilterDirection);
2250 srcTexture = temp2;
2251 }
2252 this->setRenderTarget(oldRenderTarget);
2253 this->setClip(oldClip);
2254 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002255}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002256
2257///////////////////////////////////////////////////////////////////////////////