blob: 80dd25ebee2871f0ad087a28166ab7e01e4bb537 [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"
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000014#include "effects/GrConvolutionEffect.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000015#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrIndexBuffer.h"
17#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000018#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000019#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000020#include "GrResourceCache.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000021#include "GrSoftwarePathRenderer.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000022#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000023#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000024#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000025#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000026
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000027#define DEFER_TEXT_RENDERING 1
bsalomon@google.com27847de2011-02-22 20:59:41 +000028
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000029#define DEFER_PATHS 1
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000030
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000031#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
bsalomon@google.com27847de2011-02-22 20:59:41 +000032
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000033#define MAX_BLUR_SIGMA 4.0f
34
bsalomon@google.comd46e2422011-09-23 17:40:07 +000035// When we're using coverage AA but the blend is incompatible (given gpu
36// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000037#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000038
reed@google.com4b2d3f32012-05-15 18:05:50 +000039#if GR_DEBUG
40 // change this to a 1 to see notifications when partial coverage fails
41 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
42#else
43 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
44#endif
45
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000046static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
47static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000048
bsalomon@google.com60361492012-03-15 17:47:06 +000049static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000050static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
51
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000052// path rendering is the only thing we defer today that uses non-static indices
53static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
54static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000055
bsalomon@google.combc4b6542011-11-19 13:56:11 +000056#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
57
bsalomon@google.com05ef5102011-05-02 21:14:59 +000058GrContext* GrContext::Create(GrEngine engine,
59 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000060 GrContext* ctx = NULL;
61 GrGpu* fGpu = GrGpu::Create(engine, context3D);
62 if (NULL != fGpu) {
63 ctx = new GrContext(fGpu);
64 fGpu->unref();
65 }
66 return ctx;
67}
68
bsalomon@google.com27847de2011-02-22 20:59:41 +000069GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000070 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +000071
72 // Since the gpu can hold scratch textures, give it a chance to let go
73 // of them before freeing the texture cache
74 fGpu->purgeResources();
75
bsalomon@google.com27847de2011-02-22 20:59:41 +000076 delete fTextureCache;
77 delete fFontCache;
78 delete fDrawBuffer;
79 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000080 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000081
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 GrSafeUnref(fAAFillRectIndexBuffer);
83 GrSafeUnref(fAAStrokeRectIndexBuffer);
84 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000085 GrSafeUnref(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +000086 GrSafeUnref(fSoftwarePathRenderer);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000087 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000088}
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000091 contextDestroyed();
92 this->setupDrawBuffer();
93}
94
95void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000096 // abandon first to so destructors
97 // don't try to free the resources in the API.
98 fGpu->abandonResources();
99
bsalomon@google.com30085192011-08-19 15:42:31 +0000100 // a path renderer may be holding onto resources that
101 // are now unusable
102 GrSafeSetNull(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +0000103 GrSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com30085192011-08-19 15:42:31 +0000104
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105 delete fDrawBuffer;
106 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000107
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000108 delete fDrawBufferVBAllocPool;
109 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000110
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000111 delete fDrawBufferIBAllocPool;
112 fDrawBufferIBAllocPool = NULL;
113
bsalomon@google.com205d4602011-04-25 12:43:45 +0000114 GrSafeSetNull(fAAFillRectIndexBuffer);
115 GrSafeSetNull(fAAStrokeRectIndexBuffer);
116
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000117 fTextureCache->removeAll();
118 fFontCache->freeAll();
119 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000120}
121
122void GrContext::resetContext() {
123 fGpu->markContextDirty();
124}
125
126void GrContext::freeGpuResources() {
127 this->flush();
robertphillips@google.comff175842012-05-14 19:31:39 +0000128
129 fGpu->purgeResources();
130
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000131 fTextureCache->removeAll();
132 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000133 // a path renderer may be holding onto resources
134 GrSafeSetNull(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +0000135 GrSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000136}
137
twiz@google.com05e70242012-01-27 19:12:00 +0000138size_t GrContext::getGpuTextureCacheBytes() const {
139 return fTextureCache->getCachedResourceBytes();
140}
141
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000142////////////////////////////////////////////////////////////////////////////////
143
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000144int GrContext::PaintStageVertexLayoutBits(
145 const GrPaint& paint,
146 const bool hasTexCoords[GrPaint::kTotalStages]) {
147 int stageMask = paint.getActiveStageMask();
148 int layout = 0;
149 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
150 if ((1 << i) & stageMask) {
151 if (NULL != hasTexCoords && hasTexCoords[i]) {
152 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
153 } else {
154 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
155 }
156 }
157 }
158 return layout;
159}
160
161
162////////////////////////////////////////////////////////////////////////////////
163
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000164enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000165 // flags for textures
166 kNPOTBit = 0x1,
167 kFilterBit = 0x2,
168 kScratchBit = 0x4,
169
170 // resource type
171 kTextureBit = 0x8,
172 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000173};
174
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000175GrTexture* GrContext::TextureCacheEntry::texture() const {
176 if (NULL == fEntry) {
177 return NULL;
178 } else {
179 return (GrTexture*) fEntry->resource();
180 }
181}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000182
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000183namespace {
184// returns true if this is a "special" texture because of gpu NPOT limitations
185bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000186 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000187 GrContext::TextureKey clientKey,
188 int width,
189 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000190 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191 bool scratch,
192 uint32_t v[4]) {
193 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
194 // we assume we only need 16 bits of width and height
195 // assert that texture creation will fail anyway if this assumption
196 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000197 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000198 v[0] = clientKey & 0xffffffffUL;
199 v[1] = (clientKey >> 32) & 0xffffffffUL;
200 v[2] = width | (height << 16);
201
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000202 v[3] = (sampleCnt << 24);
203 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
204
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000205 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000206 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
207
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000208 bool tiled = NULL != sampler &&
209 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
210 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000211
212 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000213 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000214 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000215 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000216 }
217 }
218 }
219
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000220 if (scratch) {
221 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000222 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000223
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000224 v[3] |= kTextureBit;
225
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000226 return v[3] & kNPOTBit;
227}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000228
229// we should never have more than one stencil buffer with same combo of
230// (width,height,samplecount)
231void gen_stencil_key_values(int width, int height,
232 int sampleCnt, uint32_t v[4]) {
233 v[0] = width;
234 v[1] = height;
235 v[2] = sampleCnt;
236 v[3] = kStencilBufferBit;
237}
238
239void gen_stencil_key_values(const GrStencilBuffer* sb,
240 uint32_t v[4]) {
241 gen_stencil_key_values(sb->width(), sb->height(),
242 sb->numSamples(), v);
243}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000244
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000245void build_kernel(float sigma, float* kernel, int kernelWidth) {
246 int halfWidth = (kernelWidth - 1) / 2;
247 float sum = 0.0f;
248 float denom = 1.0f / (2.0f * sigma * sigma);
249 for (int i = 0; i < kernelWidth; ++i) {
250 float x = static_cast<float>(i - halfWidth);
251 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
252 // is dropped here, since we renormalize the kernel below.
253 kernel[i] = sk_float_exp(- x * x * denom);
254 sum += kernel[i];
255 }
256 // Normalize the kernel
257 float scale = 1.0f / sum;
258 for (int i = 0; i < kernelWidth; ++i)
259 kernel[i] *= scale;
260}
261
262void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000263 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
264 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
265 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
266 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000267}
268
269float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
270 int *kernelWidth) {
271 *scaleFactor = 1;
272 while (sigma > MAX_BLUR_SIGMA) {
273 *scaleFactor *= 2;
274 sigma *= 0.5f;
275 }
276 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
277 *kernelWidth = *halfWidth * 2 + 1;
278 return sigma;
279}
280
281void apply_morphology(GrGpu* gpu,
282 GrTexture* texture,
283 const SkRect& rect,
284 int radius,
285 GrSamplerState::Filter filter,
286 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000287 GrAssert(filter == GrSamplerState::kErode_Filter ||
288 filter == GrSamplerState::kDilate_Filter);
289
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000290 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
291 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000292 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000293 drawState->setRenderTarget(target);
294 GrMatrix sampleM;
295 sampleM.setIDiv(texture->width(), texture->height());
296 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
297 sampleM);
298 drawState->sampler(0)->setMorphologyRadius(radius);
299 drawState->sampler(0)->setFilterDirection(direction);
300 drawState->setTexture(0, texture);
301 gpu->drawSimpleRect(rect, NULL, 1 << 0);
302}
303
304void convolve(GrGpu* gpu,
305 GrTexture* texture,
306 const SkRect& rect,
307 const float* kernel,
308 int kernelWidth,
309 GrSamplerState::FilterDirection direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000310 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
311 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000312 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000313 drawState->setRenderTarget(target);
314 GrMatrix sampleM;
315 sampleM.setIDiv(texture->width(), texture->height());
316 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
317 GrSamplerState::kConvolution_Filter,
318 sampleM);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000319 drawState->sampler(0)->setCustomStage(
320 new GrConvolutionEffect(direction, kernelWidth, kernel));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000321 drawState->setTexture(0, texture);
322 gpu->drawSimpleRect(rect, NULL, 1 << 0);
323}
324
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000325}
326
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000327GrContext::TextureCacheEntry GrContext::findAndLockTexture(
328 TextureKey key,
329 int width,
330 int height,
331 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000332 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000333 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000334 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000335 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
336 GrResourceCache::kNested_LockType));
337}
338
bsalomon@google.comfb309512011-11-30 14:13:48 +0000339bool GrContext::isTextureInCache(TextureKey key,
340 int width,
341 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000342 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000343 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000344 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000345 GrResourceKey resourceKey(v);
346 return fTextureCache->hasKey(resourceKey);
347}
348
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000349GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000350 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000351 uint32_t v[4];
352 gen_stencil_key_values(sb, v);
353 GrResourceKey resourceKey(v);
354 return fTextureCache->createAndLock(resourceKey, sb);
355}
356
357GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
358 int sampleCnt) {
359 uint32_t v[4];
360 gen_stencil_key_values(width, height, sampleCnt, v);
361 GrResourceKey resourceKey(v);
362 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
363 GrResourceCache::kSingle_LockType);
364 if (NULL != entry) {
365 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
366 return sb;
367 } else {
368 return NULL;
369 }
370}
371
372void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000373 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000374 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000375}
376
377static void stretchImage(void* dst,
378 int dstW,
379 int dstH,
380 void* src,
381 int srcW,
382 int srcH,
383 int bpp) {
384 GrFixed dx = (srcW << 16) / dstW;
385 GrFixed dy = (srcH << 16) / dstH;
386
387 GrFixed y = dy >> 1;
388
389 int dstXLimit = dstW*bpp;
390 for (int j = 0; j < dstH; ++j) {
391 GrFixed x = dx >> 1;
392 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
393 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
394 for (int i = 0; i < dstXLimit; i += bpp) {
395 memcpy((uint8_t*) dstRow + i,
396 (uint8_t*) srcRow + (x>>16)*bpp,
397 bpp);
398 x += dx;
399 }
400 y += dy;
401 }
402}
403
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000404GrContext::TextureCacheEntry GrContext::createAndLockTexture(
405 TextureKey key,
406 const GrSamplerState* sampler,
407 const GrTextureDesc& desc,
408 void* srcData,
409 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000410 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000411
412#if GR_DUMP_TEXTURE_UPLOAD
413 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
414#endif
415
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416 TextureCacheEntry entry;
417 uint32_t v[4];
418 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000419 desc.fWidth, desc.fHeight,
420 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000422
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000423 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000424 GrAssert(NULL != sampler);
425 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
426 desc.fWidth,
427 desc.fHeight,
428 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000429
430 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000431 clampEntry = this->createAndLockTexture(key, NULL, desc,
432 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000433 GrAssert(NULL != clampEntry.texture());
434 if (NULL == clampEntry.texture()) {
435 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000436 }
437 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000438 GrTextureDesc rtDesc = desc;
439 rtDesc.fFlags = rtDesc.fFlags |
440 kRenderTarget_GrTextureFlagBit |
441 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000442 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
443 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000444
445 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
446
447 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000448 GrDrawTarget::AutoStateRestore asr(fGpu,
449 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000450 GrDrawState* drawState = fGpu->drawState();
451 drawState->setRenderTarget(texture->asRenderTarget());
452 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000453
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000454 GrSamplerState::Filter filter;
455 // if filtering is not desired then we want to ensure all
456 // texels in the resampled image are copies of texels from
457 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000458 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000459 filter = GrSamplerState::kNearest_Filter;
460 } else {
461 filter = GrSamplerState::kBilinear_Filter;
462 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000463 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
464 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000465
466 static const GrVertexLayout layout =
467 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
468 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
469
470 if (arg.succeeded()) {
471 GrPoint* verts = (GrPoint*) arg.vertices();
472 verts[0].setIRectFan(0, 0,
473 texture->width(),
474 texture->height(),
475 2*sizeof(GrPoint));
476 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
477 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
478 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000479 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000480 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000481 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000482 } else {
483 // TODO: Our CPU stretch doesn't filter. But we create separate
484 // stretched textures when the sampler state is either filtered or
485 // not. Either implement filtered stretch blit on CPU or just create
486 // one when FBO case fails.
487
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000488 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000489 // no longer need to clamp at min RT size.
490 rtDesc.fWidth = GrNextPow2(desc.fWidth);
491 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000492 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000493 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000494 rtDesc.fWidth *
495 rtDesc.fHeight);
496 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
497 srcData, desc.fWidth, desc.fHeight, bpp);
498
499 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
500
501 GrTexture* texture = fGpu->createTexture(rtDesc,
502 stretchedPixels.get(),
503 stretchedRowBytes);
504 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000505 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000506 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000507 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000508
509 } else {
510 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
511 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000512 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000513 }
514 }
515 return entry;
516}
517
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518namespace {
519inline void gen_scratch_tex_key_values(const GrGpu* gpu,
520 const GrTextureDesc& desc,
521 uint32_t v[4]) {
522 // Instead of a client-provided key of the texture contents
523 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000524 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000525 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000526 // this code path isn't friendly to tiling with NPOT restricitons
527 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000528 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000529 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000530}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000531}
532
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000533GrContext::TextureCacheEntry GrContext::lockScratchTexture(
534 const GrTextureDesc& inDesc,
535 ScratchTexMatch match) {
536
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000537 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000538 if (kExact_ScratchTexMatch != match) {
539 // bin by pow2 with a reasonable min
540 static const int MIN_SIZE = 256;
541 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
542 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
543 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000544
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000545 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000546 int origWidth = desc.fWidth;
547 int origHeight = desc.fHeight;
548 bool doubledW = false;
549 bool doubledH = false;
550
551 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000552 uint32_t v[4];
553 gen_scratch_tex_key_values(fGpu, desc, v);
554 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000555 entry = fTextureCache->findAndLock(key,
556 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000557 // if we miss, relax the fit of the flags...
558 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000559 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000560 break;
561 }
562 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
563 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
564 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
565 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
566 } else if (!doubledW) {
567 desc.fFlags = inDesc.fFlags;
568 desc.fWidth *= 2;
569 doubledW = true;
570 } else if (!doubledH) {
571 desc.fFlags = inDesc.fFlags;
572 desc.fWidth = origWidth;
573 desc.fHeight *= 2;
574 doubledH = true;
575 } else {
576 break;
577 }
578
579 } while (true);
580
581 if (NULL == entry) {
582 desc.fFlags = inDesc.fFlags;
583 desc.fWidth = origWidth;
584 desc.fHeight = origHeight;
585 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
586 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000587 uint32_t v[4];
588 gen_scratch_tex_key_values(fGpu, desc, v);
589 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000590 entry = fTextureCache->createAndLock(key, texture);
591 }
592 }
593
594 // If the caller gives us the same desc/sampler twice we don't want
595 // to return the same texture the second time (unless it was previously
596 // released). So we detach the entry from the cache and reattach at release.
597 if (NULL != entry) {
598 fTextureCache->detach(entry);
599 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000600 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000601}
602
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000603void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000604 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000605 // If this is a scratch texture we detached it from the cache
606 // while it was locked (to avoid two callers simultaneously getting
607 // the same texture).
608 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
609 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000610 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000611 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000612 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000613}
614
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000615GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000616 void* srcData,
617 size_t rowBytes) {
618 return fGpu->createTexture(desc, srcData, rowBytes);
619}
620
621void GrContext::getTextureCacheLimits(int* maxTextures,
622 size_t* maxTextureBytes) const {
623 fTextureCache->getLimits(maxTextures, maxTextureBytes);
624}
625
626void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
627 fTextureCache->setLimits(maxTextures, maxTextureBytes);
628}
629
bsalomon@google.com91958362011-06-13 17:58:13 +0000630int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000631 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000632}
633
634int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000635 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000636}
637
638///////////////////////////////////////////////////////////////////////////////
639
bsalomon@google.come269f212011-11-07 13:29:52 +0000640GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
641 return fGpu->createPlatformTexture(desc);
642}
643
644GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
645 return fGpu->createPlatformRenderTarget(desc);
646}
647
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000648///////////////////////////////////////////////////////////////////////////////
649
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000650bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000651 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000652 const GrDrawTarget::Caps& caps = fGpu->getCaps();
653 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000654 return false;
655 }
656
bsalomon@google.com27847de2011-02-22 20:59:41 +0000657 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
658
659 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000660 bool tiled = NULL != sampler &&
661 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
662 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000663 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000664 return false;
665 }
666 }
667 return true;
668}
669
670////////////////////////////////////////////////////////////////////////////////
671
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000672const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
673
bsalomon@google.com27847de2011-02-22 20:59:41 +0000674void GrContext::setClip(const GrClip& clip) {
675 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000676 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000677}
678
679void GrContext::setClip(const GrIRect& rect) {
680 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000681 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000682 fGpu->setClip(clip);
683}
684
685////////////////////////////////////////////////////////////////////////////////
686
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000687void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000688 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000689 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000690}
691
692void GrContext::drawPaint(const GrPaint& paint) {
693 // set rect to be big enough to fill the space, but not super-huge, so we
694 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000695 GrRect r;
696 r.setLTRB(0, 0,
697 GrIntToScalar(getRenderTarget()->width()),
698 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000699 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000700 SkTLazy<GrPaint> tmpPaint;
701 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000702 GrAutoMatrix am;
703
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000704 // We attempt to map r by the inverse matrix and draw that. mapRect will
705 // map the four corners and bound them with a new rect. This will not
706 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000707 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000708 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000709 GrPrintf("Could not invert matrix");
710 return;
711 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000712 inverse.mapRect(&r);
713 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000714 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000715 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000716 GrPrintf("Could not invert matrix");
717 return;
718 }
719 tmpPaint.set(paint);
720 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
721 p = tmpPaint.get();
722 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000723 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000724 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000725 // by definition this fills the entire clip, no need for AA
726 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000727 if (!tmpPaint.isValid()) {
728 tmpPaint.set(paint);
729 p = tmpPaint.get();
730 }
731 GrAssert(p == tmpPaint.get());
732 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000733 }
734 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000735}
736
bsalomon@google.com205d4602011-04-25 12:43:45 +0000737////////////////////////////////////////////////////////////////////////////////
738
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000739namespace {
740inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
741 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
742}
743}
744
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000745////////////////////////////////////////////////////////////////////////////////
746
bsalomon@google.com27847de2011-02-22 20:59:41 +0000747/* create a triangle strip that strokes the specified triangle. There are 8
748 unique vertices, but we repreat the last 2 to close up. Alternatively we
749 could use an indices array, and then only send 8 verts, but not sure that
750 would be faster.
751 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000752static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000753 GrScalar width) {
754 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000755 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000756
757 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
758 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
759 verts[2].set(rect.fRight - rad, rect.fTop + rad);
760 verts[3].set(rect.fRight + rad, rect.fTop - rad);
761 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
762 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
763 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
764 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
765 verts[8] = verts[0];
766 verts[9] = verts[1];
767}
768
bsalomon@google.com205d4602011-04-25 12:43:45 +0000769static void setInsetFan(GrPoint* pts, size_t stride,
770 const GrRect& r, GrScalar dx, GrScalar dy) {
771 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
772}
773
774static const uint16_t gFillAARectIdx[] = {
775 0, 1, 5, 5, 4, 0,
776 1, 2, 6, 6, 5, 1,
777 2, 3, 7, 7, 6, 2,
778 3, 0, 4, 4, 7, 3,
779 4, 5, 6, 6, 7, 4,
780};
781
782int GrContext::aaFillRectIndexCount() const {
783 return GR_ARRAY_COUNT(gFillAARectIdx);
784}
785
786GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
787 if (NULL == fAAFillRectIndexBuffer) {
788 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
789 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000790 if (NULL != fAAFillRectIndexBuffer) {
791 #if GR_DEBUG
792 bool updated =
793 #endif
794 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
795 sizeof(gFillAARectIdx));
796 GR_DEBUGASSERT(updated);
797 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000798 }
799 return fAAFillRectIndexBuffer;
800}
801
802static const uint16_t gStrokeAARectIdx[] = {
803 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
804 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
805 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
806 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
807
808 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
809 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
810 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
811 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
812
813 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
814 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
815 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
816 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
817};
818
819int GrContext::aaStrokeRectIndexCount() const {
820 return GR_ARRAY_COUNT(gStrokeAARectIdx);
821}
822
823GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
824 if (NULL == fAAStrokeRectIndexBuffer) {
825 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
826 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000827 if (NULL != fAAStrokeRectIndexBuffer) {
828 #if GR_DEBUG
829 bool updated =
830 #endif
831 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
832 sizeof(gStrokeAARectIdx));
833 GR_DEBUGASSERT(updated);
834 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000835 }
836 return fAAStrokeRectIndexBuffer;
837}
838
bsalomon@google.coma3108262011-10-10 14:08:47 +0000839static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
840 bool useCoverage) {
841 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000842 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000843 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000844 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
845 }
846 }
847 if (useCoverage) {
848 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
849 } else {
850 layout |= GrDrawTarget::kColor_VertexLayoutBit;
851 }
852 return layout;
853}
854
bsalomon@google.com205d4602011-04-25 12:43:45 +0000855void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000856 const GrRect& devRect,
857 bool useVertexCoverage) {
858 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000859
860 size_t vsize = GrDrawTarget::VertexSize(layout);
861
862 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000863 if (!geo.succeeded()) {
864 GrPrintf("Failed to get space for vertices!\n");
865 return;
866 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000867 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
868 if (NULL == indexBuffer) {
869 GrPrintf("Failed to create index buffer!\n");
870 return;
871 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000872
873 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
874
875 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
876 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
877
878 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
879 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
880
881 verts += sizeof(GrPoint);
882 for (int i = 0; i < 4; ++i) {
883 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
884 }
885
bsalomon@google.coma3108262011-10-10 14:08:47 +0000886 GrColor innerColor;
887 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000888 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000889 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000890 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000891 }
892
bsalomon@google.com205d4602011-04-25 12:43:45 +0000893 verts += 4 * vsize;
894 for (int i = 0; i < 4; ++i) {
895 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
896 }
897
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000898 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000899
900 target->drawIndexed(kTriangles_PrimitiveType, 0,
901 0, 8, this->aaFillRectIndexCount());
902}
903
bsalomon@google.coma3108262011-10-10 14:08:47 +0000904void GrContext::strokeAARect(GrDrawTarget* target,
905 const GrRect& devRect,
906 const GrVec& devStrokeSize,
907 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 const GrScalar& dx = devStrokeSize.fX;
909 const GrScalar& dy = devStrokeSize.fY;
910 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
911 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
912
bsalomon@google.com205d4602011-04-25 12:43:45 +0000913 GrScalar spare;
914 {
915 GrScalar w = devRect.width() - dx;
916 GrScalar h = devRect.height() - dy;
917 spare = GrMin(w, h);
918 }
919
920 if (spare <= 0) {
921 GrRect r(devRect);
922 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000923 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000924 return;
925 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000926 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000927 size_t vsize = GrDrawTarget::VertexSize(layout);
928
929 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000930 if (!geo.succeeded()) {
931 GrPrintf("Failed to get space for vertices!\n");
932 return;
933 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000934 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
935 if (NULL == indexBuffer) {
936 GrPrintf("Failed to create index buffer!\n");
937 return;
938 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000939
940 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
941
942 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
943 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
944 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
945 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
946
947 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
948 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
949 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
950 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
951
952 verts += sizeof(GrPoint);
953 for (int i = 0; i < 4; ++i) {
954 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
955 }
956
bsalomon@google.coma3108262011-10-10 14:08:47 +0000957 GrColor innerColor;
958 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000959 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000960 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000961 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000962 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000963 verts += 4 * vsize;
964 for (int i = 0; i < 8; ++i) {
965 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
966 }
967
968 verts += 8 * vsize;
969 for (int i = 0; i < 8; ++i) {
970 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
971 }
972
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000973 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000974 target->drawIndexed(kTriangles_PrimitiveType,
975 0, 0, 16, aaStrokeRectIndexCount());
976}
977
reed@google.com20efde72011-05-09 17:00:02 +0000978/**
979 * Returns true if the rects edges are integer-aligned.
980 */
981static bool isIRect(const GrRect& r) {
982 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
983 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
984}
985
bsalomon@google.com205d4602011-04-25 12:43:45 +0000986static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000987 const GrRect& rect,
988 GrScalar width,
989 const GrMatrix* matrix,
990 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000991 GrRect* devRect,
992 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000993 // we use a simple coverage ramp to do aa on axis-aligned rects
994 // we check if the rect will be axis-aligned, and the rect won't land on
995 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000996
bsalomon@google.coma3108262011-10-10 14:08:47 +0000997 // we are keeping around the "tweak the alpha" trick because
998 // it is our only hope for the fixed-pipe implementation.
999 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001000 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001001 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001002 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001003 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001004#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001005 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001006#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001007 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001008 } else {
1009 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001010 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001011 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001012 const GrDrawState& drawState = target->getDrawState();
1013 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001014 return false;
1015 }
1016
bsalomon@google.com471d4712011-08-23 15:45:25 +00001017 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001018 return false;
1019 }
1020
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001021 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022 return false;
1023 }
1024
1025 if (NULL != matrix &&
1026 !matrix->preservesAxisAlignment()) {
1027 return false;
1028 }
1029
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001030 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001031 if (NULL != matrix) {
1032 combinedMatrix->preConcat(*matrix);
1033 GrAssert(combinedMatrix->preservesAxisAlignment());
1034 }
1035
1036 combinedMatrix->mapRect(devRect, rect);
1037 devRect->sort();
1038
1039 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001040 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001041 } else {
1042 return true;
1043 }
1044}
1045
bsalomon@google.com27847de2011-02-22 20:59:41 +00001046void GrContext::drawRect(const GrPaint& paint,
1047 const GrRect& rect,
1048 GrScalar width,
1049 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001050 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001051
1052 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001053 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001054
bsalomon@google.com205d4602011-04-25 12:43:45 +00001055 GrRect devRect = rect;
1056 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001057 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001058 bool needAA = paint.fAntiAlias &&
1059 !this->getRenderTarget()->isMultisampled();
1060 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1061 &combinedMatrix, &devRect,
1062 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001063
1064 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001065 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001066 if (width >= 0) {
1067 GrVec strokeSize;;
1068 if (width > 0) {
1069 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001070 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001071 strokeSize.setAbs(strokeSize);
1072 } else {
1073 strokeSize.set(GR_Scalar1, GR_Scalar1);
1074 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001075 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001076 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001077 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001078 }
1079 return;
1080 }
1081
bsalomon@google.com27847de2011-02-22 20:59:41 +00001082 if (width >= 0) {
1083 // TODO: consider making static vertex buffers for these cases.
1084 // Hairline could be done by just adding closing vertex to
1085 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001086 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1087
bsalomon@google.com27847de2011-02-22 20:59:41 +00001088 static const int worstCaseVertCount = 10;
1089 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1090
1091 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001092 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001093 return;
1094 }
1095
1096 GrPrimitiveType primType;
1097 int vertCount;
1098 GrPoint* vertex = geo.positions();
1099
1100 if (width > 0) {
1101 vertCount = 10;
1102 primType = kTriangleStrip_PrimitiveType;
1103 setStrokeRectStrip(vertex, rect, width);
1104 } else {
1105 // hairline
1106 vertCount = 5;
1107 primType = kLineStrip_PrimitiveType;
1108 vertex[0].set(rect.fLeft, rect.fTop);
1109 vertex[1].set(rect.fRight, rect.fTop);
1110 vertex[2].set(rect.fRight, rect.fBottom);
1111 vertex[3].set(rect.fLeft, rect.fBottom);
1112 vertex[4].set(rect.fLeft, rect.fTop);
1113 }
1114
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001115 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001116 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001117 GrDrawState* drawState = target->drawState();
1118 avmr.set(drawState);
1119 drawState->preConcatViewMatrix(*matrix);
1120 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001121 }
1122
1123 target->drawNonIndexed(primType, 0, vertCount);
1124 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001125#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001126 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001127 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1128 if (NULL == sqVB) {
1129 GrPrintf("Failed to create static rect vb.\n");
1130 return;
1131 }
1132 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001133 GrDrawState* drawState = target->drawState();
1134 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001135 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001136 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001137 0, rect.height(), rect.fTop,
1138 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001139
1140 if (NULL != matrix) {
1141 m.postConcat(*matrix);
1142 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001143 drawState->preConcatViewMatrix(m);
1144 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001145
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001147#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001148 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001149#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001150 }
1151}
1152
1153void GrContext::drawRectToRect(const GrPaint& paint,
1154 const GrRect& dstRect,
1155 const GrRect& srcRect,
1156 const GrMatrix* dstMatrix,
1157 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001158 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001160 // srcRect refers to paint's first texture
1161 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001162 drawRect(paint, dstRect, -1, dstMatrix);
1163 return;
1164 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001165
bsalomon@google.com27847de2011-02-22 20:59:41 +00001166 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1167
1168#if GR_STATIC_RECT_VB
1169 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001170 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001171 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001172 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001173
1174 GrMatrix m;
1175
1176 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1177 0, dstRect.height(), dstRect.fTop,
1178 0, 0, GrMatrix::I()[8]);
1179 if (NULL != dstMatrix) {
1180 m.postConcat(*dstMatrix);
1181 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001182 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001183
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001184 // srcRect refers to first stage
1185 int otherStageMask = paint.getActiveStageMask() &
1186 (~(1 << GrPaint::kFirstTextureStage));
1187 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001188 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001189 }
1190
bsalomon@google.com27847de2011-02-22 20:59:41 +00001191 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1192 0, srcRect.height(), srcRect.fTop,
1193 0, 0, GrMatrix::I()[8]);
1194 if (NULL != srcMatrix) {
1195 m.postConcat(*srcMatrix);
1196 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001197 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001199 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1200 if (NULL == sqVB) {
1201 GrPrintf("Failed to create static rect vb.\n");
1202 return;
1203 }
1204 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001205 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1206#else
1207
1208 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001209#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001210 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001211#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001212 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1213#endif
1214
tomhudson@google.com93813632011-10-27 20:21:16 +00001215 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1216 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001217 srcRects[0] = &srcRect;
1218 srcMatrices[0] = srcMatrix;
1219
1220 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1221#endif
1222}
1223
1224void GrContext::drawVertices(const GrPaint& paint,
1225 GrPrimitiveType primitiveType,
1226 int vertexCount,
1227 const GrPoint positions[],
1228 const GrPoint texCoords[],
1229 const GrColor colors[],
1230 const uint16_t indices[],
1231 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001232 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233
1234 GrDrawTarget::AutoReleaseGeometry geo;
1235
1236 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1237
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001238 bool hasTexCoords[GrPaint::kTotalStages] = {
1239 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1240 0 // remaining stages use positions
1241 };
1242
1243 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001244
1245 if (NULL != colors) {
1246 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001247 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001248 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001249
1250 if (sizeof(GrPoint) != vertexSize) {
1251 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001252 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253 return;
1254 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001255 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001256 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001257 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1258 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001259 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001260 NULL,
1261 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001262 void* curVertex = geo.vertices();
1263
1264 for (int i = 0; i < vertexCount; ++i) {
1265 *((GrPoint*)curVertex) = positions[i];
1266
1267 if (texOffsets[0] > 0) {
1268 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1269 }
1270 if (colorOffset > 0) {
1271 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1272 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001273 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274 }
1275 } else {
1276 target->setVertexSourceToArray(layout, positions, vertexCount);
1277 }
1278
bsalomon@google.com91958362011-06-13 17:58:13 +00001279 // we don't currently apply offscreen AA to this path. Need improved
1280 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001281
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001282 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001283 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001284 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001286 target->drawNonIndexed(primitiveType, 0, vertexCount);
1287 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288}
1289
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001290///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001291namespace {
1292
bsalomon@google.com93c96602012-04-27 13:05:21 +00001293struct CircleVertex {
1294 GrPoint fPos;
1295 GrPoint fCenter;
1296 GrScalar fOuterRadius;
1297 GrScalar fInnerRadius;
1298};
1299
1300/* Returns true if will map a circle to another circle. This can be true
1301 * if the matrix only includes square-scale, rotation, translation.
1302 */
1303inline bool isSimilarityTransformation(const SkMatrix& matrix,
1304 SkScalar tol = SK_ScalarNearlyZero) {
1305 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1306 return true;
1307 }
1308 if (matrix.hasPerspective()) {
1309 return false;
1310 }
1311
1312 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1313 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1314 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1315 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1316
1317 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1318 return false;
1319 }
1320
1321 // it has scales or skews, but it could also be rotation, check it out.
1322 SkVector vec[2];
1323 vec[0].set(mx, sx);
1324 vec[1].set(sy, my);
1325
1326 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1327 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1328 SkScalarSquare(tol));
1329}
1330
1331}
1332
1333// TODO: strokeWidth can't be larger than zero right now.
1334// It will be fixed when drawPath() can handle strokes.
1335void GrContext::drawOval(const GrPaint& paint,
1336 const GrRect& rect,
1337 SkScalar strokeWidth) {
1338 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1339 kUnbuffered_DrawCategory;
1340 GrDrawTarget* target = this->prepareToDraw(paint, category);
1341 GrDrawState* drawState = target->drawState();
1342 GrMatrix vm = drawState->getViewMatrix();
1343
1344 if (!isSimilarityTransformation(vm) ||
1345 !paint.fAntiAlias ||
1346 rect.height() != rect.width()) {
1347 SkPath path;
1348 path.addOval(rect);
1349 GrPathFill fill = (strokeWidth == 0) ?
1350 kHairLine_PathFill : kWinding_PathFill;
1351 this->internalDrawPath(paint, path, fill, NULL);
1352 return;
1353 }
1354
1355 const GrRenderTarget* rt = drawState->getRenderTarget();
1356 if (NULL == rt) {
1357 return;
1358 }
1359
1360 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1361
1362 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1363 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1364 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1365
1366 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1367 GrScalar radius = SkScalarHalf(rect.width());
1368
1369 vm.mapPoints(&center, 1);
1370 radius = vm.mapRadius(radius);
1371
1372 GrScalar outerRadius = radius;
1373 GrScalar innerRadius = 0;
1374 SkScalar halfWidth = 0;
1375 if (strokeWidth == 0) {
1376 halfWidth = SkScalarHalf(SK_Scalar1);
1377
1378 outerRadius += halfWidth;
1379 innerRadius = SkMaxScalar(0, radius - halfWidth);
1380 }
1381
1382 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1383 if (!geo.succeeded()) {
1384 GrPrintf("Failed to get space for vertices!\n");
1385 return;
1386 }
1387
1388 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1389
1390 SkScalar L = center.fX - outerRadius;
1391 SkScalar R = center.fX + outerRadius;
1392 SkScalar T = center.fY - outerRadius;
1393 SkScalar B = center.fY + outerRadius;
1394
1395 verts[0].fPos = SkPoint::Make(L, T);
1396 verts[1].fPos = SkPoint::Make(R, T);
1397 verts[2].fPos = SkPoint::Make(L, B);
1398 verts[3].fPos = SkPoint::Make(R, B);
1399
1400 for (int i = 0; i < 4; ++i) {
1401 // this goes to fragment shader, it should be in y-points-up space.
1402 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1403
1404 verts[i].fOuterRadius = outerRadius;
1405 verts[i].fInnerRadius = innerRadius;
1406 }
1407
1408 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1409 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001410}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001412void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001413 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001415 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001416 if (GrIsFillInverted(fill)) {
1417 this->drawPaint(paint);
1418 }
1419 return;
1420 }
1421
bsalomon@google.com93c96602012-04-27 13:05:21 +00001422 SkRect ovalRect;
1423 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1424 if (translate) {
1425 ovalRect.offset(*translate);
1426 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001427 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001428 this->drawOval(paint, ovalRect, width);
1429 return;
1430 }
1431
1432 internalDrawPath(paint, path, fill, translate);
1433}
1434
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001435void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001436 GrPathFill fill, const GrPoint* translate) {
1437
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001438 // Note that below we may sw-rasterize the path into a scratch texture.
1439 // Scratch textures can be recycled after they are returned to the texture
1440 // cache. This presents a potential hazard for buffered drawing. However,
1441 // the writePixels that uploads to the scratch will perform a flush so we're
1442 // OK.
1443 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1444 kUnbuffered_DrawCategory;
1445 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001446 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001447
bsalomon@google.com289533a2011-10-27 12:34:25 +00001448 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1449
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001450 // An Assumption here is that path renderer would use some form of tweaking
1451 // the src color (either the input alpha or in the frag shader) to implement
1452 // aa. If we have some future driver-mojo path AA that can do the right
1453 // thing WRT to the blend then we'll need some query on the PR.
1454 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001455#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001456 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001457#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001458 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001459 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001460
robertphillips@google.com72176b22012-05-23 13:19:12 +00001461 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA, true);
bsalomon@google.com30085192011-08-19 15:42:31 +00001462 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001463#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001464 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001465#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001466 return;
1467 }
1468
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001469 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001470}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001471
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472////////////////////////////////////////////////////////////////////////////////
1473
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001474void GrContext::flush(int flagsBitfield) {
1475 if (kDiscard_FlushBit & flagsBitfield) {
1476 fDrawBuffer->reset();
1477 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001478 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001479 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001480 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481 fGpu->forceRenderTargetFlush();
1482 }
1483}
1484
bsalomon@google.com27847de2011-02-22 20:59:41 +00001485void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001486 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001487 // With addition of the AA clip path, flushing the draw buffer can
1488 // result in the generation of an AA clip mask. During this
1489 // process the SW path renderer may be invoked which recusively
1490 // calls this method (via internalWriteTexturePixels) creating
1491 // infinite recursion
1492 GrInOrderDrawBuffer* temp = fDrawBuffer;
1493 fDrawBuffer = NULL;
1494
1495 temp->flushTo(fGpu);
1496
1497 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001498 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001499}
1500
bsalomon@google.com6f379512011-11-16 20:36:03 +00001501void GrContext::internalWriteTexturePixels(GrTexture* texture,
1502 int left, int top,
1503 int width, int height,
1504 GrPixelConfig config,
1505 const void* buffer,
1506 size_t rowBytes,
1507 uint32_t flags) {
1508 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001509 ASSERT_OWNED_RESOURCE(texture);
1510
bsalomon@google.com6f379512011-11-16 20:36:03 +00001511 if (!(kDontFlush_PixelOpsFlag & flags)) {
1512 this->flush();
1513 }
1514 // TODO: use scratch texture to perform conversion
1515 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1516 GrPixelConfigIsUnpremultiplied(config)) {
1517 return;
1518 }
1519
1520 fGpu->writeTexturePixels(texture, left, top, width, height,
1521 config, buffer, rowBytes);
1522}
1523
1524bool GrContext::internalReadTexturePixels(GrTexture* texture,
1525 int left, int top,
1526 int width, int height,
1527 GrPixelConfig config,
1528 void* buffer,
1529 size_t rowBytes,
1530 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001531 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001532 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001533
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001534 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001535 GrRenderTarget* target = texture->asRenderTarget();
1536 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001537 return this->internalReadRenderTargetPixels(target,
1538 left, top, width, height,
1539 config, buffer, rowBytes,
1540 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001541 } else {
1542 return false;
1543 }
1544}
1545
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001546#include "SkConfig8888.h"
1547
1548namespace {
1549/**
1550 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1551 * formats are representable as Config8888 and so the function returns false
1552 * if the GrPixelConfig has no equivalent Config8888.
1553 */
1554bool grconfig_to_config8888(GrPixelConfig config,
1555 SkCanvas::Config8888* config8888) {
1556 switch (config) {
1557 case kRGBA_8888_PM_GrPixelConfig:
1558 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1559 return true;
1560 case kRGBA_8888_UPM_GrPixelConfig:
1561 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1562 return true;
1563 case kBGRA_8888_PM_GrPixelConfig:
1564 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1565 return true;
1566 case kBGRA_8888_UPM_GrPixelConfig:
1567 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1568 return true;
1569 default:
1570 return false;
1571 }
1572}
1573}
1574
bsalomon@google.com6f379512011-11-16 20:36:03 +00001575bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1576 int left, int top,
1577 int width, int height,
1578 GrPixelConfig config,
1579 void* buffer,
1580 size_t rowBytes,
1581 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001582 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001583 ASSERT_OWNED_RESOURCE(target);
1584
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001585 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001586 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001587 if (NULL == target) {
1588 return false;
1589 }
1590 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001591
bsalomon@google.com6f379512011-11-16 20:36:03 +00001592 if (!(kDontFlush_PixelOpsFlag & flags)) {
1593 this->flush();
1594 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001595
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001596 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1597 GrPixelConfigIsUnpremultiplied(config) &&
1598 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1599 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1600 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1601 !grconfig_to_config8888(config, &dstConfig8888)) {
1602 return false;
1603 }
1604 // do read back using target's own config
1605 this->internalReadRenderTargetPixels(target,
1606 left, top,
1607 width, height,
1608 target->config(),
1609 buffer, rowBytes,
1610 kDontFlush_PixelOpsFlag);
1611 // sw convert the pixels to unpremul config
1612 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1613 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1614 pixels, rowBytes, srcConfig8888,
1615 width, height);
1616 return true;
1617 }
1618
bsalomon@google.comc4364992011-11-07 15:54:49 +00001619 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001620 bool swapRAndB = NULL != src &&
1621 fGpu->preferredReadPixelsConfig(config) ==
1622 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001623
1624 bool flipY = NULL != src &&
1625 fGpu->readPixelsWillPayForYFlip(target, left, top,
1626 width, height, config,
1627 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001628 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1629 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001630
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001631 if (NULL == src && alphaConversion) {
1632 // we should fallback to cpu conversion here. This could happen when
1633 // we were given an external render target by the client that is not
1634 // also a texture (e.g. FBO 0 in GL)
1635 return false;
1636 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001637 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001638 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001639 if (flipY || swapRAndB || alphaConversion) {
1640 GrAssert(NULL != src);
1641 if (swapRAndB) {
1642 config = GrPixelConfigSwapRAndB(config);
1643 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001644 }
1645 // Make the scratch a render target because we don't have a robust
1646 // readTexturePixels as of yet (it calls this function).
1647 const GrTextureDesc desc = {
1648 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001649 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001650 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001651 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001652 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001653
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001654 // When a full readback is faster than a partial we could always make
1655 // the scratch exactly match the passed rect. However, if we see many
1656 // different size rectangles we will trash our texture cache and pay the
1657 // cost of creating and destroying many textures. So, we only request
1658 // an exact match when the caller is reading an entire RT.
1659 ScratchTexMatch match = kApprox_ScratchTexMatch;
1660 if (0 == left &&
1661 0 == top &&
1662 target->width() == width &&
1663 target->height() == height &&
1664 fGpu->fullReadPixelsIsFasterThanPartial()) {
1665 match = kExact_ScratchTexMatch;
1666 }
1667 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001668 GrTexture* texture = ast.texture();
1669 if (!texture) {
1670 return false;
1671 }
1672 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001673 GrAssert(NULL != target);
1674
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001675 GrDrawTarget::AutoStateRestore asr(fGpu,
1676 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001677 GrDrawState* drawState = fGpu->drawState();
1678 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001679
bsalomon@google.comc4364992011-11-07 15:54:49 +00001680 GrMatrix matrix;
1681 if (flipY) {
1682 matrix.setTranslate(SK_Scalar1 * left,
1683 SK_Scalar1 * (top + height));
1684 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1685 } else {
1686 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1687 }
1688 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001689 drawState->sampler(0)->reset(matrix);
1690 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001691 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001692 GrRect rect;
1693 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1694 fGpu->drawSimpleRect(rect, NULL, 0x1);
1695 left = 0;
1696 top = 0;
1697 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001698 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001699 left, top, width, height,
1700 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001701}
1702
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001703void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1704 GrAssert(target);
1705 ASSERT_OWNED_RESOURCE(target);
1706 // In the future we may track whether there are any pending draws to this
1707 // target. We don't today so we always perform a flush. We don't promise
1708 // this to our clients, though.
1709 this->flush();
1710 fGpu->resolveRenderTarget(target);
1711}
1712
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001713void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1714 if (NULL == src || NULL == dst) {
1715 return;
1716 }
1717 ASSERT_OWNED_RESOURCE(src);
1718
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001719 // Writes pending to the source texture are not tracked, so a flush
1720 // is required to ensure that the copy captures the most recent contents
1721 // of the source texture. See similar behaviour in
1722 // GrContext::resolveRenderTarget.
1723 this->flush();
1724
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001725 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001726 GrDrawState* drawState = fGpu->drawState();
1727 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001728 GrMatrix sampleM;
1729 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001730 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001731 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001732 SkRect rect = SkRect::MakeXYWH(0, 0,
1733 SK_Scalar1 * src->width(),
1734 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001735 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1736}
1737
bsalomon@google.com6f379512011-11-16 20:36:03 +00001738void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1739 int left, int top,
1740 int width, int height,
1741 GrPixelConfig config,
1742 const void* buffer,
1743 size_t rowBytes,
1744 uint32_t flags) {
1745 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001746 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001747
1748 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001749 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001750 if (NULL == target) {
1751 return;
1752 }
1753 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001754
1755 // TODO: when underlying api has a direct way to do this we should use it
1756 // (e.g. glDrawPixels on desktop GL).
1757
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001758 // If the RT is also a texture and we don't have to do PM/UPM conversion
1759 // then take the texture path, which we expect to be at least as fast or
1760 // faster since it doesn't use an intermediate texture as we do below.
1761
1762#if !GR_MAC_BUILD
1763 // At least some drivers on the Mac get confused when glTexImage2D is called
1764 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1765 // determine what OS versions and/or HW is affected.
1766 if (NULL != target->asTexture() &&
1767 GrPixelConfigIsUnpremultiplied(target->config()) ==
1768 GrPixelConfigIsUnpremultiplied(config)) {
1769
1770 this->internalWriteTexturePixels(target->asTexture(),
1771 left, top, width, height,
1772 config, buffer, rowBytes, flags);
1773 return;
1774 }
1775#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001776 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1777 GrPixelConfigIsUnpremultiplied(config) &&
1778 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1779 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1780 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1781 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1782 return;
1783 }
1784 // allocate a tmp buffer and sw convert the pixels to premul
1785 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1786 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1787 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1788 src, rowBytes, srcConfig8888,
1789 width, height);
1790 // upload the already premul pixels
1791 this->internalWriteRenderTargetPixels(target,
1792 left, top,
1793 width, height,
1794 target->config(),
1795 tmpPixels, 4 * width, flags);
1796 return;
1797 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001798
1799 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1800 GrPixelConfigSwapRAndB(config);
1801 if (swapRAndB) {
1802 config = GrPixelConfigSwapRAndB(config);
1803 }
1804
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001805 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001806 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001807 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001808 GrAutoScratchTexture ast(this, desc);
1809 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001810 if (NULL == texture) {
1811 return;
1812 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001813 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1814 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001815
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001816 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001817 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001818
1819 GrMatrix matrix;
1820 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001821 drawState->setViewMatrix(matrix);
1822 drawState->setRenderTarget(target);
1823 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001824
bsalomon@google.com5c638652011-07-18 19:31:59 +00001825 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001826 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1827 GrSamplerState::kNearest_Filter,
1828 matrix);
1829 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830
1831 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1832 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001833 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001834 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1835 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001836 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001837 return;
1838 }
1839 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1840 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1841}
1842////////////////////////////////////////////////////////////////////////////////
1843
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001844void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001845
1846 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1847 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001848 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001849 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001850 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001851 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001852 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001853 }
1854
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001855 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001856
1857 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1858 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001859 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001860 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001861 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001862 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001863 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001864 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001865
1866 // disable all stages not accessible via the paint
1867 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001868 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001869 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001870
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001871 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001872
1873 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001874 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001875 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001876 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001877 }
1878 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001879 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001880 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001881 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001882 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001883 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001884 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1885 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001886 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001887 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001888 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001889 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1890 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1891 fDrawState->setCoverage(paint.fCoverage);
reed@google.com4b2d3f32012-05-15 18:05:50 +00001892#if GR_DEBUG_PARTIAL_COVERAGE_CHECK
bsalomon@google.come79c8152012-03-29 19:07:12 +00001893 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001894 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001895 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1896 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001897#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001898}
1899
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001900GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001901 DrawCategory category) {
1902 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001903 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001904 fLastDrawCategory = category;
1905 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001906 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001907 GrDrawTarget* target = fGpu;
1908 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001909 case kUnbuffered_DrawCategory:
1910 target = fGpu;
1911 break;
1912 case kBuffered_DrawCategory:
1913 target = fDrawBuffer;
1914 fDrawBuffer->setClip(fGpu->getClip());
1915 break;
1916 default:
1917 GrCrash("Unexpected DrawCategory.");
1918 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001919 }
1920 return target;
1921}
1922
robertphillips@google.com72176b22012-05-23 13:19:12 +00001923/*
1924 * This method finds a path renderer that can draw the specified path on
1925 * the provided target.
1926 * Due to its expense, the software path renderer has split out so it can
1927 * can be individually allowed/disallowed via the "allowSW" boolean.
1928 */
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001929GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001930 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001931 const GrDrawTarget* target,
robertphillips@google.com72176b22012-05-23 13:19:12 +00001932 bool antiAlias,
1933 bool allowSW) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001934 if (NULL == fPathRendererChain) {
1935 fPathRendererChain =
1936 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1937 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001938
1939 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path, fill,
1940 target,
1941 antiAlias);
1942
1943 if (NULL == pr && allowSW) {
1944 if (NULL == fSoftwarePathRenderer) {
1945 fSoftwarePathRenderer = new GrSoftwarePathRenderer(this);
1946 }
1947
1948 pr = fSoftwarePathRenderer;
1949 }
1950
1951 return pr;
bsalomon@google.com30085192011-08-19 15:42:31 +00001952}
1953
bsalomon@google.com27847de2011-02-22 20:59:41 +00001954////////////////////////////////////////////////////////////////////////////////
1955
bsalomon@google.com27847de2011-02-22 20:59:41 +00001956void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001957 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001958 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001959 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001960 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001961 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001962}
1963
1964GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001965 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001966}
1967
1968const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001969 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001970}
1971
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001972bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1973 return fGpu->isConfigRenderable(config);
1974}
1975
bsalomon@google.com27847de2011-02-22 20:59:41 +00001976const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001977 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001978}
1979
1980void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001981 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982}
1983
1984void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001985 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001986}
1987
1988static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1989 intptr_t mask = 1 << shift;
1990 if (pred) {
1991 bits |= mask;
1992 } else {
1993 bits &= ~mask;
1994 }
1995 return bits;
1996}
1997
1998void GrContext::resetStats() {
1999 fGpu->resetStats();
2000}
2001
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002002const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002003 return fGpu->getStats();
2004}
2005
2006void GrContext::printStats() const {
2007 fGpu->printStats();
2008}
2009
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002010GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002011 fGpu = gpu;
2012 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002013 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002014
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002015 fDrawState = new GrDrawState();
2016 fGpu->setDrawState(fDrawState);
2017
bsalomon@google.com30085192011-08-19 15:42:31 +00002018 fPathRendererChain = NULL;
robertphillips@google.com72176b22012-05-23 13:19:12 +00002019 fSoftwarePathRenderer = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002020
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002021 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2022 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002023 fFontCache = new GrFontCache(fGpu);
2024
2025 fLastDrawCategory = kUnbuffered_DrawCategory;
2026
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002027 fDrawBuffer = NULL;
2028 fDrawBufferVBAllocPool = NULL;
2029 fDrawBufferIBAllocPool = NULL;
2030
bsalomon@google.com205d4602011-04-25 12:43:45 +00002031 fAAFillRectIndexBuffer = NULL;
2032 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002033
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002034 this->setupDrawBuffer();
2035}
2036
2037void GrContext::setupDrawBuffer() {
2038
2039 GrAssert(NULL == fDrawBuffer);
2040 GrAssert(NULL == fDrawBufferVBAllocPool);
2041 GrAssert(NULL == fDrawBufferIBAllocPool);
2042
bsalomon@google.com92edd312012-04-04 21:40:21 +00002043#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002044 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002045 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002046 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2047 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002048 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002049 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002050 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002051 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2052
bsalomon@google.com471d4712011-08-23 15:45:25 +00002053 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2054 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002055 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002056#endif
2057
2058#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002059 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002060#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002061 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002062 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002063}
2064
bsalomon@google.com27847de2011-02-22 20:59:41 +00002065GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002066#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002067 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002068#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002069 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002070#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002071}
2072
2073const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2074 return fGpu->getQuadIndexBuffer();
2075}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002076
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002077GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2078 GrAutoScratchTexture* temp1,
2079 GrAutoScratchTexture* temp2,
2080 const SkRect& rect,
2081 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002082 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002083 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2084 GrClip oldClip = this->getClip();
2085 GrTexture* origTexture = srcTexture;
2086 GrAutoMatrix avm(this, GrMatrix::I());
2087 SkIRect clearRect;
2088 int scaleFactorX, halfWidthX, kernelWidthX;
2089 int scaleFactorY, halfWidthY, kernelWidthY;
2090 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2091 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002092
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002093 SkRect srcRect(rect);
2094 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2095 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002096 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2097 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002098 this->setClip(srcRect);
2099
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002100 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2101 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2102 kAlpha_8_GrPixelConfig == srcTexture->config());
2103
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002104 const GrTextureDesc desc = {
2105 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002106 SkScalarFloorToInt(srcRect.width()),
2107 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002108 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002109 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002110 };
2111
2112 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002113 if (temp2) {
2114 temp2->set(this, desc);
2115 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002116
2117 GrTexture* dstTexture = temp1->texture();
2118 GrPaint paint;
2119 paint.reset();
2120 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2121
2122 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2123 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2124 srcTexture->height());
2125 this->setRenderTarget(dstTexture->asRenderTarget());
2126 SkRect dstRect(srcRect);
2127 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2128 i < scaleFactorY ? 0.5f : 1.0f);
2129 paint.setTexture(0, srcTexture);
2130 this->drawRectToRect(paint, dstRect, srcRect);
2131 srcRect = dstRect;
2132 SkTSwap(srcTexture, dstTexture);
2133 // If temp2 is non-NULL, don't render back to origTexture
2134 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2135 }
2136
robertphillips@google.com7a396332012-05-10 15:11:27 +00002137 SkIRect srcIRect;
2138 srcRect.roundOut(&srcIRect);
2139
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002140 if (sigmaX > 0.0f) {
2141 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2142 float* kernelX = kernelStorageX.get();
2143 build_kernel(sigmaX, kernelX, kernelWidthX);
2144
2145 if (scaleFactorX > 1) {
2146 // Clear out a halfWidth to the right of the srcRect to prevent the
2147 // X convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002148 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2149 halfWidthX, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002150 this->clear(&clearRect, 0x0);
2151 }
2152
2153 this->setRenderTarget(dstTexture->asRenderTarget());
2154 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2155 GrSamplerState::kX_FilterDirection);
2156 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002157 if (temp2 && dstTexture == origTexture) {
2158 dstTexture = temp2->texture();
2159 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002160 }
2161
2162 if (sigmaY > 0.0f) {
2163 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2164 float* kernelY = kernelStorageY.get();
2165 build_kernel(sigmaY, kernelY, kernelWidthY);
2166
2167 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2168 // Clear out a halfWidth below the srcRect to prevent the Y
2169 // convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002170 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2171 srcIRect.width(), halfWidthY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002172 this->clear(&clearRect, 0x0);
2173 }
2174
2175 this->setRenderTarget(dstTexture->asRenderTarget());
2176 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2177 GrSamplerState::kY_FilterDirection);
2178 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002179 if (temp2 && dstTexture == origTexture) {
2180 dstTexture = temp2->texture();
2181 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002182 }
2183
2184 if (scaleFactorX > 1 || scaleFactorY > 1) {
2185 // Clear one pixel to the right and below, to accommodate bilinear
2186 // upsampling.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002187 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2188 srcIRect.width() + 1, 1);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002189 this->clear(&clearRect, 0x0);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002190 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2191 1, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002192 this->clear(&clearRect, 0x0);
2193 // FIXME: This should be mitchell, not bilinear.
2194 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2195 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2196 srcTexture->height());
2197 this->setRenderTarget(dstTexture->asRenderTarget());
2198 paint.setTexture(0, srcTexture);
2199 SkRect dstRect(srcRect);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002200 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002201 this->drawRectToRect(paint, dstRect, srcRect);
2202 srcRect = dstRect;
2203 SkTSwap(srcTexture, dstTexture);
2204 }
2205 this->setRenderTarget(oldRenderTarget);
2206 this->setClip(oldClip);
2207 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002208}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002209
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002210GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2211 const GrRect& rect,
2212 GrTexture* temp1, GrTexture* temp2,
2213 GrSamplerState::Filter filter,
2214 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002215 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002216 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2217 GrAutoMatrix avm(this, GrMatrix::I());
2218 GrClip oldClip = this->getClip();
robertphillips@google.com7a396332012-05-10 15:11:27 +00002219 this->setClip(GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
2220 SkIntToScalar(srcTexture->height())));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002221 if (radius.fWidth > 0) {
2222 this->setRenderTarget(temp1->asRenderTarget());
2223 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2224 GrSamplerState::kX_FilterDirection);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002225 SkIRect clearRect = SkIRect::MakeXYWH(
2226 SkScalarFloorToInt(rect.fLeft),
2227 SkScalarFloorToInt(rect.fBottom),
2228 SkScalarFloorToInt(rect.width()),
2229 radius.fHeight);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002230 this->clear(&clearRect, 0x0);
2231 srcTexture = temp1;
2232 }
2233 if (radius.fHeight > 0) {
2234 this->setRenderTarget(temp2->asRenderTarget());
2235 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2236 GrSamplerState::kY_FilterDirection);
2237 srcTexture = temp2;
2238 }
2239 this->setRenderTarget(oldRenderTarget);
2240 this->setClip(oldClip);
2241 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002242}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002243
robertphillips@google.com49d9fd52012-05-23 11:44:08 +00002244void GrContext::postClipPush() {
2245 fGpu->postClipPush();
2246}
2247
2248void GrContext::preClipPop() {
2249 fGpu->preClipPop();
2250};
2251
bsalomon@google.comc4364992011-11-07 15:54:49 +00002252///////////////////////////////////////////////////////////////////////////////