blob: b7ada614a344f6bba8d54d058b142c42940ad902 [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
bsalomon@google.comb505a122012-05-31 18:40:36 +000012#include "effects/GrMorphologyEffect.h"
13#include "effects/GrConvolutionEffect.h"
14
tomhudson@google.com278cbb42011-06-30 19:37:01 +000015#include "GrBufferAllocPool.h"
16#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000017#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000018#include "GrIndexBuffer.h"
19#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000020#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000021#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000022#include "GrResourceCache.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000023#include "GrSoftwarePathRenderer.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000024#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000025#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000026#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000027#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000028
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000029#define DEFER_TEXT_RENDERING 1
bsalomon@google.com27847de2011-02-22 20:59:41 +000030
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000031#define DEFER_PATHS 1
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000032
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000033#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
bsalomon@google.com27847de2011-02-22 20:59:41 +000034
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000035#define MAX_BLUR_SIGMA 4.0f
36
bsalomon@google.comd46e2422011-09-23 17:40:07 +000037// When we're using coverage AA but the blend is incompatible (given gpu
38// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000039#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000040
reed@google.com4b2d3f32012-05-15 18:05:50 +000041#if GR_DEBUG
42 // change this to a 1 to see notifications when partial coverage fails
43 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
44#else
45 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
46#endif
47
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000048static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
49static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000050
bsalomon@google.com60361492012-03-15 17:47:06 +000051static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000052static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
53
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000054// path rendering is the only thing we defer today that uses non-static indices
55static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
56static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000057
bsalomon@google.combc4b6542011-11-19 13:56:11 +000058#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
59
bsalomon@google.com05ef5102011-05-02 21:14:59 +000060GrContext* GrContext::Create(GrEngine engine,
61 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 GrContext* ctx = NULL;
63 GrGpu* fGpu = GrGpu::Create(engine, context3D);
64 if (NULL != fGpu) {
65 ctx = new GrContext(fGpu);
66 fGpu->unref();
67 }
68 return ctx;
69}
70
bsalomon@google.com27847de2011-02-22 20:59:41 +000071GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000072 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +000073
74 // Since the gpu can hold scratch textures, give it a chance to let go
75 // of them before freeing the texture cache
76 fGpu->purgeResources();
77
bsalomon@google.com27847de2011-02-22 20:59:41 +000078 delete fTextureCache;
79 delete fFontCache;
80 delete fDrawBuffer;
81 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000082 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000083
bsalomon@google.com205d4602011-04-25 12:43:45 +000084 GrSafeUnref(fAAFillRectIndexBuffer);
85 GrSafeUnref(fAAStrokeRectIndexBuffer);
86 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000087 GrSafeUnref(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +000088 GrSafeUnref(fSoftwarePathRenderer);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000089 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000090}
91
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000093 contextDestroyed();
94 this->setupDrawBuffer();
95}
96
97void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 // abandon first to so destructors
99 // don't try to free the resources in the API.
100 fGpu->abandonResources();
101
bsalomon@google.com30085192011-08-19 15:42:31 +0000102 // a path renderer may be holding onto resources that
103 // are now unusable
104 GrSafeSetNull(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +0000105 GrSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com30085192011-08-19 15:42:31 +0000106
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000107 delete fDrawBuffer;
108 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000109
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000110 delete fDrawBufferVBAllocPool;
111 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000112
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000113 delete fDrawBufferIBAllocPool;
114 fDrawBufferIBAllocPool = NULL;
115
bsalomon@google.com205d4602011-04-25 12:43:45 +0000116 GrSafeSetNull(fAAFillRectIndexBuffer);
117 GrSafeSetNull(fAAStrokeRectIndexBuffer);
118
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000119 fTextureCache->removeAll();
120 fFontCache->freeAll();
121 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000122}
123
124void GrContext::resetContext() {
125 fGpu->markContextDirty();
126}
127
128void GrContext::freeGpuResources() {
129 this->flush();
robertphillips@google.comff175842012-05-14 19:31:39 +0000130
131 fGpu->purgeResources();
132
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000133 fTextureCache->removeAll();
134 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000135 // a path renderer may be holding onto resources
136 GrSafeSetNull(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +0000137 GrSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000138}
139
twiz@google.com05e70242012-01-27 19:12:00 +0000140size_t GrContext::getGpuTextureCacheBytes() const {
141 return fTextureCache->getCachedResourceBytes();
142}
143
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000144////////////////////////////////////////////////////////////////////////////////
145
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000146int GrContext::PaintStageVertexLayoutBits(
147 const GrPaint& paint,
148 const bool hasTexCoords[GrPaint::kTotalStages]) {
149 int stageMask = paint.getActiveStageMask();
150 int layout = 0;
151 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
152 if ((1 << i) & stageMask) {
153 if (NULL != hasTexCoords && hasTexCoords[i]) {
154 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
155 } else {
156 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
157 }
158 }
159 }
160 return layout;
161}
162
163
164////////////////////////////////////////////////////////////////////////////////
165
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000166enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000167 // flags for textures
168 kNPOTBit = 0x1,
169 kFilterBit = 0x2,
170 kScratchBit = 0x4,
171
172 // resource type
173 kTextureBit = 0x8,
174 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000175};
176
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000177GrTexture* GrContext::TextureCacheEntry::texture() const {
178 if (NULL == fEntry) {
179 return NULL;
180 } else {
181 return (GrTexture*) fEntry->resource();
182 }
183}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000185namespace {
186// returns true if this is a "special" texture because of gpu NPOT limitations
187bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000188 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000189 GrContext::TextureKey clientKey,
190 int width,
191 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000192 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 bool scratch,
194 uint32_t v[4]) {
195 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
196 // we assume we only need 16 bits of width and height
197 // assert that texture creation will fail anyway if this assumption
198 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000199 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000200 v[0] = clientKey & 0xffffffffUL;
201 v[1] = (clientKey >> 32) & 0xffffffffUL;
202 v[2] = width | (height << 16);
203
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000204 v[3] = (sampleCnt << 24);
205 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
206
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000207 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000208 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
209
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000210 bool tiled = NULL != sampler &&
211 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
212 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000213
214 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000215 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000216 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000217 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000218 }
219 }
220 }
221
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000222 if (scratch) {
223 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000224 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000225
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000226 v[3] |= kTextureBit;
227
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000228 return v[3] & kNPOTBit;
229}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000230
231// we should never have more than one stencil buffer with same combo of
232// (width,height,samplecount)
233void gen_stencil_key_values(int width, int height,
234 int sampleCnt, uint32_t v[4]) {
235 v[0] = width;
236 v[1] = height;
237 v[2] = sampleCnt;
238 v[3] = kStencilBufferBit;
239}
240
241void gen_stencil_key_values(const GrStencilBuffer* sb,
242 uint32_t v[4]) {
243 gen_stencil_key_values(sb->width(), sb->height(),
244 sb->numSamples(), v);
245}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000246
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000247void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000248 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
249 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
250 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
251 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000252}
253
bsalomon@google.comb505a122012-05-31 18:40:36 +0000254float adjust_sigma(float sigma, int *scaleFactor, int *radius) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000255 *scaleFactor = 1;
256 while (sigma > MAX_BLUR_SIGMA) {
257 *scaleFactor *= 2;
258 sigma *= 0.5f;
259 }
bsalomon@google.comb505a122012-05-31 18:40:36 +0000260 *radius = static_cast<int>(ceilf(sigma * 3.0f));
261 GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000262 return sigma;
263}
264
265void apply_morphology(GrGpu* gpu,
266 GrTexture* texture,
267 const SkRect& rect,
268 int radius,
bsalomon@google.comb505a122012-05-31 18:40:36 +0000269 GrContext::MorphologyType morphType,
270 Gr1DKernelEffect::Direction direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000271
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000272 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
273 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000274 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000275 drawState->setRenderTarget(target);
276 GrMatrix sampleM;
277 sampleM.setIDiv(texture->width(), texture->height());
bsalomon@google.comb505a122012-05-31 18:40:36 +0000278 drawState->sampler(0)->reset(sampleM);
279 SkAutoTUnref<GrCustomStage> morph(
280 new GrMorphologyEffect(direction, radius, morphType));
281 drawState->sampler(0)->setCustomStage(morph);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000282 drawState->setTexture(0, texture);
283 gpu->drawSimpleRect(rect, NULL, 1 << 0);
284}
285
bsalomon@google.comb505a122012-05-31 18:40:36 +0000286void convolve_gaussian(GrGpu* gpu,
287 GrTexture* texture,
288 const SkRect& rect,
289 float sigma,
290 int radius,
291 Gr1DKernelEffect::Direction direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000292 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
293 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000294 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000295 drawState->setRenderTarget(target);
296 GrMatrix sampleM;
297 sampleM.setIDiv(texture->width(), texture->height());
bsalomon@google.comb505a122012-05-31 18:40:36 +0000298 drawState->sampler(0)->reset(sampleM);
299 SkAutoTUnref<GrConvolutionEffect> conv(new
300 GrConvolutionEffect(direction, radius));
301 conv->setGaussianKernel(sigma);
302 drawState->sampler(0)->setCustomStage(conv);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000303 drawState->setTexture(0, texture);
304 gpu->drawSimpleRect(rect, NULL, 1 << 0);
305}
306
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000307}
308
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000309GrContext::TextureCacheEntry GrContext::findAndLockTexture(
310 TextureKey key,
311 int width,
312 int height,
313 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000314 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000315 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000316 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000317 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
318 GrResourceCache::kNested_LockType));
319}
320
bsalomon@google.comfb309512011-11-30 14:13:48 +0000321bool GrContext::isTextureInCache(TextureKey key,
322 int width,
323 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000324 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000325 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000326 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000327 GrResourceKey resourceKey(v);
328 return fTextureCache->hasKey(resourceKey);
329}
330
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000331GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000332 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000333 uint32_t v[4];
334 gen_stencil_key_values(sb, v);
335 GrResourceKey resourceKey(v);
336 return fTextureCache->createAndLock(resourceKey, sb);
337}
338
339GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
340 int sampleCnt) {
341 uint32_t v[4];
342 gen_stencil_key_values(width, height, sampleCnt, v);
343 GrResourceKey resourceKey(v);
344 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
345 GrResourceCache::kSingle_LockType);
346 if (NULL != entry) {
347 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
348 return sb;
349 } else {
350 return NULL;
351 }
352}
353
354void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000355 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000356 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000357}
358
359static void stretchImage(void* dst,
360 int dstW,
361 int dstH,
362 void* src,
363 int srcW,
364 int srcH,
365 int bpp) {
366 GrFixed dx = (srcW << 16) / dstW;
367 GrFixed dy = (srcH << 16) / dstH;
368
369 GrFixed y = dy >> 1;
370
371 int dstXLimit = dstW*bpp;
372 for (int j = 0; j < dstH; ++j) {
373 GrFixed x = dx >> 1;
374 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
375 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
376 for (int i = 0; i < dstXLimit; i += bpp) {
377 memcpy((uint8_t*) dstRow + i,
378 (uint8_t*) srcRow + (x>>16)*bpp,
379 bpp);
380 x += dx;
381 }
382 y += dy;
383 }
384}
385
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000386GrContext::TextureCacheEntry GrContext::createAndLockTexture(
387 TextureKey key,
388 const GrSamplerState* sampler,
389 const GrTextureDesc& desc,
390 void* srcData,
391 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000392 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000393
394#if GR_DUMP_TEXTURE_UPLOAD
395 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
396#endif
397
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000398 TextureCacheEntry entry;
399 uint32_t v[4];
400 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000401 desc.fWidth, desc.fHeight,
402 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000404
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000405 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000406 GrAssert(NULL != sampler);
407 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
408 desc.fWidth,
409 desc.fHeight,
410 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000411
412 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000413 clampEntry = this->createAndLockTexture(key, NULL, desc,
414 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000415 GrAssert(NULL != clampEntry.texture());
416 if (NULL == clampEntry.texture()) {
417 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418 }
419 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000420 GrTextureDesc rtDesc = desc;
421 rtDesc.fFlags = rtDesc.fFlags |
422 kRenderTarget_GrTextureFlagBit |
423 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000424 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
425 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000426
427 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
428
429 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000430 GrDrawTarget::AutoStateRestore asr(fGpu,
431 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000432 GrDrawState* drawState = fGpu->drawState();
433 drawState->setRenderTarget(texture->asRenderTarget());
434 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000435
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000436 GrSamplerState::Filter filter;
437 // if filtering is not desired then we want to ensure all
438 // texels in the resampled image are copies of texels from
439 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000440 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000441 filter = GrSamplerState::kNearest_Filter;
442 } else {
443 filter = GrSamplerState::kBilinear_Filter;
444 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000445 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
446 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000447
448 static const GrVertexLayout layout =
449 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
450 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
451
452 if (arg.succeeded()) {
453 GrPoint* verts = (GrPoint*) arg.vertices();
454 verts[0].setIRectFan(0, 0,
455 texture->width(),
456 texture->height(),
457 2*sizeof(GrPoint));
458 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
459 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
460 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000461 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000462 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000463 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000464 } else {
465 // TODO: Our CPU stretch doesn't filter. But we create separate
466 // stretched textures when the sampler state is either filtered or
467 // not. Either implement filtered stretch blit on CPU or just create
468 // one when FBO case fails.
469
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000470 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000471 // no longer need to clamp at min RT size.
472 rtDesc.fWidth = GrNextPow2(desc.fWidth);
473 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000474 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000475 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000476 rtDesc.fWidth *
477 rtDesc.fHeight);
478 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
479 srcData, desc.fWidth, desc.fHeight, bpp);
480
481 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
482
483 GrTexture* texture = fGpu->createTexture(rtDesc,
484 stretchedPixels.get(),
485 stretchedRowBytes);
486 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000487 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000488 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000489 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000490
491 } else {
492 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
493 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000494 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000495 }
496 }
497 return entry;
498}
499
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500namespace {
501inline void gen_scratch_tex_key_values(const GrGpu* gpu,
502 const GrTextureDesc& desc,
503 uint32_t v[4]) {
504 // Instead of a client-provided key of the texture contents
505 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000506 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000507 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000508 // this code path isn't friendly to tiling with NPOT restricitons
509 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000510 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000511 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000512}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000513}
514
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000515GrContext::TextureCacheEntry GrContext::lockScratchTexture(
516 const GrTextureDesc& inDesc,
517 ScratchTexMatch match) {
518
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000519 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000520 if (kExact_ScratchTexMatch != match) {
521 // bin by pow2 with a reasonable min
522 static const int MIN_SIZE = 256;
523 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
524 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
525 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000526
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000527 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000528 int origWidth = desc.fWidth;
529 int origHeight = desc.fHeight;
530 bool doubledW = false;
531 bool doubledH = false;
532
533 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000534 uint32_t v[4];
535 gen_scratch_tex_key_values(fGpu, desc, v);
536 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000537 entry = fTextureCache->findAndLock(key,
538 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000539 // if we miss, relax the fit of the flags...
540 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000541 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000542 break;
543 }
544 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
545 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
546 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
547 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
548 } else if (!doubledW) {
549 desc.fFlags = inDesc.fFlags;
550 desc.fWidth *= 2;
551 doubledW = true;
552 } else if (!doubledH) {
553 desc.fFlags = inDesc.fFlags;
554 desc.fWidth = origWidth;
555 desc.fHeight *= 2;
556 doubledH = true;
557 } else {
558 break;
559 }
560
561 } while (true);
562
563 if (NULL == entry) {
564 desc.fFlags = inDesc.fFlags;
565 desc.fWidth = origWidth;
566 desc.fHeight = origHeight;
567 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
568 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000569 uint32_t v[4];
570 gen_scratch_tex_key_values(fGpu, desc, v);
571 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000572 entry = fTextureCache->createAndLock(key, texture);
573 }
574 }
575
576 // If the caller gives us the same desc/sampler twice we don't want
577 // to return the same texture the second time (unless it was previously
578 // released). So we detach the entry from the cache and reattach at release.
579 if (NULL != entry) {
580 fTextureCache->detach(entry);
581 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000582 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000583}
584
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000585void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000586 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000587 // If this is a scratch texture we detached it from the cache
588 // while it was locked (to avoid two callers simultaneously getting
589 // the same texture).
590 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
591 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000592 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000593 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000594 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595}
596
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000597GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000598 void* srcData,
599 size_t rowBytes) {
600 return fGpu->createTexture(desc, srcData, rowBytes);
601}
602
603void GrContext::getTextureCacheLimits(int* maxTextures,
604 size_t* maxTextureBytes) const {
605 fTextureCache->getLimits(maxTextures, maxTextureBytes);
606}
607
608void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
609 fTextureCache->setLimits(maxTextures, maxTextureBytes);
610}
611
bsalomon@google.com91958362011-06-13 17:58:13 +0000612int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000613 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000614}
615
616int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000617 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000618}
619
620///////////////////////////////////////////////////////////////////////////////
621
bsalomon@google.come269f212011-11-07 13:29:52 +0000622GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
623 return fGpu->createPlatformTexture(desc);
624}
625
626GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
627 return fGpu->createPlatformRenderTarget(desc);
628}
629
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000630///////////////////////////////////////////////////////////////////////////////
631
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000632bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000633 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000634 const GrDrawTarget::Caps& caps = fGpu->getCaps();
635 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000636 return false;
637 }
638
bsalomon@google.com27847de2011-02-22 20:59:41 +0000639 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
640
641 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000642 bool tiled = NULL != sampler &&
643 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
644 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000645 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000646 return false;
647 }
648 }
649 return true;
650}
651
652////////////////////////////////////////////////////////////////////////////////
653
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000654const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
655
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656void GrContext::setClip(const GrClip& clip) {
657 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000658 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000659}
660
661void GrContext::setClip(const GrIRect& rect) {
662 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000663 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000664 fGpu->setClip(clip);
665}
666
667////////////////////////////////////////////////////////////////////////////////
668
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000669void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000670 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000671 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000672}
673
674void GrContext::drawPaint(const GrPaint& paint) {
675 // set rect to be big enough to fill the space, but not super-huge, so we
676 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000677 GrRect r;
678 r.setLTRB(0, 0,
679 GrIntToScalar(getRenderTarget()->width()),
680 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000681 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000682 SkTLazy<GrPaint> tmpPaint;
683 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000684 GrAutoMatrix am;
685
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000686 // We attempt to map r by the inverse matrix and draw that. mapRect will
687 // map the four corners and bound them with a new rect. This will not
688 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000689 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000690 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000691 GrPrintf("Could not invert matrix");
692 return;
693 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000694 inverse.mapRect(&r);
695 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000696 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000697 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000698 GrPrintf("Could not invert matrix");
699 return;
700 }
701 tmpPaint.set(paint);
702 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
703 p = tmpPaint.get();
704 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000705 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000706 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000707 // by definition this fills the entire clip, no need for AA
708 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000709 if (!tmpPaint.isValid()) {
710 tmpPaint.set(paint);
711 p = tmpPaint.get();
712 }
713 GrAssert(p == tmpPaint.get());
714 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000715 }
716 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000717}
718
bsalomon@google.com205d4602011-04-25 12:43:45 +0000719////////////////////////////////////////////////////////////////////////////////
720
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000721namespace {
722inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
723 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
724}
725}
726
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000727////////////////////////////////////////////////////////////////////////////////
728
bsalomon@google.com27847de2011-02-22 20:59:41 +0000729/* create a triangle strip that strokes the specified triangle. There are 8
730 unique vertices, but we repreat the last 2 to close up. Alternatively we
731 could use an indices array, and then only send 8 verts, but not sure that
732 would be faster.
733 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000734static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000735 GrScalar width) {
736 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000737 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000738
739 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
740 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
741 verts[2].set(rect.fRight - rad, rect.fTop + rad);
742 verts[3].set(rect.fRight + rad, rect.fTop - rad);
743 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
744 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
745 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
746 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
747 verts[8] = verts[0];
748 verts[9] = verts[1];
749}
750
bsalomon@google.com205d4602011-04-25 12:43:45 +0000751static void setInsetFan(GrPoint* pts, size_t stride,
752 const GrRect& r, GrScalar dx, GrScalar dy) {
753 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
754}
755
756static const uint16_t gFillAARectIdx[] = {
757 0, 1, 5, 5, 4, 0,
758 1, 2, 6, 6, 5, 1,
759 2, 3, 7, 7, 6, 2,
760 3, 0, 4, 4, 7, 3,
761 4, 5, 6, 6, 7, 4,
762};
763
764int GrContext::aaFillRectIndexCount() const {
765 return GR_ARRAY_COUNT(gFillAARectIdx);
766}
767
768GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
769 if (NULL == fAAFillRectIndexBuffer) {
770 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
771 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000772 if (NULL != fAAFillRectIndexBuffer) {
773 #if GR_DEBUG
774 bool updated =
775 #endif
776 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
777 sizeof(gFillAARectIdx));
778 GR_DEBUGASSERT(updated);
779 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000780 }
781 return fAAFillRectIndexBuffer;
782}
783
784static const uint16_t gStrokeAARectIdx[] = {
785 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
786 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
787 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
788 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
789
790 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
791 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
792 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
793 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
794
795 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
796 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
797 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
798 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
799};
800
801int GrContext::aaStrokeRectIndexCount() const {
802 return GR_ARRAY_COUNT(gStrokeAARectIdx);
803}
804
805GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
806 if (NULL == fAAStrokeRectIndexBuffer) {
807 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
808 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000809 if (NULL != fAAStrokeRectIndexBuffer) {
810 #if GR_DEBUG
811 bool updated =
812 #endif
813 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
814 sizeof(gStrokeAARectIdx));
815 GR_DEBUGASSERT(updated);
816 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000817 }
818 return fAAStrokeRectIndexBuffer;
819}
820
bsalomon@google.coma3108262011-10-10 14:08:47 +0000821static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
822 bool useCoverage) {
823 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000824 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000825 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000826 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
827 }
828 }
829 if (useCoverage) {
830 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
831 } else {
832 layout |= GrDrawTarget::kColor_VertexLayoutBit;
833 }
834 return layout;
835}
836
bsalomon@google.com205d4602011-04-25 12:43:45 +0000837void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000838 const GrRect& devRect,
839 bool useVertexCoverage) {
840 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000841
842 size_t vsize = GrDrawTarget::VertexSize(layout);
843
844 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000845 if (!geo.succeeded()) {
846 GrPrintf("Failed to get space for vertices!\n");
847 return;
848 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000849 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
850 if (NULL == indexBuffer) {
851 GrPrintf("Failed to create index buffer!\n");
852 return;
853 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000854
855 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
856
857 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
858 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
859
860 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
861 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
862
863 verts += sizeof(GrPoint);
864 for (int i = 0; i < 4; ++i) {
865 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
866 }
867
bsalomon@google.coma3108262011-10-10 14:08:47 +0000868 GrColor innerColor;
869 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000870 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000871 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000872 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000873 }
874
bsalomon@google.com205d4602011-04-25 12:43:45 +0000875 verts += 4 * vsize;
876 for (int i = 0; i < 4; ++i) {
877 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
878 }
879
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000880 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000881
882 target->drawIndexed(kTriangles_PrimitiveType, 0,
883 0, 8, this->aaFillRectIndexCount());
884}
885
bsalomon@google.coma3108262011-10-10 14:08:47 +0000886void GrContext::strokeAARect(GrDrawTarget* target,
887 const GrRect& devRect,
888 const GrVec& devStrokeSize,
889 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000890 const GrScalar& dx = devStrokeSize.fX;
891 const GrScalar& dy = devStrokeSize.fY;
892 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
893 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
894
bsalomon@google.com205d4602011-04-25 12:43:45 +0000895 GrScalar spare;
896 {
897 GrScalar w = devRect.width() - dx;
898 GrScalar h = devRect.height() - dy;
899 spare = GrMin(w, h);
900 }
901
902 if (spare <= 0) {
903 GrRect r(devRect);
904 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000905 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000906 return;
907 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000908 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000909 size_t vsize = GrDrawTarget::VertexSize(layout);
910
911 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000912 if (!geo.succeeded()) {
913 GrPrintf("Failed to get space for vertices!\n");
914 return;
915 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000916 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
917 if (NULL == indexBuffer) {
918 GrPrintf("Failed to create index buffer!\n");
919 return;
920 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000921
922 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
923
924 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
925 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
926 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
927 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
928
929 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
930 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
931 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
932 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
933
934 verts += sizeof(GrPoint);
935 for (int i = 0; i < 4; ++i) {
936 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
937 }
938
bsalomon@google.coma3108262011-10-10 14:08:47 +0000939 GrColor innerColor;
940 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000941 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000942 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000943 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000944 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000945 verts += 4 * vsize;
946 for (int i = 0; i < 8; ++i) {
947 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
948 }
949
950 verts += 8 * vsize;
951 for (int i = 0; i < 8; ++i) {
952 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
953 }
954
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000955 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000956 target->drawIndexed(kTriangles_PrimitiveType,
957 0, 0, 16, aaStrokeRectIndexCount());
958}
959
reed@google.com20efde72011-05-09 17:00:02 +0000960/**
961 * Returns true if the rects edges are integer-aligned.
962 */
963static bool isIRect(const GrRect& r) {
964 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
965 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
966}
967
bsalomon@google.com205d4602011-04-25 12:43:45 +0000968static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000969 const GrRect& rect,
970 GrScalar width,
971 const GrMatrix* matrix,
972 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000973 GrRect* devRect,
974 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000975 // we use a simple coverage ramp to do aa on axis-aligned rects
976 // we check if the rect will be axis-aligned, and the rect won't land on
977 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000978
bsalomon@google.coma3108262011-10-10 14:08:47 +0000979 // we are keeping around the "tweak the alpha" trick because
980 // it is our only hope for the fixed-pipe implementation.
981 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000982 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000983 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000984 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000985 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000986#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000987 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000988#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000989 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000990 } else {
991 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000992 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000993 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000994 const GrDrawState& drawState = target->getDrawState();
995 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000996 return false;
997 }
998
bsalomon@google.com471d4712011-08-23 15:45:25 +0000999 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001000 return false;
1001 }
1002
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001003 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001004 return false;
1005 }
1006
1007 if (NULL != matrix &&
1008 !matrix->preservesAxisAlignment()) {
1009 return false;
1010 }
1011
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001012 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001013 if (NULL != matrix) {
1014 combinedMatrix->preConcat(*matrix);
1015 GrAssert(combinedMatrix->preservesAxisAlignment());
1016 }
1017
1018 combinedMatrix->mapRect(devRect, rect);
1019 devRect->sort();
1020
1021 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001022 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001023 } else {
1024 return true;
1025 }
1026}
1027
bsalomon@google.com27847de2011-02-22 20:59:41 +00001028void GrContext::drawRect(const GrPaint& paint,
1029 const GrRect& rect,
1030 GrScalar width,
1031 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001032 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001033
1034 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001035 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001036
bsalomon@google.com205d4602011-04-25 12:43:45 +00001037 GrRect devRect = rect;
1038 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001039 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001040 bool needAA = paint.fAntiAlias &&
1041 !this->getRenderTarget()->isMultisampled();
1042 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1043 &combinedMatrix, &devRect,
1044 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001045
1046 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001047 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001048 if (width >= 0) {
1049 GrVec strokeSize;;
1050 if (width > 0) {
1051 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001052 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001053 strokeSize.setAbs(strokeSize);
1054 } else {
1055 strokeSize.set(GR_Scalar1, GR_Scalar1);
1056 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001057 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001058 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001059 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060 }
1061 return;
1062 }
1063
bsalomon@google.com27847de2011-02-22 20:59:41 +00001064 if (width >= 0) {
1065 // TODO: consider making static vertex buffers for these cases.
1066 // Hairline could be done by just adding closing vertex to
1067 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001068 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1069
bsalomon@google.com27847de2011-02-22 20:59:41 +00001070 static const int worstCaseVertCount = 10;
1071 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1072
1073 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001074 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001075 return;
1076 }
1077
1078 GrPrimitiveType primType;
1079 int vertCount;
1080 GrPoint* vertex = geo.positions();
1081
1082 if (width > 0) {
1083 vertCount = 10;
1084 primType = kTriangleStrip_PrimitiveType;
1085 setStrokeRectStrip(vertex, rect, width);
1086 } else {
1087 // hairline
1088 vertCount = 5;
1089 primType = kLineStrip_PrimitiveType;
1090 vertex[0].set(rect.fLeft, rect.fTop);
1091 vertex[1].set(rect.fRight, rect.fTop);
1092 vertex[2].set(rect.fRight, rect.fBottom);
1093 vertex[3].set(rect.fLeft, rect.fBottom);
1094 vertex[4].set(rect.fLeft, rect.fTop);
1095 }
1096
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001097 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001098 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001099 GrDrawState* drawState = target->drawState();
1100 avmr.set(drawState);
1101 drawState->preConcatViewMatrix(*matrix);
1102 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001103 }
1104
1105 target->drawNonIndexed(primType, 0, vertCount);
1106 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001107#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001108 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001109 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1110 if (NULL == sqVB) {
1111 GrPrintf("Failed to create static rect vb.\n");
1112 return;
1113 }
1114 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001115 GrDrawState* drawState = target->drawState();
1116 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001117 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001118 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001119 0, rect.height(), rect.fTop,
1120 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001121
1122 if (NULL != matrix) {
1123 m.postConcat(*matrix);
1124 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001125 drawState->preConcatViewMatrix(m);
1126 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001127
bsalomon@google.com27847de2011-02-22 20:59:41 +00001128 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001129#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001130 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001131#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001132 }
1133}
1134
1135void GrContext::drawRectToRect(const GrPaint& paint,
1136 const GrRect& dstRect,
1137 const GrRect& srcRect,
1138 const GrMatrix* dstMatrix,
1139 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001140 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001141
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001142 // srcRect refers to paint's first texture
1143 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001144 drawRect(paint, dstRect, -1, dstMatrix);
1145 return;
1146 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001147
bsalomon@google.com27847de2011-02-22 20:59:41 +00001148 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1149
1150#if GR_STATIC_RECT_VB
1151 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001152 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001153 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001154 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001155
1156 GrMatrix m;
1157
1158 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1159 0, dstRect.height(), dstRect.fTop,
1160 0, 0, GrMatrix::I()[8]);
1161 if (NULL != dstMatrix) {
1162 m.postConcat(*dstMatrix);
1163 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001164 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001165
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001166 // srcRect refers to first stage
1167 int otherStageMask = paint.getActiveStageMask() &
1168 (~(1 << GrPaint::kFirstTextureStage));
1169 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001170 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001171 }
1172
bsalomon@google.com27847de2011-02-22 20:59:41 +00001173 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1174 0, srcRect.height(), srcRect.fTop,
1175 0, 0, GrMatrix::I()[8]);
1176 if (NULL != srcMatrix) {
1177 m.postConcat(*srcMatrix);
1178 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001179 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001180
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001181 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1182 if (NULL == sqVB) {
1183 GrPrintf("Failed to create static rect vb.\n");
1184 return;
1185 }
1186 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001187 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1188#else
1189
1190 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001191#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001192 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001193#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001194 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1195#endif
1196
tomhudson@google.com93813632011-10-27 20:21:16 +00001197 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1198 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001199 srcRects[0] = &srcRect;
1200 srcMatrices[0] = srcMatrix;
1201
1202 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1203#endif
1204}
1205
1206void GrContext::drawVertices(const GrPaint& paint,
1207 GrPrimitiveType primitiveType,
1208 int vertexCount,
1209 const GrPoint positions[],
1210 const GrPoint texCoords[],
1211 const GrColor colors[],
1212 const uint16_t indices[],
1213 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001214 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001215
1216 GrDrawTarget::AutoReleaseGeometry geo;
1217
1218 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1219
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001220 bool hasTexCoords[GrPaint::kTotalStages] = {
1221 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1222 0 // remaining stages use positions
1223 };
1224
1225 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001226
1227 if (NULL != colors) {
1228 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001230 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001231
1232 if (sizeof(GrPoint) != vertexSize) {
1233 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001234 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001235 return;
1236 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001237 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001238 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001239 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1240 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001241 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001242 NULL,
1243 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001244 void* curVertex = geo.vertices();
1245
1246 for (int i = 0; i < vertexCount; ++i) {
1247 *((GrPoint*)curVertex) = positions[i];
1248
1249 if (texOffsets[0] > 0) {
1250 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1251 }
1252 if (colorOffset > 0) {
1253 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1254 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001255 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001256 }
1257 } else {
1258 target->setVertexSourceToArray(layout, positions, vertexCount);
1259 }
1260
bsalomon@google.com91958362011-06-13 17:58:13 +00001261 // we don't currently apply offscreen AA to this path. Need improved
1262 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001263
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001264 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001265 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001266 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001267 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001268 target->drawNonIndexed(primitiveType, 0, vertexCount);
1269 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001270}
1271
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001272///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001273namespace {
1274
bsalomon@google.com93c96602012-04-27 13:05:21 +00001275struct CircleVertex {
1276 GrPoint fPos;
1277 GrPoint fCenter;
1278 GrScalar fOuterRadius;
1279 GrScalar fInnerRadius;
1280};
1281
1282/* Returns true if will map a circle to another circle. This can be true
1283 * if the matrix only includes square-scale, rotation, translation.
1284 */
1285inline bool isSimilarityTransformation(const SkMatrix& matrix,
1286 SkScalar tol = SK_ScalarNearlyZero) {
1287 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1288 return true;
1289 }
1290 if (matrix.hasPerspective()) {
1291 return false;
1292 }
1293
1294 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1295 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1296 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1297 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1298
1299 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1300 return false;
1301 }
1302
1303 // it has scales or skews, but it could also be rotation, check it out.
1304 SkVector vec[2];
1305 vec[0].set(mx, sx);
1306 vec[1].set(sy, my);
1307
1308 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1309 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1310 SkScalarSquare(tol));
1311}
1312
1313}
1314
1315// TODO: strokeWidth can't be larger than zero right now.
1316// It will be fixed when drawPath() can handle strokes.
1317void GrContext::drawOval(const GrPaint& paint,
1318 const GrRect& rect,
1319 SkScalar strokeWidth) {
1320 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1321 kUnbuffered_DrawCategory;
1322 GrDrawTarget* target = this->prepareToDraw(paint, category);
1323 GrDrawState* drawState = target->drawState();
1324 GrMatrix vm = drawState->getViewMatrix();
1325
1326 if (!isSimilarityTransformation(vm) ||
1327 !paint.fAntiAlias ||
1328 rect.height() != rect.width()) {
1329 SkPath path;
1330 path.addOval(rect);
1331 GrPathFill fill = (strokeWidth == 0) ?
1332 kHairLine_PathFill : kWinding_PathFill;
1333 this->internalDrawPath(paint, path, fill, NULL);
1334 return;
1335 }
1336
1337 const GrRenderTarget* rt = drawState->getRenderTarget();
1338 if (NULL == rt) {
1339 return;
1340 }
1341
1342 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1343
1344 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1345 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1346 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1347
1348 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1349 GrScalar radius = SkScalarHalf(rect.width());
1350
1351 vm.mapPoints(&center, 1);
1352 radius = vm.mapRadius(radius);
1353
1354 GrScalar outerRadius = radius;
1355 GrScalar innerRadius = 0;
1356 SkScalar halfWidth = 0;
1357 if (strokeWidth == 0) {
1358 halfWidth = SkScalarHalf(SK_Scalar1);
1359
1360 outerRadius += halfWidth;
1361 innerRadius = SkMaxScalar(0, radius - halfWidth);
1362 }
1363
1364 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1365 if (!geo.succeeded()) {
1366 GrPrintf("Failed to get space for vertices!\n");
1367 return;
1368 }
1369
1370 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1371
1372 SkScalar L = center.fX - outerRadius;
1373 SkScalar R = center.fX + outerRadius;
1374 SkScalar T = center.fY - outerRadius;
1375 SkScalar B = center.fY + outerRadius;
1376
1377 verts[0].fPos = SkPoint::Make(L, T);
1378 verts[1].fPos = SkPoint::Make(R, T);
1379 verts[2].fPos = SkPoint::Make(L, B);
1380 verts[3].fPos = SkPoint::Make(R, B);
1381
1382 for (int i = 0; i < 4; ++i) {
1383 // this goes to fragment shader, it should be in y-points-up space.
1384 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1385
1386 verts[i].fOuterRadius = outerRadius;
1387 verts[i].fInnerRadius = innerRadius;
1388 }
1389
1390 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1391 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001392}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001393
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001394void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001395 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001396
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001397 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001398 if (GrIsFillInverted(fill)) {
1399 this->drawPaint(paint);
1400 }
1401 return;
1402 }
1403
bsalomon@google.com93c96602012-04-27 13:05:21 +00001404 SkRect ovalRect;
1405 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1406 if (translate) {
1407 ovalRect.offset(*translate);
1408 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001409 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001410 this->drawOval(paint, ovalRect, width);
1411 return;
1412 }
1413
1414 internalDrawPath(paint, path, fill, translate);
1415}
1416
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001417void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001418 GrPathFill fill, const GrPoint* translate) {
1419
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001420 // Note that below we may sw-rasterize the path into a scratch texture.
1421 // Scratch textures can be recycled after they are returned to the texture
1422 // cache. This presents a potential hazard for buffered drawing. However,
1423 // the writePixels that uploads to the scratch will perform a flush so we're
1424 // OK.
1425 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1426 kUnbuffered_DrawCategory;
1427 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001428 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001429
bsalomon@google.com289533a2011-10-27 12:34:25 +00001430 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1431
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001432 // An Assumption here is that path renderer would use some form of tweaking
1433 // the src color (either the input alpha or in the frag shader) to implement
1434 // aa. If we have some future driver-mojo path AA that can do the right
1435 // thing WRT to the blend then we'll need some query on the PR.
1436 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001437#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001438 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001439#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001440 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001441 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001442
robertphillips@google.com72176b22012-05-23 13:19:12 +00001443 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA, true);
bsalomon@google.com30085192011-08-19 15:42:31 +00001444 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001445#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001446 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001447#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001448 return;
1449 }
1450
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001451 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001452}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001453
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454////////////////////////////////////////////////////////////////////////////////
1455
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001456void GrContext::flush(int flagsBitfield) {
1457 if (kDiscard_FlushBit & flagsBitfield) {
1458 fDrawBuffer->reset();
1459 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001460 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001461 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001462 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463 fGpu->forceRenderTargetFlush();
1464 }
1465}
1466
bsalomon@google.com27847de2011-02-22 20:59:41 +00001467void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001468 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001469 // With addition of the AA clip path, flushing the draw buffer can
1470 // result in the generation of an AA clip mask. During this
1471 // process the SW path renderer may be invoked which recusively
1472 // calls this method (via internalWriteTexturePixels) creating
1473 // infinite recursion
1474 GrInOrderDrawBuffer* temp = fDrawBuffer;
1475 fDrawBuffer = NULL;
1476
1477 temp->flushTo(fGpu);
1478
1479 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001480 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481}
1482
bsalomon@google.com6f379512011-11-16 20:36:03 +00001483void GrContext::internalWriteTexturePixels(GrTexture* texture,
1484 int left, int top,
1485 int width, int height,
1486 GrPixelConfig config,
1487 const void* buffer,
1488 size_t rowBytes,
1489 uint32_t flags) {
1490 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001491 ASSERT_OWNED_RESOURCE(texture);
1492
bsalomon@google.com6f379512011-11-16 20:36:03 +00001493 if (!(kDontFlush_PixelOpsFlag & flags)) {
1494 this->flush();
1495 }
1496 // TODO: use scratch texture to perform conversion
1497 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1498 GrPixelConfigIsUnpremultiplied(config)) {
1499 return;
1500 }
1501
1502 fGpu->writeTexturePixels(texture, left, top, width, height,
1503 config, buffer, rowBytes);
1504}
1505
1506bool GrContext::internalReadTexturePixels(GrTexture* texture,
1507 int left, int top,
1508 int width, int height,
1509 GrPixelConfig config,
1510 void* buffer,
1511 size_t rowBytes,
1512 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001513 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001514 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001515
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001516 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001517 GrRenderTarget* target = texture->asRenderTarget();
1518 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001519 return this->internalReadRenderTargetPixels(target,
1520 left, top, width, height,
1521 config, buffer, rowBytes,
1522 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001523 } else {
1524 return false;
1525 }
1526}
1527
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001528#include "SkConfig8888.h"
1529
1530namespace {
1531/**
1532 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1533 * formats are representable as Config8888 and so the function returns false
1534 * if the GrPixelConfig has no equivalent Config8888.
1535 */
1536bool grconfig_to_config8888(GrPixelConfig config,
1537 SkCanvas::Config8888* config8888) {
1538 switch (config) {
1539 case kRGBA_8888_PM_GrPixelConfig:
1540 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1541 return true;
1542 case kRGBA_8888_UPM_GrPixelConfig:
1543 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1544 return true;
1545 case kBGRA_8888_PM_GrPixelConfig:
1546 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1547 return true;
1548 case kBGRA_8888_UPM_GrPixelConfig:
1549 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1550 return true;
1551 default:
1552 return false;
1553 }
1554}
1555}
1556
bsalomon@google.com6f379512011-11-16 20:36:03 +00001557bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1558 int left, int top,
1559 int width, int height,
1560 GrPixelConfig config,
1561 void* buffer,
1562 size_t rowBytes,
1563 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001564 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001565 ASSERT_OWNED_RESOURCE(target);
1566
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001567 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001568 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001569 if (NULL == target) {
1570 return false;
1571 }
1572 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001573
bsalomon@google.com6f379512011-11-16 20:36:03 +00001574 if (!(kDontFlush_PixelOpsFlag & flags)) {
1575 this->flush();
1576 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001577
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001578 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1579 GrPixelConfigIsUnpremultiplied(config) &&
1580 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1581 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1582 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1583 !grconfig_to_config8888(config, &dstConfig8888)) {
1584 return false;
1585 }
1586 // do read back using target's own config
1587 this->internalReadRenderTargetPixels(target,
1588 left, top,
1589 width, height,
1590 target->config(),
1591 buffer, rowBytes,
1592 kDontFlush_PixelOpsFlag);
1593 // sw convert the pixels to unpremul config
1594 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1595 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1596 pixels, rowBytes, srcConfig8888,
1597 width, height);
1598 return true;
1599 }
1600
bsalomon@google.comc4364992011-11-07 15:54:49 +00001601 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001602 bool swapRAndB = NULL != src &&
1603 fGpu->preferredReadPixelsConfig(config) ==
1604 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001605
1606 bool flipY = NULL != src &&
1607 fGpu->readPixelsWillPayForYFlip(target, left, top,
1608 width, height, config,
1609 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001610 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1611 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001612
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001613 if (NULL == src && alphaConversion) {
1614 // we should fallback to cpu conversion here. This could happen when
1615 // we were given an external render target by the client that is not
1616 // also a texture (e.g. FBO 0 in GL)
1617 return false;
1618 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001619 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001620 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001621 if (flipY || swapRAndB || alphaConversion) {
1622 GrAssert(NULL != src);
1623 if (swapRAndB) {
1624 config = GrPixelConfigSwapRAndB(config);
1625 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001626 }
1627 // Make the scratch a render target because we don't have a robust
1628 // readTexturePixels as of yet (it calls this function).
1629 const GrTextureDesc desc = {
1630 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001631 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001632 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001633 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001634 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001635
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001636 // When a full readback is faster than a partial we could always make
1637 // the scratch exactly match the passed rect. However, if we see many
1638 // different size rectangles we will trash our texture cache and pay the
1639 // cost of creating and destroying many textures. So, we only request
1640 // an exact match when the caller is reading an entire RT.
1641 ScratchTexMatch match = kApprox_ScratchTexMatch;
1642 if (0 == left &&
1643 0 == top &&
1644 target->width() == width &&
1645 target->height() == height &&
1646 fGpu->fullReadPixelsIsFasterThanPartial()) {
1647 match = kExact_ScratchTexMatch;
1648 }
1649 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001650 GrTexture* texture = ast.texture();
1651 if (!texture) {
1652 return false;
1653 }
1654 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001655 GrAssert(NULL != target);
1656
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001657 GrDrawTarget::AutoStateRestore asr(fGpu,
1658 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001659 GrDrawState* drawState = fGpu->drawState();
1660 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001661
bsalomon@google.comc4364992011-11-07 15:54:49 +00001662 GrMatrix matrix;
1663 if (flipY) {
1664 matrix.setTranslate(SK_Scalar1 * left,
1665 SK_Scalar1 * (top + height));
1666 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1667 } else {
1668 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1669 }
1670 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001671 drawState->sampler(0)->reset(matrix);
1672 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001673 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001674 GrRect rect;
1675 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1676 fGpu->drawSimpleRect(rect, NULL, 0x1);
1677 left = 0;
1678 top = 0;
1679 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001680 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001681 left, top, width, height,
1682 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001683}
1684
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001685void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1686 GrAssert(target);
1687 ASSERT_OWNED_RESOURCE(target);
1688 // In the future we may track whether there are any pending draws to this
1689 // target. We don't today so we always perform a flush. We don't promise
1690 // this to our clients, though.
1691 this->flush();
1692 fGpu->resolveRenderTarget(target);
1693}
1694
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001695void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1696 if (NULL == src || NULL == dst) {
1697 return;
1698 }
1699 ASSERT_OWNED_RESOURCE(src);
1700
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001701 // Writes pending to the source texture are not tracked, so a flush
1702 // is required to ensure that the copy captures the most recent contents
1703 // of the source texture. See similar behaviour in
1704 // GrContext::resolveRenderTarget.
1705 this->flush();
1706
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001707 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001708 GrDrawState* drawState = fGpu->drawState();
1709 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001710 GrMatrix sampleM;
1711 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001712 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001713 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001714 SkRect rect = SkRect::MakeXYWH(0, 0,
1715 SK_Scalar1 * src->width(),
1716 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001717 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1718}
1719
bsalomon@google.com6f379512011-11-16 20:36:03 +00001720void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1721 int left, int top,
1722 int width, int height,
1723 GrPixelConfig config,
1724 const void* buffer,
1725 size_t rowBytes,
1726 uint32_t flags) {
1727 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001728 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001729
1730 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001731 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001732 if (NULL == target) {
1733 return;
1734 }
1735 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001736
1737 // TODO: when underlying api has a direct way to do this we should use it
1738 // (e.g. glDrawPixels on desktop GL).
1739
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001740 // If the RT is also a texture and we don't have to do PM/UPM conversion
1741 // then take the texture path, which we expect to be at least as fast or
1742 // faster since it doesn't use an intermediate texture as we do below.
1743
1744#if !GR_MAC_BUILD
1745 // At least some drivers on the Mac get confused when glTexImage2D is called
1746 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1747 // determine what OS versions and/or HW is affected.
1748 if (NULL != target->asTexture() &&
1749 GrPixelConfigIsUnpremultiplied(target->config()) ==
1750 GrPixelConfigIsUnpremultiplied(config)) {
1751
1752 this->internalWriteTexturePixels(target->asTexture(),
1753 left, top, width, height,
1754 config, buffer, rowBytes, flags);
1755 return;
1756 }
1757#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001758 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1759 GrPixelConfigIsUnpremultiplied(config) &&
1760 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1761 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1762 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1763 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1764 return;
1765 }
1766 // allocate a tmp buffer and sw convert the pixels to premul
1767 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1768 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1769 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1770 src, rowBytes, srcConfig8888,
1771 width, height);
1772 // upload the already premul pixels
1773 this->internalWriteRenderTargetPixels(target,
1774 left, top,
1775 width, height,
1776 target->config(),
1777 tmpPixels, 4 * width, flags);
1778 return;
1779 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001780
1781 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1782 GrPixelConfigSwapRAndB(config);
1783 if (swapRAndB) {
1784 config = GrPixelConfigSwapRAndB(config);
1785 }
1786
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001787 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001788 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001789 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001790 GrAutoScratchTexture ast(this, desc);
1791 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001792 if (NULL == texture) {
1793 return;
1794 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001795 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1796 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001797
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001798 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001799 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001800
1801 GrMatrix matrix;
1802 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001803 drawState->setViewMatrix(matrix);
1804 drawState->setRenderTarget(target);
1805 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001806
bsalomon@google.com5c638652011-07-18 19:31:59 +00001807 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001808 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1809 GrSamplerState::kNearest_Filter,
1810 matrix);
1811 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001812
1813 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1814 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001815 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001816 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1817 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001818 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001819 return;
1820 }
1821 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1822 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1823}
1824////////////////////////////////////////////////////////////////////////////////
1825
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001826void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001827
1828 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1829 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001830 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001831 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001832 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001833 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001834 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001835 }
1836
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001837 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001838
1839 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1840 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001841 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001842 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001843 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001844 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001845 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001846 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001847
1848 // disable all stages not accessible via the paint
1849 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001850 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001851 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001852
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001853 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001854
1855 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001856 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001857 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001858 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001859 }
1860 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001861 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001862 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001863 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001864 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001865 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001866 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1867 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001868 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001869 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001870 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001871 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1872 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1873 fDrawState->setCoverage(paint.fCoverage);
reed@google.com4b2d3f32012-05-15 18:05:50 +00001874#if GR_DEBUG_PARTIAL_COVERAGE_CHECK
bsalomon@google.come79c8152012-03-29 19:07:12 +00001875 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001876 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001877 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1878 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001879#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001880}
1881
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001882GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001883 DrawCategory category) {
1884 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001885 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001886 fLastDrawCategory = category;
1887 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001888 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889 GrDrawTarget* target = fGpu;
1890 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001891 case kUnbuffered_DrawCategory:
1892 target = fGpu;
1893 break;
1894 case kBuffered_DrawCategory:
1895 target = fDrawBuffer;
1896 fDrawBuffer->setClip(fGpu->getClip());
1897 break;
1898 default:
1899 GrCrash("Unexpected DrawCategory.");
1900 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001901 }
1902 return target;
1903}
1904
robertphillips@google.com72176b22012-05-23 13:19:12 +00001905/*
1906 * This method finds a path renderer that can draw the specified path on
1907 * the provided target.
1908 * Due to its expense, the software path renderer has split out so it can
1909 * can be individually allowed/disallowed via the "allowSW" boolean.
1910 */
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001911GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001912 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001913 const GrDrawTarget* target,
robertphillips@google.com72176b22012-05-23 13:19:12 +00001914 bool antiAlias,
1915 bool allowSW) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001916 if (NULL == fPathRendererChain) {
1917 fPathRendererChain =
1918 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1919 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001920
1921 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path, fill,
1922 target,
1923 antiAlias);
1924
1925 if (NULL == pr && allowSW) {
1926 if (NULL == fSoftwarePathRenderer) {
1927 fSoftwarePathRenderer = new GrSoftwarePathRenderer(this);
1928 }
1929
1930 pr = fSoftwarePathRenderer;
1931 }
1932
1933 return pr;
bsalomon@google.com30085192011-08-19 15:42:31 +00001934}
1935
bsalomon@google.com27847de2011-02-22 20:59:41 +00001936////////////////////////////////////////////////////////////////////////////////
1937
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001939 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001940 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001941 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001942 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001943 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001944}
1945
1946GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001947 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001948}
1949
1950const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001951 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001952}
1953
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001954bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1955 return fGpu->isConfigRenderable(config);
1956}
1957
bsalomon@google.com27847de2011-02-22 20:59:41 +00001958const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001959 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001960}
1961
1962void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001963 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001964}
1965
1966void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001967 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001968}
1969
1970static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1971 intptr_t mask = 1 << shift;
1972 if (pred) {
1973 bits |= mask;
1974 } else {
1975 bits &= ~mask;
1976 }
1977 return bits;
1978}
1979
1980void GrContext::resetStats() {
1981 fGpu->resetStats();
1982}
1983
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001984const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001985 return fGpu->getStats();
1986}
1987
1988void GrContext::printStats() const {
1989 fGpu->printStats();
1990}
1991
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001992GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993 fGpu = gpu;
1994 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001995 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001996
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001997 fDrawState = new GrDrawState();
1998 fGpu->setDrawState(fDrawState);
1999
bsalomon@google.com30085192011-08-19 15:42:31 +00002000 fPathRendererChain = NULL;
robertphillips@google.com72176b22012-05-23 13:19:12 +00002001 fSoftwarePathRenderer = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002002
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002003 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2004 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005 fFontCache = new GrFontCache(fGpu);
2006
2007 fLastDrawCategory = kUnbuffered_DrawCategory;
2008
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002009 fDrawBuffer = NULL;
2010 fDrawBufferVBAllocPool = NULL;
2011 fDrawBufferIBAllocPool = NULL;
2012
bsalomon@google.com205d4602011-04-25 12:43:45 +00002013 fAAFillRectIndexBuffer = NULL;
2014 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002015
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002016 this->setupDrawBuffer();
2017}
2018
2019void GrContext::setupDrawBuffer() {
2020
2021 GrAssert(NULL == fDrawBuffer);
2022 GrAssert(NULL == fDrawBufferVBAllocPool);
2023 GrAssert(NULL == fDrawBufferIBAllocPool);
2024
bsalomon@google.com92edd312012-04-04 21:40:21 +00002025#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002026 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002027 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002028 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2029 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002030 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002031 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002032 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002033 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2034
bsalomon@google.com471d4712011-08-23 15:45:25 +00002035 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2036 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002037 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002038#endif
2039
2040#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002041 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002042#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002043 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002044 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002045}
2046
bsalomon@google.com27847de2011-02-22 20:59:41 +00002047GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002048#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002049 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002050#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002051 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002052#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053}
2054
2055const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2056 return fGpu->getQuadIndexBuffer();
2057}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002058
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002059GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2060 GrAutoScratchTexture* temp1,
2061 GrAutoScratchTexture* temp2,
2062 const SkRect& rect,
2063 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002064 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002065 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2066 GrClip oldClip = this->getClip();
2067 GrTexture* origTexture = srcTexture;
2068 GrAutoMatrix avm(this, GrMatrix::I());
2069 SkIRect clearRect;
bsalomon@google.comb505a122012-05-31 18:40:36 +00002070 int scaleFactorX, radiusX;
2071 int scaleFactorY, radiusY;
2072 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX);
2073 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002074
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002075 SkRect srcRect(rect);
2076 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2077 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002078 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2079 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002080 this->setClip(srcRect);
2081
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002082 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2083 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2084 kAlpha_8_GrPixelConfig == srcTexture->config());
2085
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002086 const GrTextureDesc desc = {
2087 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002088 SkScalarFloorToInt(srcRect.width()),
2089 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002090 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002091 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002092 };
2093
2094 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002095 if (temp2) {
2096 temp2->set(this, desc);
2097 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002098
2099 GrTexture* dstTexture = temp1->texture();
2100 GrPaint paint;
2101 paint.reset();
2102 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2103
2104 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2105 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2106 srcTexture->height());
2107 this->setRenderTarget(dstTexture->asRenderTarget());
2108 SkRect dstRect(srcRect);
2109 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2110 i < scaleFactorY ? 0.5f : 1.0f);
2111 paint.setTexture(0, srcTexture);
2112 this->drawRectToRect(paint, dstRect, srcRect);
2113 srcRect = dstRect;
2114 SkTSwap(srcTexture, dstTexture);
2115 // If temp2 is non-NULL, don't render back to origTexture
2116 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2117 }
2118
robertphillips@google.com7a396332012-05-10 15:11:27 +00002119 SkIRect srcIRect;
2120 srcRect.roundOut(&srcIRect);
2121
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002122 if (sigmaX > 0.0f) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002123 if (scaleFactorX > 1) {
bsalomon@google.comb505a122012-05-31 18:40:36 +00002124 // Clear out a radius to the right of the srcRect to prevent the
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002125 // X convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002126 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002127 radiusX, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002128 this->clear(&clearRect, 0x0);
2129 }
2130
2131 this->setRenderTarget(dstTexture->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002132 convolve_gaussian(fGpu, srcTexture, srcRect, sigmaX, radiusX,
2133 Gr1DKernelEffect::kX_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002134 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002135 if (temp2 && dstTexture == origTexture) {
2136 dstTexture = temp2->texture();
2137 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002138 }
2139
2140 if (sigmaY > 0.0f) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002141 if (scaleFactorY > 1 || sigmaX > 0.0f) {
bsalomon@google.comb505a122012-05-31 18:40:36 +00002142 // Clear out a radius below the srcRect to prevent the Y
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002143 // convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002144 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002145 srcIRect.width(), radiusY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002146 this->clear(&clearRect, 0x0);
2147 }
2148
2149 this->setRenderTarget(dstTexture->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002150 convolve_gaussian(fGpu, srcTexture, srcRect, sigmaY, radiusY,
2151 Gr1DKernelEffect::kY_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002152 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002153 if (temp2 && dstTexture == origTexture) {
2154 dstTexture = temp2->texture();
2155 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002156 }
2157
2158 if (scaleFactorX > 1 || scaleFactorY > 1) {
2159 // Clear one pixel to the right and below, to accommodate bilinear
2160 // upsampling.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002161 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2162 srcIRect.width() + 1, 1);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002163 this->clear(&clearRect, 0x0);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002164 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2165 1, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002166 this->clear(&clearRect, 0x0);
2167 // FIXME: This should be mitchell, not bilinear.
2168 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2169 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2170 srcTexture->height());
2171 this->setRenderTarget(dstTexture->asRenderTarget());
2172 paint.setTexture(0, srcTexture);
2173 SkRect dstRect(srcRect);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002174 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002175 this->drawRectToRect(paint, dstRect, srcRect);
2176 srcRect = dstRect;
2177 SkTSwap(srcTexture, dstTexture);
2178 }
2179 this->setRenderTarget(oldRenderTarget);
2180 this->setClip(oldClip);
2181 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002182}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002183
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002184GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2185 const GrRect& rect,
2186 GrTexture* temp1, GrTexture* temp2,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002187 MorphologyType morphType,
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002188 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002189 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002190 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2191 GrAutoMatrix avm(this, GrMatrix::I());
2192 GrClip oldClip = this->getClip();
robertphillips@google.com7a396332012-05-10 15:11:27 +00002193 this->setClip(GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
2194 SkIntToScalar(srcTexture->height())));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002195 if (radius.fWidth > 0) {
2196 this->setRenderTarget(temp1->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002197 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, morphType,
2198 Gr1DKernelEffect::kX_Direction);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002199 SkIRect clearRect = SkIRect::MakeXYWH(
2200 SkScalarFloorToInt(rect.fLeft),
2201 SkScalarFloorToInt(rect.fBottom),
2202 SkScalarFloorToInt(rect.width()),
2203 radius.fHeight);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002204 this->clear(&clearRect, 0x0);
2205 srcTexture = temp1;
2206 }
2207 if (radius.fHeight > 0) {
2208 this->setRenderTarget(temp2->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002209 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, morphType,
2210 Gr1DKernelEffect::kY_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002211 srcTexture = temp2;
2212 }
2213 this->setRenderTarget(oldRenderTarget);
2214 this->setClip(oldClip);
2215 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002216}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002217
robertphillips@google.com49d9fd52012-05-23 11:44:08 +00002218void GrContext::postClipPush() {
2219 fGpu->postClipPush();
2220}
2221
2222void GrContext::preClipPop() {
2223 fGpu->preClipPop();
2224};
2225
bsalomon@google.comc4364992011-11-07 15:54:49 +00002226///////////////////////////////////////////////////////////////////////////////