blob: 419d9d9eb5da8f0c8bcc63ece90170e375bcdb05 [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
bsalomon@google.com27847de2011-02-22 20:59:41 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000018#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000019#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022#include "GrClipIterator.h"
23#include "GrIndexBuffer.h"
24#include "GrInOrderDrawBuffer.h"
25#include "GrBufferAllocPool.h"
26#include "GrPathRenderer.h"
27
bsalomon@google.com8295dc12011-05-02 12:53:34 +000028#define ENABLE_OFFSCREEN_AA 0
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000029
bsalomon@google.com27847de2011-02-22 20:59:41 +000030#define DEFER_TEXT_RENDERING 1
31
32#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
33
34static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
35static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
36
37static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
38static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
39
40// We are currently only batching Text and drawRectToRect, both
41// of which use the quad index buffer.
42static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
43static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
44
bsalomon@google.com05ef5102011-05-02 21:14:59 +000045GrContext* GrContext::Create(GrEngine engine,
46 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000047 GrContext* ctx = NULL;
48 GrGpu* fGpu = GrGpu::Create(engine, context3D);
49 if (NULL != fGpu) {
50 ctx = new GrContext(fGpu);
51 fGpu->unref();
52 }
53 return ctx;
54}
55
56GrContext* GrContext::CreateGLShaderContext() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +000057 return GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +000058}
59
60GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000061 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 delete fTextureCache;
63 delete fFontCache;
64 delete fDrawBuffer;
65 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000066 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000067 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000068 GrSafeUnref(fAAFillRectIndexBuffer);
69 GrSafeUnref(fAAStrokeRectIndexBuffer);
70 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000071}
72
bsalomon@google.com8fe72472011-03-30 21:26:44 +000073void GrContext::contextLost() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000074 // abandon first to so destructors
75 // don't try to free the resources in the API.
76 fGpu->abandonResources();
77
bsalomon@google.com8fe72472011-03-30 21:26:44 +000078 delete fDrawBuffer;
79 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000080
bsalomon@google.com8fe72472011-03-30 21:26:44 +000081 delete fDrawBufferVBAllocPool;
82 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000083
bsalomon@google.com8fe72472011-03-30 21:26:44 +000084 delete fDrawBufferIBAllocPool;
85 fDrawBufferIBAllocPool = NULL;
86
bsalomon@google.com205d4602011-04-25 12:43:45 +000087 GrSafeSetNull(fAAFillRectIndexBuffer);
88 GrSafeSetNull(fAAStrokeRectIndexBuffer);
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 fTextureCache->removeAll();
91 fFontCache->freeAll();
92 fGpu->markContextDirty();
93
bsalomon@google.com8fe72472011-03-30 21:26:44 +000094 this->setupDrawBuffer();
95}
96
97void GrContext::resetContext() {
98 fGpu->markContextDirty();
99}
100
101void GrContext::freeGpuResources() {
102 this->flush();
103 fTextureCache->removeAll();
104 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000105}
106
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000107////////////////////////////////////////////////////////////////////////////////
108
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000109int GrContext::PaintStageVertexLayoutBits(
110 const GrPaint& paint,
111 const bool hasTexCoords[GrPaint::kTotalStages]) {
112 int stageMask = paint.getActiveStageMask();
113 int layout = 0;
114 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
115 if ((1 << i) & stageMask) {
116 if (NULL != hasTexCoords && hasTexCoords[i]) {
117 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
118 } else {
119 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
120 }
121 }
122 }
123 return layout;
124}
125
126
127////////////////////////////////////////////////////////////////////////////////
128
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000129enum {
130 kNPOTBit = 0x1,
131 kFilterBit = 0x2,
132 kKeylessBit = 0x4,
133};
134
135bool GrContext::finalizeTextureKey(GrTextureKey* key,
136 const GrSamplerState& sampler,
137 bool keyless) const {
138 uint32_t bits = 0;
139 uint16_t width = key->width();
140 uint16_t height = key->height();
141
142 if (!fGpu->npotTextureTileSupport()) {
143 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
144
145 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
146 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
147
148 if (tiled && !isPow2) {
149 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000150 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000151 bits |= kFilterBit;
152 }
153 }
154 }
155
156 if (keyless) {
157 bits |= kKeylessBit;
158 }
159 key->finalize(bits);
160 return 0 != bits;
161}
162
bsalomon@google.com27847de2011-02-22 20:59:41 +0000163GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
164 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000165 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000166 return fTextureCache->findAndLock(*key);
167}
168
169static void stretchImage(void* dst,
170 int dstW,
171 int dstH,
172 void* src,
173 int srcW,
174 int srcH,
175 int bpp) {
176 GrFixed dx = (srcW << 16) / dstW;
177 GrFixed dy = (srcH << 16) / dstH;
178
179 GrFixed y = dy >> 1;
180
181 int dstXLimit = dstW*bpp;
182 for (int j = 0; j < dstH; ++j) {
183 GrFixed x = dx >> 1;
184 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
185 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
186 for (int i = 0; i < dstXLimit; i += bpp) {
187 memcpy((uint8_t*) dstRow + i,
188 (uint8_t*) srcRow + (x>>16)*bpp,
189 bpp);
190 x += dx;
191 }
192 y += dy;
193 }
194}
195
196GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
197 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000198 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000199 void* srcData, size_t rowBytes) {
200 GrAssert(key->width() == desc.fWidth);
201 GrAssert(key->height() == desc.fHeight);
202
203#if GR_DUMP_TEXTURE_UPLOAD
204 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
205#endif
206
207 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000208 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000209 if (special) {
210 GrTextureEntry* clampEntry;
211 GrTextureKey clampKey(*key);
212 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
213
214 if (NULL == clampEntry) {
215 clampEntry = createAndLockTexture(&clampKey,
216 GrSamplerState::ClampNoFilter(),
217 desc, srcData, rowBytes);
218 GrAssert(NULL != clampEntry);
219 if (NULL == clampEntry) {
220 return NULL;
221 }
222 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000223 GrTextureDesc rtDesc = desc;
224 rtDesc.fFlags = rtDesc.fFlags |
225 kRenderTarget_GrTextureFlagBit |
226 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000227 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
228 fGpu->minRenderTargetWidth()));
229 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
230 fGpu->minRenderTargetHeight()));
231
232 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
233
234 if (NULL != texture) {
235 GrDrawTarget::AutoStateRestore asr(fGpu);
236 fGpu->setRenderTarget(texture->asRenderTarget());
237 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000238 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000239 fGpu->setViewMatrix(GrMatrix::I());
240 fGpu->setAlpha(0xff);
241 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
242 fGpu->disableState(GrDrawTarget::kDither_StateBit |
243 GrDrawTarget::kClip_StateBit |
244 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000245 GrSamplerState::Filter filter;
246 // if filtering is not desired then we want to ensure all
247 // texels in the resampled image are copies of texels from
248 // the original.
249 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
250 filter = GrSamplerState::kNearest_Filter;
251 } else {
252 filter = GrSamplerState::kBilinear_Filter;
253 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000254 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
255 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000256 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000257 fGpu->setSamplerState(0, stretchSampler);
258
259 static const GrVertexLayout layout =
260 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
261 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
262
263 if (arg.succeeded()) {
264 GrPoint* verts = (GrPoint*) arg.vertices();
265 verts[0].setIRectFan(0, 0,
266 texture->width(),
267 texture->height(),
268 2*sizeof(GrPoint));
269 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
270 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
271 0, 4);
272 entry = fTextureCache->createAndLock(*key, texture);
273 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000274 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000275 } else {
276 // TODO: Our CPU stretch doesn't filter. But we create separate
277 // stretched textures when the sampler state is either filtered or
278 // not. Either implement filtered stretch blit on CPU or just create
279 // one when FBO case fails.
280
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000281 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000282 // no longer need to clamp at min RT size.
283 rtDesc.fWidth = GrNextPow2(desc.fWidth);
284 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000285 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000286 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
287 rtDesc.fWidth *
288 rtDesc.fHeight);
289 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
290 srcData, desc.fWidth, desc.fHeight, bpp);
291
292 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
293
294 GrTexture* texture = fGpu->createTexture(rtDesc,
295 stretchedPixels.get(),
296 stretchedRowBytes);
297 GrAssert(NULL != texture);
298 entry = fTextureCache->createAndLock(*key, texture);
299 }
300 fTextureCache->unlock(clampEntry);
301
302 } else {
303 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
304 if (NULL != texture) {
305 entry = fTextureCache->createAndLock(*key, texture);
306 } else {
307 entry = NULL;
308 }
309 }
310 return entry;
311}
312
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000313GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000314 uint32_t p0 = desc.fFormat;
315 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
316 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000317 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
318
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000319 GrTextureEntry* entry = fTextureCache->findAndLock(key);
320 if (NULL == entry) {
321 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
322 if (NULL != texture) {
323 entry = fTextureCache->createAndLock(key, texture);
324 }
325 }
326 // If the caller gives us the same desc/sampler twice we don't want
327 // to return the same texture the second time (unless it was previously
328 // released). So we detach the entry from the cache and reattach at release.
329 if (NULL != entry) {
330 fTextureCache->detach(entry);
331 }
332 return entry;
333}
334
bsalomon@google.com27847de2011-02-22 20:59:41 +0000335void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000336 if (kKeylessBit & entry->key().getPrivateBits()) {
337 fTextureCache->reattachAndUnlock(entry);
338 } else {
339 fTextureCache->unlock(entry);
340 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000341}
342
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000343GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000344 void* srcData,
345 size_t rowBytes) {
346 return fGpu->createTexture(desc, srcData, rowBytes);
347}
348
349void GrContext::getTextureCacheLimits(int* maxTextures,
350 size_t* maxTextureBytes) const {
351 fTextureCache->getLimits(maxTextures, maxTextureBytes);
352}
353
354void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
355 fTextureCache->setLimits(maxTextures, maxTextureBytes);
356}
357
358int GrContext::getMaxTextureDimension() {
359 return fGpu->maxTextureDimension();
360}
361
362///////////////////////////////////////////////////////////////////////////////
363
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000364GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
365 // validate flags here so that GrGpu subclasses don't have to check
366 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
367 0 != desc.fRenderTargetFlags) {
368 return NULL;
369 }
370 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
371 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
372 return NULL;
373 }
374 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
375 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
376 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
377 return NULL;
378 }
379 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000380}
381
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000382GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000383 return fGpu->createRenderTargetFrom3DApiState();
384}
385
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000386///////////////////////////////////////////////////////////////////////////////
387
bsalomon@google.com27847de2011-02-22 20:59:41 +0000388bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
389 int width, int height) {
390 if (!fGpu->supports8BitPalette()) {
391 return false;
392 }
393
394
395 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
396
397 if (!isPow2) {
398 if (!fGpu->npotTextureSupport()) {
399 return false;
400 }
401
402 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
403 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
404 if (tiled && !fGpu->npotTextureTileSupport()) {
405 return false;
406 }
407 }
408 return true;
409}
410
411////////////////////////////////////////////////////////////////////////////////
412
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000413const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
414
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415void GrContext::setClip(const GrClip& clip) {
416 fGpu->setClip(clip);
417 fGpu->enableState(GrDrawTarget::kClip_StateBit);
418}
419
420void GrContext::setClip(const GrIRect& rect) {
421 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000422 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000423 fGpu->setClip(clip);
424}
425
426////////////////////////////////////////////////////////////////////////////////
427
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000428void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000429 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000430 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000431}
432
433void GrContext::drawPaint(const GrPaint& paint) {
434 // set rect to be big enough to fill the space, but not super-huge, so we
435 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000436 GrRect r;
437 r.setLTRB(0, 0,
438 GrIntToScalar(getRenderTarget()->width()),
439 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000440 GrMatrix inverse;
441 if (fGpu->getViewInverse(&inverse)) {
442 inverse.mapRect(&r);
443 } else {
444 GrPrintf("---- fGpu->getViewInverse failed\n");
445 }
446 this->drawRect(paint, r);
447}
448
bsalomon@google.com205d4602011-04-25 12:43:45 +0000449////////////////////////////////////////////////////////////////////////////////
450
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000451bool GrContext::doOffscreenAA(GrDrawTarget* target,
452 const GrPaint& paint,
453 bool isLines) const {
454#if !ENABLE_OFFSCREEN_AA
455 return false;
456#else
457 if (!paint.fAntiAlias) {
458 return false;
459 }
460 if (isLines && fGpu->supportsAALines()) {
461 return false;
462 }
463 if (target->getRenderTarget()->isMultisampled()) {
464 return false;
465 }
466 // we have to be sure that the blend equation is expressible
467 // as simple src / dst coeffecients when the source
468 // is already modulated by the coverage fraction.
469 // We could use dual-source blending to get the correct per-pixel
470 // dst coeffecient for the remaining cases.
471 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
472 kOne_BlendCoeff != paint.fDstBlendCoeff &&
473 kISA_BlendCoeff != paint.fDstBlendCoeff) {
474 return false;
475 }
476 return true;
477#endif
478}
479
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000480bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
481 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000482 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000483 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000484 GrAssert(ENABLE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000485
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000486 GrAssert(NULL == record->fEntry0);
487 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000488
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000489 int boundW = boundRect.width();
490 int boundH = boundRect.height();
491 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000492
493 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000494 if (requireStencil) {
495 desc.fFlags = kRenderTarget_GrTextureFlagBit;
496 } else {
497 desc.fFlags = kRenderTarget_GrTextureFlagBit |
498 kNoStencil_GrTextureFlagBit;
499 }
500
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000501 desc.fFormat = kRGBA_8888_GrPixelConfig;
502
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000503 int scale;
504 // Using MSAA seems to be slower for some yet unknown reason.
505 if (false && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000506 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000507 scale = GR_Scalar1;
508 desc.fAALevel = kMed_GrAALevel;
509 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000510 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
511 OffscreenRecord::k4x4SinglePass_Downsample :
512 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000513 scale = 4;
514 desc.fAALevel = kNone_GrAALevel;
515 }
516
517 desc.fWidth = scale * size;
518 desc.fHeight = scale * size;
519
520 record->fEntry0 = this->lockKeylessTexture(desc);
521
522 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000523 return false;
524 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000525
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000526 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000527 desc.fWidth /= 2;
528 desc.fHeight /= 2;
529 record->fEntry1 = this->lockKeylessTexture(desc);
530 if (NULL == record->fEntry1) {
531 this->unlockTexture(record->fEntry0);
532 record->fEntry0 = NULL;
533 return false;
534 }
535 }
536
537 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
538 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000539
540 target->saveCurrentDrawState(&record->fSavedState);
541
542 GrPaint tempPaint;
543 tempPaint.reset();
544 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000545 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000546
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000547 GrMatrix transM;
548 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
549 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000550 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000551 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000552 target->postConcatViewMatrix(scaleM);
553
554 // clip gets applied in second pass
555 target->disableState(GrDrawTarget::kClip_StateBit);
556
reed@google.com20efde72011-05-09 17:00:02 +0000557 GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000558 target->clear(&clear, 0x0);
559
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000560 return true;
561}
562
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000563void GrContext::offscreenAAPass2(GrDrawTarget* target,
564 const GrPaint& paint,
565 const GrIRect& boundRect,
566 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000567
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000568 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000569
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000570 GrSamplerState::Filter filter;
571 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
572 filter = GrSamplerState::k4x4Downsample_Filter;
573 } else {
574 filter = GrSamplerState::kBilinear_Filter;
575 }
576
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000577 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000578 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000579 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000580
581 GrTexture* src = record->fEntry0->texture();
582 int scale;
583
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000584 enum {
585 kOffscreenStage = GrPaint::kTotalStages,
586 };
587
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000588 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
589 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000590 scale = 2;
591 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
592
593 // Do 2x2 downsample from first to second
594 target->setTexture(kOffscreenStage, src);
595 target->setRenderTarget(dst);
596 target->setViewMatrix(GrMatrix::I());
597 sampleM.setScale(scale * GR_Scalar1 / src->width(),
598 scale * GR_Scalar1 / src->height());
599 sampler.setMatrix(sampleM);
600 target->setSamplerState(kOffscreenStage, sampler);
reed@google.com20efde72011-05-09 17:00:02 +0000601 GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
602 scale * boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000603 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
604
605 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000606 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000607 scale = 1;
reed@google.com20efde72011-05-09 17:00:02 +0000608 GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000609 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000610 } else {
611 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
612 record->fDownsample);
613 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000614 }
615
616 // setup for draw back to main RT
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000617 int stageMask = paint.getActiveStageMask();
618
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000619 target->restoreDrawState(record->fSavedState);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000620
621 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000622 GrMatrix invVM;
623 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000624 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000625 }
626 }
627 target->setViewMatrix(GrMatrix::I());
628
629 target->setTexture(kOffscreenStage, src);
630 sampleM.setScale(scale * GR_Scalar1 / src->width(),
631 scale * GR_Scalar1 / src->height());
632 sampler.setMatrix(sampleM);
633 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
634 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000635 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000636
reed@google.com20efde72011-05-09 17:00:02 +0000637 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000638 int stages = (1 << kOffscreenStage) | stageMask;
reed@google.com20efde72011-05-09 17:00:02 +0000639 dstRect.set(boundRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000640 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000641
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000642 this->unlockTexture(record->fEntry0);
643 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000644 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000645 this->unlockTexture(record->fEntry1);
646 record->fEntry1 = NULL;
647 }
648 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000649}
650
651////////////////////////////////////////////////////////////////////////////////
652
bsalomon@google.com27847de2011-02-22 20:59:41 +0000653/* create a triangle strip that strokes the specified triangle. There are 8
654 unique vertices, but we repreat the last 2 to close up. Alternatively we
655 could use an indices array, and then only send 8 verts, but not sure that
656 would be faster.
657 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000658static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000659 GrScalar width) {
660 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000661 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000662
663 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
664 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
665 verts[2].set(rect.fRight - rad, rect.fTop + rad);
666 verts[3].set(rect.fRight + rad, rect.fTop - rad);
667 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
668 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
669 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
670 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
671 verts[8] = verts[0];
672 verts[9] = verts[1];
673}
674
bsalomon@google.com205d4602011-04-25 12:43:45 +0000675static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000676 // FIXME: This was copied from SkGpuDevice, seems like
677 // we should have already smeared a in caller if that
678 // is what is desired.
679 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000680 unsigned a = GrColorUnpackA(paint.fColor);
681 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000682 } else {
683 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000684 }
685}
686
687static void setInsetFan(GrPoint* pts, size_t stride,
688 const GrRect& r, GrScalar dx, GrScalar dy) {
689 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
690}
691
692static const uint16_t gFillAARectIdx[] = {
693 0, 1, 5, 5, 4, 0,
694 1, 2, 6, 6, 5, 1,
695 2, 3, 7, 7, 6, 2,
696 3, 0, 4, 4, 7, 3,
697 4, 5, 6, 6, 7, 4,
698};
699
700int GrContext::aaFillRectIndexCount() const {
701 return GR_ARRAY_COUNT(gFillAARectIdx);
702}
703
704GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
705 if (NULL == fAAFillRectIndexBuffer) {
706 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
707 false);
708 GrAssert(NULL != fAAFillRectIndexBuffer);
709#if GR_DEBUG
710 bool updated =
711#endif
712 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
713 sizeof(gFillAARectIdx));
714 GR_DEBUGASSERT(updated);
715 }
716 return fAAFillRectIndexBuffer;
717}
718
719static const uint16_t gStrokeAARectIdx[] = {
720 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
721 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
722 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
723 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
724
725 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
726 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
727 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
728 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
729
730 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
731 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
732 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
733 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
734};
735
736int GrContext::aaStrokeRectIndexCount() const {
737 return GR_ARRAY_COUNT(gStrokeAARectIdx);
738}
739
740GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
741 if (NULL == fAAStrokeRectIndexBuffer) {
742 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
743 false);
744 GrAssert(NULL != fAAStrokeRectIndexBuffer);
745#if GR_DEBUG
746 bool updated =
747#endif
748 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
749 sizeof(gStrokeAARectIdx));
750 GR_DEBUGASSERT(updated);
751 }
752 return fAAStrokeRectIndexBuffer;
753}
754
755void GrContext::fillAARect(GrDrawTarget* target,
756 const GrPaint& paint,
757 const GrRect& devRect) {
758
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000759 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
760 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000761
762 size_t vsize = GrDrawTarget::VertexSize(layout);
763
764 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
765
766 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
767
768 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
769 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
770
771 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
772 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
773
774 verts += sizeof(GrPoint);
775 for (int i = 0; i < 4; ++i) {
776 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
777 }
778
779 GrColor innerColor = getColorForMesh(paint);
780 verts += 4 * vsize;
781 for (int i = 0; i < 4; ++i) {
782 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
783 }
784
785 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
786
787 target->drawIndexed(kTriangles_PrimitiveType, 0,
788 0, 8, this->aaFillRectIndexCount());
789}
790
791void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
792 const GrRect& devRect, const GrVec& devStrokeSize) {
793 const GrScalar& dx = devStrokeSize.fX;
794 const GrScalar& dy = devStrokeSize.fY;
795 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
796 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
797
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000798 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
799 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000800
801 GrScalar spare;
802 {
803 GrScalar w = devRect.width() - dx;
804 GrScalar h = devRect.height() - dy;
805 spare = GrMin(w, h);
806 }
807
808 if (spare <= 0) {
809 GrRect r(devRect);
810 r.inset(-rx, -ry);
811 fillAARect(target, paint, r);
812 return;
813 }
814
815 size_t vsize = GrDrawTarget::VertexSize(layout);
816
817 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
818
819 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
820
821 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
822 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
823 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
824 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
825
826 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
827 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
828 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
829 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
830
831 verts += sizeof(GrPoint);
832 for (int i = 0; i < 4; ++i) {
833 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
834 }
835
836 GrColor innerColor = getColorForMesh(paint);
837 verts += 4 * vsize;
838 for (int i = 0; i < 8; ++i) {
839 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
840 }
841
842 verts += 8 * vsize;
843 for (int i = 0; i < 8; ++i) {
844 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
845 }
846
847 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
848 target->drawIndexed(kTriangles_PrimitiveType,
849 0, 0, 16, aaStrokeRectIndexCount());
850}
851
reed@google.com20efde72011-05-09 17:00:02 +0000852/**
853 * Returns true if the rects edges are integer-aligned.
854 */
855static bool isIRect(const GrRect& r) {
856 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
857 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
858}
859
bsalomon@google.com205d4602011-04-25 12:43:45 +0000860static bool apply_aa_to_rect(GrDrawTarget* target,
861 GrGpu* gpu,
862 const GrPaint& paint,
863 const GrRect& rect,
864 GrScalar width,
865 const GrMatrix* matrix,
866 GrMatrix* combinedMatrix,
867 GrRect* devRect) {
868 // we use a simple alpha ramp to do aa on axis-aligned rects
869 // do AA with alpha ramp if the caller requested AA, the rect
870 // will be axis-aligned,the render target is not
871 // multisampled, and the rect won't land on integer coords.
872
873 if (!paint.fAntiAlias) {
874 return false;
875 }
876
877 if (target->getRenderTarget()->isMultisampled()) {
878 return false;
879 }
880
881 if (0 == width && gpu->supportsAALines()) {
882 return false;
883 }
884
885 if (!target->getViewMatrix().preservesAxisAlignment()) {
886 return false;
887 }
888
889 if (NULL != matrix &&
890 !matrix->preservesAxisAlignment()) {
891 return false;
892 }
893
894 *combinedMatrix = target->getViewMatrix();
895 if (NULL != matrix) {
896 combinedMatrix->preConcat(*matrix);
897 GrAssert(combinedMatrix->preservesAxisAlignment());
898 }
899
900 combinedMatrix->mapRect(devRect, rect);
901 devRect->sort();
902
903 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000904 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000905 } else {
906 return true;
907 }
908}
909
bsalomon@google.com27847de2011-02-22 20:59:41 +0000910void GrContext::drawRect(const GrPaint& paint,
911 const GrRect& rect,
912 GrScalar width,
913 const GrMatrix* matrix) {
914
bsalomon@google.com27847de2011-02-22 20:59:41 +0000915
916 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000917 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000918
bsalomon@google.com205d4602011-04-25 12:43:45 +0000919 GrRect devRect = rect;
920 GrMatrix combinedMatrix;
921 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
922 &combinedMatrix, &devRect);
923
924 if (doAA) {
925 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000926 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000927 GrMatrix inv;
928 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000929 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000930 }
931 }
932 target->setViewMatrix(GrMatrix::I());
933 if (width >= 0) {
934 GrVec strokeSize;;
935 if (width > 0) {
936 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000937 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000938 strokeSize.setAbs(strokeSize);
939 } else {
940 strokeSize.set(GR_Scalar1, GR_Scalar1);
941 }
942 strokeAARect(target, paint, devRect, strokeSize);
943 } else {
944 fillAARect(target, paint, devRect);
945 }
946 return;
947 }
948
bsalomon@google.com27847de2011-02-22 20:59:41 +0000949 if (width >= 0) {
950 // TODO: consider making static vertex buffers for these cases.
951 // Hairline could be done by just adding closing vertex to
952 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000953 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
954
bsalomon@google.com27847de2011-02-22 20:59:41 +0000955 static const int worstCaseVertCount = 10;
956 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
957
958 if (!geo.succeeded()) {
959 return;
960 }
961
962 GrPrimitiveType primType;
963 int vertCount;
964 GrPoint* vertex = geo.positions();
965
966 if (width > 0) {
967 vertCount = 10;
968 primType = kTriangleStrip_PrimitiveType;
969 setStrokeRectStrip(vertex, rect, width);
970 } else {
971 // hairline
972 vertCount = 5;
973 primType = kLineStrip_PrimitiveType;
974 vertex[0].set(rect.fLeft, rect.fTop);
975 vertex[1].set(rect.fRight, rect.fTop);
976 vertex[2].set(rect.fRight, rect.fBottom);
977 vertex[3].set(rect.fLeft, rect.fBottom);
978 vertex[4].set(rect.fLeft, rect.fTop);
979 }
980
981 GrDrawTarget::AutoViewMatrixRestore avmr;
982 if (NULL != matrix) {
983 avmr.set(target);
984 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000985 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000986 }
987
988 target->drawNonIndexed(primType, 0, vertCount);
989 } else {
990 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000991 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
992
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000993 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000994 fGpu->getUnitSquareVertexBuffer());
995 GrDrawTarget::AutoViewMatrixRestore avmr(target);
996 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000997 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000998 0, rect.height(), rect.fTop,
999 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001000
1001 if (NULL != matrix) {
1002 m.postConcat(*matrix);
1003 }
1004
1005 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001006 target->preConcatSamplerMatrices(stageMask, m);
1007
bsalomon@google.com27847de2011-02-22 20:59:41 +00001008 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1009 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001010 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001011 #endif
1012 }
1013}
1014
1015void GrContext::drawRectToRect(const GrPaint& paint,
1016 const GrRect& dstRect,
1017 const GrRect& srcRect,
1018 const GrMatrix* dstMatrix,
1019 const GrMatrix* srcMatrix) {
1020
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001021 // srcRect refers to paint's first texture
1022 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001023 drawRect(paint, dstRect, -1, dstMatrix);
1024 return;
1025 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001026
bsalomon@google.com27847de2011-02-22 20:59:41 +00001027 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1028
1029#if GR_STATIC_RECT_VB
1030 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001031
1032 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001033 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1034
1035 GrMatrix m;
1036
1037 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1038 0, dstRect.height(), dstRect.fTop,
1039 0, 0, GrMatrix::I()[8]);
1040 if (NULL != dstMatrix) {
1041 m.postConcat(*dstMatrix);
1042 }
1043 target->preConcatViewMatrix(m);
1044
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001045 // srcRect refers to first stage
1046 int otherStageMask = paint.getActiveStageMask() &
1047 (~(1 << GrPaint::kFirstTextureStage));
1048 if (otherStageMask) {
1049 target->preConcatSamplerMatrices(otherStageMask, m);
1050 }
1051
bsalomon@google.com27847de2011-02-22 20:59:41 +00001052 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1053 0, srcRect.height(), srcRect.fTop,
1054 0, 0, GrMatrix::I()[8]);
1055 if (NULL != srcMatrix) {
1056 m.postConcat(*srcMatrix);
1057 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001058 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001059
1060 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1061 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1062#else
1063
1064 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001065#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001066 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001067#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001068 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1069#endif
1070
1071 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1072 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1073 srcRects[0] = &srcRect;
1074 srcMatrices[0] = srcMatrix;
1075
1076 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1077#endif
1078}
1079
1080void GrContext::drawVertices(const GrPaint& paint,
1081 GrPrimitiveType primitiveType,
1082 int vertexCount,
1083 const GrPoint positions[],
1084 const GrPoint texCoords[],
1085 const GrColor colors[],
1086 const uint16_t indices[],
1087 int indexCount) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001088
1089 GrDrawTarget::AutoReleaseGeometry geo;
1090
1091 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1092
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001093 bool hasTexCoords[GrPaint::kTotalStages] = {
1094 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1095 0 // remaining stages use positions
1096 };
1097
1098 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001099
1100 if (NULL != colors) {
1101 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001102 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001103 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001104
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001105 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001106 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001107 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001108
bsalomon@google.com27847de2011-02-22 20:59:41 +00001109 if (sizeof(GrPoint) != vertexSize) {
1110 if (!geo.set(target, layout, vertexCount, 0)) {
1111 GrPrintf("Failed to get space for vertices!");
1112 return;
1113 }
1114 int texOffsets[GrDrawTarget::kMaxTexCoords];
1115 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001116 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1117 texOffsets,
1118 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119 void* curVertex = geo.vertices();
1120
1121 for (int i = 0; i < vertexCount; ++i) {
1122 *((GrPoint*)curVertex) = positions[i];
1123
1124 if (texOffsets[0] > 0) {
1125 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1126 }
1127 if (colorOffset > 0) {
1128 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1129 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001130 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001131 }
1132 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001133 // we don't do offscreen AA when we have per-vertex tex coords or colors
1134 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1135 GrRect b;
1136 b.setBounds(positions, vertexCount);
1137 target->getViewMatrix().mapRect(&b);
1138 b.roundOut(&bounds);
1139
1140 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1141 doAA = true;
1142 }
1143 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001144 target->setVertexSourceToArray(layout, positions, vertexCount);
1145 }
1146
1147 if (NULL != indices) {
1148 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001149 }
1150
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001151 if (NULL != indices) {
1152 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001153 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001154 target->drawNonIndexed(primitiveType, 0, vertexCount);
1155 }
1156
1157 if (doAA) {
1158 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159 }
1160}
1161
1162
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001163///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001164
reed@google.com07f3ee12011-05-16 17:21:57 +00001165void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1166 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167
bsalomon@google.com27847de2011-02-22 20:59:41 +00001168 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001169 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001170
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001171 if (!IsFillInverted(fill) && // will be relaxed soon
1172 !pr->supportsAA(target, path, fill) &&
1173 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001174
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001175 OffscreenRecord record;
1176 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001177
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001178 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001179 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1180 target->getRenderTarget()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001181 if (target->getClip().hasConservativeBounds()) {
1182 GrIRect clipIBounds;
1183 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001184 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001185 return;
1186 }
1187 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001188 GrRect pathBounds = path.getBounds();
1189 if (!pathBounds.isEmpty()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001190 GrIRect pathIBounds;
1191 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1192 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001193 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001194 return;
1195 }
1196 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001197
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001198 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1199 pr->drawPath(target, 0, path, fill, translate);
1200 this->offscreenAAPass2(target, paint, bound, &record);
1201 return;
1202 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001203 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001204 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001205
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001206 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001207}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001208
bsalomon@google.com27847de2011-02-22 20:59:41 +00001209////////////////////////////////////////////////////////////////////////////////
1210
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001211void GrContext::flush(int flagsBitfield) {
1212 if (kDiscard_FlushBit & flagsBitfield) {
1213 fDrawBuffer->reset();
1214 } else {
1215 flushDrawBuffer();
1216 }
1217
1218 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001219 fGpu->forceRenderTargetFlush();
1220 }
1221}
1222
1223void GrContext::flushText() {
1224 if (kText_DrawCategory == fLastDrawCategory) {
1225 flushDrawBuffer();
1226 }
1227}
1228
1229void GrContext::flushDrawBuffer() {
1230#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1231 fDrawBuffer->playback(fGpu);
1232 fDrawBuffer->reset();
1233#endif
1234}
1235
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001236bool GrContext::readTexturePixels(GrTexture* texture,
1237 int left, int top, int width, int height,
1238 GrPixelConfig config, void* buffer) {
1239
1240 // TODO: code read pixels for textures that aren't rendertargets
1241
1242 this->flush();
1243 GrRenderTarget* target = texture->asRenderTarget();
1244 if (NULL != target) {
1245 return fGpu->readPixels(target,
1246 left, top, width, height,
1247 config, buffer);
1248 } else {
1249 return false;
1250 }
1251}
1252
1253bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1254 int left, int top, int width, int height,
1255 GrPixelConfig config, void* buffer) {
1256 uint32_t flushFlags = 0;
1257 if (NULL == target) {
1258 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1259 }
1260
1261 this->flush(flushFlags);
1262 return fGpu->readPixels(target,
1263 left, top, width, height,
1264 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265}
1266
1267void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001268 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269 size_t stride) {
1270
1271 // TODO: when underlying api has a direct way to do this we should use it
1272 // (e.g. glDrawPixels on desktop GL).
1273
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001274 const GrTextureDesc desc = {
1275 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276 };
1277 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1278 if (NULL == texture) {
1279 return;
1280 }
1281
1282 this->flush(true);
1283
1284 GrAutoUnref aur(texture);
1285 GrDrawTarget::AutoStateRestore asr(fGpu);
1286
1287 GrMatrix matrix;
1288 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1289 fGpu->setViewMatrix(matrix);
1290
1291 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1292 fGpu->setAlpha(0xFF);
1293 fGpu->setBlendFunc(kOne_BlendCoeff,
1294 kZero_BlendCoeff);
1295 fGpu->setTexture(0, texture);
1296
1297 GrSamplerState sampler;
1298 sampler.setClampNoFilter();
1299 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1300 sampler.setMatrix(matrix);
1301 fGpu->setSamplerState(0, sampler);
1302
1303 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1304 static const int VCOUNT = 4;
1305
1306 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1307 if (!geo.succeeded()) {
1308 return;
1309 }
1310 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1311 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1312}
1313////////////////////////////////////////////////////////////////////////////////
1314
1315void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001316
1317 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1318 int s = i + GrPaint::kFirstTextureStage;
1319 target->setTexture(s, paint.getTexture(i));
1320 target->setSamplerState(s, *paint.getTextureSampler(i));
1321 }
1322
1323 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1324
1325 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1326 int s = i + GrPaint::kFirstMaskStage;
1327 target->setTexture(s, paint.getMask(i));
1328 target->setSamplerState(s, *paint.getMaskSampler(i));
1329 }
1330
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 target->setColor(paint.fColor);
1332
1333 if (paint.fDither) {
1334 target->enableState(GrDrawTarget::kDither_StateBit);
1335 } else {
1336 target->disableState(GrDrawTarget::kDither_StateBit);
1337 }
1338 if (paint.fAntiAlias) {
1339 target->enableState(GrDrawTarget::kAntialias_StateBit);
1340 } else {
1341 target->disableState(GrDrawTarget::kAntialias_StateBit);
1342 }
1343 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001344 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001345}
1346
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001347GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001348 DrawCategory category) {
1349 if (category != fLastDrawCategory) {
1350 flushDrawBuffer();
1351 fLastDrawCategory = category;
1352 }
1353 SetPaint(paint, fGpu);
1354 GrDrawTarget* target = fGpu;
1355 switch (category) {
1356 case kText_DrawCategory:
1357#if DEFER_TEXT_RENDERING
1358 target = fDrawBuffer;
1359 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1360#else
1361 target = fGpu;
1362#endif
1363 break;
1364 case kUnbuffered_DrawCategory:
1365 target = fGpu;
1366 break;
1367 case kBuffered_DrawCategory:
1368 target = fDrawBuffer;
1369 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1370 break;
1371 }
1372 return target;
1373}
1374
1375////////////////////////////////////////////////////////////////////////////////
1376
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001378 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379 fGpu->setRenderTarget(target);
1380}
1381
1382GrRenderTarget* GrContext::getRenderTarget() {
1383 return fGpu->getRenderTarget();
1384}
1385
1386const GrRenderTarget* GrContext::getRenderTarget() const {
1387 return fGpu->getRenderTarget();
1388}
1389
1390const GrMatrix& GrContext::getMatrix() const {
1391 return fGpu->getViewMatrix();
1392}
1393
1394void GrContext::setMatrix(const GrMatrix& m) {
1395 fGpu->setViewMatrix(m);
1396}
1397
1398void GrContext::concatMatrix(const GrMatrix& m) const {
1399 fGpu->preConcatViewMatrix(m);
1400}
1401
1402static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1403 intptr_t mask = 1 << shift;
1404 if (pred) {
1405 bits |= mask;
1406 } else {
1407 bits &= ~mask;
1408 }
1409 return bits;
1410}
1411
1412void GrContext::resetStats() {
1413 fGpu->resetStats();
1414}
1415
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001416const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417 return fGpu->getStats();
1418}
1419
1420void GrContext::printStats() const {
1421 fGpu->printStats();
1422}
1423
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001424GrContext::GrContext(GrGpu* gpu) :
1425 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1426 gpu->supportsStencilWrapOps()) {
1427
bsalomon@google.com27847de2011-02-22 20:59:41 +00001428 fGpu = gpu;
1429 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001430 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001431
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001432 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1433 fGpu->setClipPathRenderer(fCustomPathRenderer);
1434
bsalomon@google.com27847de2011-02-22 20:59:41 +00001435 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1436 MAX_TEXTURE_CACHE_BYTES);
1437 fFontCache = new GrFontCache(fGpu);
1438
1439 fLastDrawCategory = kUnbuffered_DrawCategory;
1440
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001441 fDrawBuffer = NULL;
1442 fDrawBufferVBAllocPool = NULL;
1443 fDrawBufferIBAllocPool = NULL;
1444
bsalomon@google.com205d4602011-04-25 12:43:45 +00001445 fAAFillRectIndexBuffer = NULL;
1446 fAAStrokeRectIndexBuffer = NULL;
1447
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001448 this->setupDrawBuffer();
1449}
1450
1451void GrContext::setupDrawBuffer() {
1452
1453 GrAssert(NULL == fDrawBuffer);
1454 GrAssert(NULL == fDrawBufferVBAllocPool);
1455 GrAssert(NULL == fDrawBufferIBAllocPool);
1456
bsalomon@google.com27847de2011-02-22 20:59:41 +00001457#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001458 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001459 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1461 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001462 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001463 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001464 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1466
1467 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1468 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469#endif
1470
1471#if BATCH_RECT_TO_RECT
1472 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1473#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001474}
1475
bsalomon@google.com27847de2011-02-22 20:59:41 +00001476GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1477 GrDrawTarget* target;
1478#if DEFER_TEXT_RENDERING
1479 target = prepareToDraw(paint, kText_DrawCategory);
1480#else
1481 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1482#endif
1483 SetPaint(paint, target);
1484 return target;
1485}
1486
1487const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1488 return fGpu->getQuadIndexBuffer();
1489}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001490
1491GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001492 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001493 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001494 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001495 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1496 return fCustomPathRenderer;
1497 } else {
1498 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1499 return &fDefaultPathRenderer;
1500 }
1501}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001502