blob: 4ebf225a3c5a60cbcc5bc9719de72cc86fdf5625 [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
reed@google.com70c136e2011-06-03 19:51:26 +000028// larger than this, and we don't AA. set to 0 for no AA
29#ifndef GR_MAX_OFFSCREEN_AA_DIM
30 #define GR_MAX_OFFSCREEN_AA_DIM 0
31#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000032
bsalomon@google.com27847de2011-02-22 20:59:41 +000033#define DEFER_TEXT_RENDERING 1
34
35#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
36
37static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
39
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.com05ef5102011-05-02 21:14:59 +000048GrContext* GrContext::Create(GrEngine engine,
49 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000050 GrContext* ctx = NULL;
51 GrGpu* fGpu = GrGpu::Create(engine, context3D);
52 if (NULL != fGpu) {
53 ctx = new GrContext(fGpu);
54 fGpu->unref();
55 }
56 return ctx;
57}
58
59GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000060 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000061}
62
63GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000064 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000065 delete fTextureCache;
66 delete fFontCache;
67 delete fDrawBuffer;
68 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000069 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000070 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000071 GrSafeUnref(fAAFillRectIndexBuffer);
72 GrSafeUnref(fAAStrokeRectIndexBuffer);
73 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com8fe72472011-03-30 21:26:44 +000086 delete fDrawBuffer;
87 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000088
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBufferVBAllocPool;
90 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferIBAllocPool;
93 fDrawBufferIBAllocPool = NULL;
94
bsalomon@google.com205d4602011-04-25 12:43:45 +000095 GrSafeSetNull(fAAFillRectIndexBuffer);
96 GrSafeSetNull(fAAStrokeRectIndexBuffer);
97
bsalomon@google.com8fe72472011-03-30 21:26:44 +000098 fTextureCache->removeAll();
99 fFontCache->freeAll();
100 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101}
102
103void GrContext::resetContext() {
104 fGpu->markContextDirty();
105}
106
107void GrContext::freeGpuResources() {
108 this->flush();
109 fTextureCache->removeAll();
110 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000111}
112
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000113////////////////////////////////////////////////////////////////////////////////
114
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000115int GrContext::PaintStageVertexLayoutBits(
116 const GrPaint& paint,
117 const bool hasTexCoords[GrPaint::kTotalStages]) {
118 int stageMask = paint.getActiveStageMask();
119 int layout = 0;
120 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
121 if ((1 << i) & stageMask) {
122 if (NULL != hasTexCoords && hasTexCoords[i]) {
123 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
124 } else {
125 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
126 }
127 }
128 }
129 return layout;
130}
131
132
133////////////////////////////////////////////////////////////////////////////////
134
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000135enum {
136 kNPOTBit = 0x1,
137 kFilterBit = 0x2,
138 kKeylessBit = 0x4,
139};
140
141bool GrContext::finalizeTextureKey(GrTextureKey* key,
142 const GrSamplerState& sampler,
143 bool keyless) const {
144 uint32_t bits = 0;
145 uint16_t width = key->width();
146 uint16_t height = key->height();
147
148 if (!fGpu->npotTextureTileSupport()) {
149 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
150
151 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
152 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
153
154 if (tiled && !isPow2) {
155 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000156 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000157 bits |= kFilterBit;
158 }
159 }
160 }
161
162 if (keyless) {
163 bits |= kKeylessBit;
164 }
165 key->finalize(bits);
166 return 0 != bits;
167}
168
bsalomon@google.com27847de2011-02-22 20:59:41 +0000169GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
170 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000171 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000172 return fTextureCache->findAndLock(*key);
173}
174
175static void stretchImage(void* dst,
176 int dstW,
177 int dstH,
178 void* src,
179 int srcW,
180 int srcH,
181 int bpp) {
182 GrFixed dx = (srcW << 16) / dstW;
183 GrFixed dy = (srcH << 16) / dstH;
184
185 GrFixed y = dy >> 1;
186
187 int dstXLimit = dstW*bpp;
188 for (int j = 0; j < dstH; ++j) {
189 GrFixed x = dx >> 1;
190 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
191 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
192 for (int i = 0; i < dstXLimit; i += bpp) {
193 memcpy((uint8_t*) dstRow + i,
194 (uint8_t*) srcRow + (x>>16)*bpp,
195 bpp);
196 x += dx;
197 }
198 y += dy;
199 }
200}
201
202GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
203 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000204 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000205 void* srcData, size_t rowBytes) {
206 GrAssert(key->width() == desc.fWidth);
207 GrAssert(key->height() == desc.fHeight);
208
209#if GR_DUMP_TEXTURE_UPLOAD
210 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
211#endif
212
213 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000214 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000215 if (special) {
216 GrTextureEntry* clampEntry;
217 GrTextureKey clampKey(*key);
218 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
219
220 if (NULL == clampEntry) {
221 clampEntry = createAndLockTexture(&clampKey,
222 GrSamplerState::ClampNoFilter(),
223 desc, srcData, rowBytes);
224 GrAssert(NULL != clampEntry);
225 if (NULL == clampEntry) {
226 return NULL;
227 }
228 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000229 GrTextureDesc rtDesc = desc;
230 rtDesc.fFlags = rtDesc.fFlags |
231 kRenderTarget_GrTextureFlagBit |
232 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000233 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
234 fGpu->minRenderTargetWidth()));
235 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
236 fGpu->minRenderTargetHeight()));
237
238 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
239
240 if (NULL != texture) {
241 GrDrawTarget::AutoStateRestore asr(fGpu);
242 fGpu->setRenderTarget(texture->asRenderTarget());
243 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000244 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000245 fGpu->setViewMatrix(GrMatrix::I());
246 fGpu->setAlpha(0xff);
247 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
248 fGpu->disableState(GrDrawTarget::kDither_StateBit |
249 GrDrawTarget::kClip_StateBit |
250 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000251 GrSamplerState::Filter filter;
252 // if filtering is not desired then we want to ensure all
253 // texels in the resampled image are copies of texels from
254 // the original.
255 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
256 filter = GrSamplerState::kNearest_Filter;
257 } else {
258 filter = GrSamplerState::kBilinear_Filter;
259 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000260 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
261 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000262 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000263 fGpu->setSamplerState(0, stretchSampler);
264
265 static const GrVertexLayout layout =
266 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
267 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
268
269 if (arg.succeeded()) {
270 GrPoint* verts = (GrPoint*) arg.vertices();
271 verts[0].setIRectFan(0, 0,
272 texture->width(),
273 texture->height(),
274 2*sizeof(GrPoint));
275 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
276 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
277 0, 4);
278 entry = fTextureCache->createAndLock(*key, texture);
279 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000280 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000281 } else {
282 // TODO: Our CPU stretch doesn't filter. But we create separate
283 // stretched textures when the sampler state is either filtered or
284 // not. Either implement filtered stretch blit on CPU or just create
285 // one when FBO case fails.
286
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000287 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000288 // no longer need to clamp at min RT size.
289 rtDesc.fWidth = GrNextPow2(desc.fWidth);
290 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000291 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000292 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
293 rtDesc.fWidth *
294 rtDesc.fHeight);
295 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
296 srcData, desc.fWidth, desc.fHeight, bpp);
297
298 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
299
300 GrTexture* texture = fGpu->createTexture(rtDesc,
301 stretchedPixels.get(),
302 stretchedRowBytes);
303 GrAssert(NULL != texture);
304 entry = fTextureCache->createAndLock(*key, texture);
305 }
306 fTextureCache->unlock(clampEntry);
307
308 } else {
309 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
310 if (NULL != texture) {
311 entry = fTextureCache->createAndLock(*key, texture);
312 } else {
313 entry = NULL;
314 }
315 }
316 return entry;
317}
318
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000319GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000320 uint32_t p0 = desc.fFormat;
321 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
322 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000323 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
324
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000325 GrTextureEntry* entry = fTextureCache->findAndLock(key);
326 if (NULL == entry) {
327 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
328 if (NULL != texture) {
329 entry = fTextureCache->createAndLock(key, texture);
330 }
331 }
332 // If the caller gives us the same desc/sampler twice we don't want
333 // to return the same texture the second time (unless it was previously
334 // released). So we detach the entry from the cache and reattach at release.
335 if (NULL != entry) {
336 fTextureCache->detach(entry);
337 }
338 return entry;
339}
340
bsalomon@google.com27847de2011-02-22 20:59:41 +0000341void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000342 if (kKeylessBit & entry->key().getPrivateBits()) {
343 fTextureCache->reattachAndUnlock(entry);
344 } else {
345 fTextureCache->unlock(entry);
346 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000347}
348
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000349GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000350 void* srcData,
351 size_t rowBytes) {
352 return fGpu->createTexture(desc, srcData, rowBytes);
353}
354
355void GrContext::getTextureCacheLimits(int* maxTextures,
356 size_t* maxTextureBytes) const {
357 fTextureCache->getLimits(maxTextures, maxTextureBytes);
358}
359
360void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
361 fTextureCache->setLimits(maxTextures, maxTextureBytes);
362}
363
364int GrContext::getMaxTextureDimension() {
365 return fGpu->maxTextureDimension();
366}
367
368///////////////////////////////////////////////////////////////////////////////
369
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000370GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
371 // validate flags here so that GrGpu subclasses don't have to check
372 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
373 0 != desc.fRenderTargetFlags) {
374 return NULL;
375 }
376 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
377 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
378 return NULL;
379 }
380 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
381 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
382 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
383 return NULL;
384 }
385 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000386}
387
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000388GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000389 return fGpu->createRenderTargetFrom3DApiState();
390}
391
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000392///////////////////////////////////////////////////////////////////////////////
393
bsalomon@google.com27847de2011-02-22 20:59:41 +0000394bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
395 int width, int height) {
396 if (!fGpu->supports8BitPalette()) {
397 return false;
398 }
399
400
401 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
402
403 if (!isPow2) {
404 if (!fGpu->npotTextureSupport()) {
405 return false;
406 }
407
408 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
409 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
410 if (tiled && !fGpu->npotTextureTileSupport()) {
411 return false;
412 }
413 }
414 return true;
415}
416
417////////////////////////////////////////////////////////////////////////////////
418
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000419const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
420
bsalomon@google.com27847de2011-02-22 20:59:41 +0000421void GrContext::setClip(const GrClip& clip) {
422 fGpu->setClip(clip);
423 fGpu->enableState(GrDrawTarget::kClip_StateBit);
424}
425
426void GrContext::setClip(const GrIRect& rect) {
427 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000428 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000429 fGpu->setClip(clip);
430}
431
432////////////////////////////////////////////////////////////////////////////////
433
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000434void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000435 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000436 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000437}
438
439void GrContext::drawPaint(const GrPaint& paint) {
440 // set rect to be big enough to fill the space, but not super-huge, so we
441 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000442 GrRect r;
443 r.setLTRB(0, 0,
444 GrIntToScalar(getRenderTarget()->width()),
445 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000446 GrMatrix inverse;
447 if (fGpu->getViewInverse(&inverse)) {
448 inverse.mapRect(&r);
449 } else {
450 GrPrintf("---- fGpu->getViewInverse failed\n");
451 }
452 this->drawRect(paint, r);
453}
454
bsalomon@google.com205d4602011-04-25 12:43:45 +0000455////////////////////////////////////////////////////////////////////////////////
456
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000457bool GrContext::doOffscreenAA(GrDrawTarget* target,
458 const GrPaint& paint,
459 bool isLines) const {
reed@google.com70c136e2011-06-03 19:51:26 +0000460#if GR_MAX_OFFSCREEN_AA_DIM==0
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000461 return false;
462#else
463 if (!paint.fAntiAlias) {
464 return false;
465 }
466 if (isLines && fGpu->supportsAALines()) {
467 return false;
468 }
469 if (target->getRenderTarget()->isMultisampled()) {
470 return false;
471 }
472 // we have to be sure that the blend equation is expressible
473 // as simple src / dst coeffecients when the source
474 // is already modulated by the coverage fraction.
475 // We could use dual-source blending to get the correct per-pixel
476 // dst coeffecient for the remaining cases.
477 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
478 kOne_BlendCoeff != paint.fDstBlendCoeff &&
479 kISA_BlendCoeff != paint.fDstBlendCoeff) {
480 return false;
481 }
482 return true;
483#endif
484}
485
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000486bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
487 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000488 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000489 OffscreenRecord* record) {
reed@google.com70c136e2011-06-03 19:51:26 +0000490 GrAssert(GR_MAX_OFFSCREEN_AA_DIM > 0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000491
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000492 GrAssert(NULL == record->fEntry0);
493 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000494
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000495 int boundW = boundRect.width();
496 int boundH = boundRect.height();
497 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000498
499 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000500 if (requireStencil) {
501 desc.fFlags = kRenderTarget_GrTextureFlagBit;
502 } else {
503 desc.fFlags = kRenderTarget_GrTextureFlagBit |
504 kNoStencil_GrTextureFlagBit;
505 }
506
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000507 desc.fFormat = kRGBA_8888_GrPixelConfig;
508
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000509 int scale;
510 // Using MSAA seems to be slower for some yet unknown reason.
511 if (false && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000512 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000513 scale = GR_Scalar1;
514 desc.fAALevel = kMed_GrAALevel;
515 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000516 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
517 OffscreenRecord::k4x4SinglePass_Downsample :
518 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000519 scale = 4;
520 desc.fAALevel = kNone_GrAALevel;
521 }
522
523 desc.fWidth = scale * size;
524 desc.fHeight = scale * size;
525
526 record->fEntry0 = this->lockKeylessTexture(desc);
527
528 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000529 return false;
530 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000531
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000532 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000533 desc.fWidth /= 2;
534 desc.fHeight /= 2;
535 record->fEntry1 = this->lockKeylessTexture(desc);
536 if (NULL == record->fEntry1) {
537 this->unlockTexture(record->fEntry0);
538 record->fEntry0 = NULL;
539 return false;
540 }
541 }
542
543 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
544 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000545
546 target->saveCurrentDrawState(&record->fSavedState);
547
548 GrPaint tempPaint;
549 tempPaint.reset();
550 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000551 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000552
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000553 GrMatrix transM;
554 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
555 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000556 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000557 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000558 target->postConcatViewMatrix(scaleM);
559
560 // clip gets applied in second pass
561 target->disableState(GrDrawTarget::kClip_StateBit);
562
reed@google.com20efde72011-05-09 17:00:02 +0000563 GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000564 target->clear(&clear, 0x0);
565
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000566 return true;
567}
568
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000569void GrContext::offscreenAAPass2(GrDrawTarget* target,
570 const GrPaint& paint,
571 const GrIRect& boundRect,
572 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000573
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000574 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000575
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000576 GrSamplerState::Filter filter;
577 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
578 filter = GrSamplerState::k4x4Downsample_Filter;
579 } else {
580 filter = GrSamplerState::kBilinear_Filter;
581 }
582
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000583 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000584 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000585 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000586
587 GrTexture* src = record->fEntry0->texture();
588 int scale;
589
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000590 enum {
591 kOffscreenStage = GrPaint::kTotalStages,
592 };
593
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000594 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
595 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000596 scale = 2;
597 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
598
599 // Do 2x2 downsample from first to second
600 target->setTexture(kOffscreenStage, src);
601 target->setRenderTarget(dst);
602 target->setViewMatrix(GrMatrix::I());
603 sampleM.setScale(scale * GR_Scalar1 / src->width(),
604 scale * GR_Scalar1 / src->height());
605 sampler.setMatrix(sampleM);
606 target->setSamplerState(kOffscreenStage, sampler);
reed@google.com20efde72011-05-09 17:00:02 +0000607 GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
608 scale * boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000609 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
610
611 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000612 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000613 scale = 1;
reed@google.com20efde72011-05-09 17:00:02 +0000614 GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000615 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000616 } else {
617 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
618 record->fDownsample);
619 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000620 }
621
622 // setup for draw back to main RT
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000623 int stageMask = paint.getActiveStageMask();
624
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000625 target->restoreDrawState(record->fSavedState);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000626
627 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000628 GrMatrix invVM;
629 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000630 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000631 }
632 }
633 target->setViewMatrix(GrMatrix::I());
634
635 target->setTexture(kOffscreenStage, src);
636 sampleM.setScale(scale * GR_Scalar1 / src->width(),
637 scale * GR_Scalar1 / src->height());
638 sampler.setMatrix(sampleM);
639 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
640 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000641 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000642
reed@google.com20efde72011-05-09 17:00:02 +0000643 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000644 int stages = (1 << kOffscreenStage) | stageMask;
reed@google.com20efde72011-05-09 17:00:02 +0000645 dstRect.set(boundRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000646 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000647
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000648 this->unlockTexture(record->fEntry0);
649 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000650 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000651 this->unlockTexture(record->fEntry1);
652 record->fEntry1 = NULL;
653 }
654 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000655}
656
657////////////////////////////////////////////////////////////////////////////////
658
bsalomon@google.com27847de2011-02-22 20:59:41 +0000659/* create a triangle strip that strokes the specified triangle. There are 8
660 unique vertices, but we repreat the last 2 to close up. Alternatively we
661 could use an indices array, and then only send 8 verts, but not sure that
662 would be faster.
663 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000664static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000665 GrScalar width) {
666 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000667 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000668
669 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
670 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
671 verts[2].set(rect.fRight - rad, rect.fTop + rad);
672 verts[3].set(rect.fRight + rad, rect.fTop - rad);
673 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
674 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
675 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
676 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
677 verts[8] = verts[0];
678 verts[9] = verts[1];
679}
680
bsalomon@google.com205d4602011-04-25 12:43:45 +0000681static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000682 // FIXME: This was copied from SkGpuDevice, seems like
683 // we should have already smeared a in caller if that
684 // is what is desired.
685 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000686 unsigned a = GrColorUnpackA(paint.fColor);
687 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000688 } else {
689 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000690 }
691}
692
693static void setInsetFan(GrPoint* pts, size_t stride,
694 const GrRect& r, GrScalar dx, GrScalar dy) {
695 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
696}
697
698static const uint16_t gFillAARectIdx[] = {
699 0, 1, 5, 5, 4, 0,
700 1, 2, 6, 6, 5, 1,
701 2, 3, 7, 7, 6, 2,
702 3, 0, 4, 4, 7, 3,
703 4, 5, 6, 6, 7, 4,
704};
705
706int GrContext::aaFillRectIndexCount() const {
707 return GR_ARRAY_COUNT(gFillAARectIdx);
708}
709
710GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
711 if (NULL == fAAFillRectIndexBuffer) {
712 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
713 false);
714 GrAssert(NULL != fAAFillRectIndexBuffer);
715#if GR_DEBUG
716 bool updated =
717#endif
718 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
719 sizeof(gFillAARectIdx));
720 GR_DEBUGASSERT(updated);
721 }
722 return fAAFillRectIndexBuffer;
723}
724
725static const uint16_t gStrokeAARectIdx[] = {
726 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
727 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
728 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
729 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
730
731 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
732 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
733 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
734 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
735
736 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
737 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
738 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
739 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
740};
741
742int GrContext::aaStrokeRectIndexCount() const {
743 return GR_ARRAY_COUNT(gStrokeAARectIdx);
744}
745
746GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
747 if (NULL == fAAStrokeRectIndexBuffer) {
748 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
749 false);
750 GrAssert(NULL != fAAStrokeRectIndexBuffer);
751#if GR_DEBUG
752 bool updated =
753#endif
754 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
755 sizeof(gStrokeAARectIdx));
756 GR_DEBUGASSERT(updated);
757 }
758 return fAAStrokeRectIndexBuffer;
759}
760
761void GrContext::fillAARect(GrDrawTarget* target,
762 const GrPaint& paint,
763 const GrRect& devRect) {
764
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000765 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
766 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000767
768 size_t vsize = GrDrawTarget::VertexSize(layout);
769
770 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
771
772 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
773
774 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
775 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
776
777 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
778 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
779
780 verts += sizeof(GrPoint);
781 for (int i = 0; i < 4; ++i) {
782 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
783 }
784
785 GrColor innerColor = getColorForMesh(paint);
786 verts += 4 * vsize;
787 for (int i = 0; i < 4; ++i) {
788 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
789 }
790
791 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
792
793 target->drawIndexed(kTriangles_PrimitiveType, 0,
794 0, 8, this->aaFillRectIndexCount());
795}
796
797void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
798 const GrRect& devRect, const GrVec& devStrokeSize) {
799 const GrScalar& dx = devStrokeSize.fX;
800 const GrScalar& dy = devStrokeSize.fY;
801 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
802 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
803
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000804 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
805 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000806
807 GrScalar spare;
808 {
809 GrScalar w = devRect.width() - dx;
810 GrScalar h = devRect.height() - dy;
811 spare = GrMin(w, h);
812 }
813
814 if (spare <= 0) {
815 GrRect r(devRect);
816 r.inset(-rx, -ry);
817 fillAARect(target, paint, r);
818 return;
819 }
820
821 size_t vsize = GrDrawTarget::VertexSize(layout);
822
823 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
824
825 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
826
827 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
828 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
829 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
830 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
831
832 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
833 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
834 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
835 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
836
837 verts += sizeof(GrPoint);
838 for (int i = 0; i < 4; ++i) {
839 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
840 }
841
842 GrColor innerColor = getColorForMesh(paint);
843 verts += 4 * vsize;
844 for (int i = 0; i < 8; ++i) {
845 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
846 }
847
848 verts += 8 * vsize;
849 for (int i = 0; i < 8; ++i) {
850 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
851 }
852
853 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
854 target->drawIndexed(kTriangles_PrimitiveType,
855 0, 0, 16, aaStrokeRectIndexCount());
856}
857
reed@google.com20efde72011-05-09 17:00:02 +0000858/**
859 * Returns true if the rects edges are integer-aligned.
860 */
861static bool isIRect(const GrRect& r) {
862 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
863 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
864}
865
bsalomon@google.com205d4602011-04-25 12:43:45 +0000866static bool apply_aa_to_rect(GrDrawTarget* target,
867 GrGpu* gpu,
868 const GrPaint& paint,
869 const GrRect& rect,
870 GrScalar width,
871 const GrMatrix* matrix,
872 GrMatrix* combinedMatrix,
873 GrRect* devRect) {
874 // we use a simple alpha ramp to do aa on axis-aligned rects
875 // do AA with alpha ramp if the caller requested AA, the rect
876 // will be axis-aligned,the render target is not
877 // multisampled, and the rect won't land on integer coords.
878
879 if (!paint.fAntiAlias) {
880 return false;
881 }
882
883 if (target->getRenderTarget()->isMultisampled()) {
884 return false;
885 }
886
887 if (0 == width && gpu->supportsAALines()) {
888 return false;
889 }
890
891 if (!target->getViewMatrix().preservesAxisAlignment()) {
892 return false;
893 }
894
895 if (NULL != matrix &&
896 !matrix->preservesAxisAlignment()) {
897 return false;
898 }
899
900 *combinedMatrix = target->getViewMatrix();
901 if (NULL != matrix) {
902 combinedMatrix->preConcat(*matrix);
903 GrAssert(combinedMatrix->preservesAxisAlignment());
904 }
905
906 combinedMatrix->mapRect(devRect, rect);
907 devRect->sort();
908
909 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000910 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000911 } else {
912 return true;
913 }
914}
915
bsalomon@google.com27847de2011-02-22 20:59:41 +0000916void GrContext::drawRect(const GrPaint& paint,
917 const GrRect& rect,
918 GrScalar width,
919 const GrMatrix* matrix) {
920
bsalomon@google.com27847de2011-02-22 20:59:41 +0000921
922 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000923 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000924
bsalomon@google.com205d4602011-04-25 12:43:45 +0000925 GrRect devRect = rect;
926 GrMatrix combinedMatrix;
927 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
928 &combinedMatrix, &devRect);
929
930 if (doAA) {
931 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000932 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000933 GrMatrix inv;
934 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000935 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000936 }
937 }
938 target->setViewMatrix(GrMatrix::I());
939 if (width >= 0) {
940 GrVec strokeSize;;
941 if (width > 0) {
942 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000943 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000944 strokeSize.setAbs(strokeSize);
945 } else {
946 strokeSize.set(GR_Scalar1, GR_Scalar1);
947 }
948 strokeAARect(target, paint, devRect, strokeSize);
949 } else {
950 fillAARect(target, paint, devRect);
951 }
952 return;
953 }
954
bsalomon@google.com27847de2011-02-22 20:59:41 +0000955 if (width >= 0) {
956 // TODO: consider making static vertex buffers for these cases.
957 // Hairline could be done by just adding closing vertex to
958 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000959 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
960
bsalomon@google.com27847de2011-02-22 20:59:41 +0000961 static const int worstCaseVertCount = 10;
962 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
963
964 if (!geo.succeeded()) {
965 return;
966 }
967
968 GrPrimitiveType primType;
969 int vertCount;
970 GrPoint* vertex = geo.positions();
971
972 if (width > 0) {
973 vertCount = 10;
974 primType = kTriangleStrip_PrimitiveType;
975 setStrokeRectStrip(vertex, rect, width);
976 } else {
977 // hairline
978 vertCount = 5;
979 primType = kLineStrip_PrimitiveType;
980 vertex[0].set(rect.fLeft, rect.fTop);
981 vertex[1].set(rect.fRight, rect.fTop);
982 vertex[2].set(rect.fRight, rect.fBottom);
983 vertex[3].set(rect.fLeft, rect.fBottom);
984 vertex[4].set(rect.fLeft, rect.fTop);
985 }
986
987 GrDrawTarget::AutoViewMatrixRestore avmr;
988 if (NULL != matrix) {
989 avmr.set(target);
990 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000991 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000992 }
993
994 target->drawNonIndexed(primType, 0, vertCount);
995 } else {
996 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000997 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
998
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000999 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001000 fGpu->getUnitSquareVertexBuffer());
1001 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1002 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001003 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001004 0, rect.height(), rect.fTop,
1005 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001006
1007 if (NULL != matrix) {
1008 m.postConcat(*matrix);
1009 }
1010
1011 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001012 target->preConcatSamplerMatrices(stageMask, m);
1013
bsalomon@google.com27847de2011-02-22 20:59:41 +00001014 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1015 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001016 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001017 #endif
1018 }
1019}
1020
1021void GrContext::drawRectToRect(const GrPaint& paint,
1022 const GrRect& dstRect,
1023 const GrRect& srcRect,
1024 const GrMatrix* dstMatrix,
1025 const GrMatrix* srcMatrix) {
1026
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001027 // srcRect refers to paint's first texture
1028 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001029 drawRect(paint, dstRect, -1, dstMatrix);
1030 return;
1031 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001032
bsalomon@google.com27847de2011-02-22 20:59:41 +00001033 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1034
1035#if GR_STATIC_RECT_VB
1036 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001037
1038 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001039 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1040
1041 GrMatrix m;
1042
1043 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1044 0, dstRect.height(), dstRect.fTop,
1045 0, 0, GrMatrix::I()[8]);
1046 if (NULL != dstMatrix) {
1047 m.postConcat(*dstMatrix);
1048 }
1049 target->preConcatViewMatrix(m);
1050
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001051 // srcRect refers to first stage
1052 int otherStageMask = paint.getActiveStageMask() &
1053 (~(1 << GrPaint::kFirstTextureStage));
1054 if (otherStageMask) {
1055 target->preConcatSamplerMatrices(otherStageMask, m);
1056 }
1057
bsalomon@google.com27847de2011-02-22 20:59:41 +00001058 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1059 0, srcRect.height(), srcRect.fTop,
1060 0, 0, GrMatrix::I()[8]);
1061 if (NULL != srcMatrix) {
1062 m.postConcat(*srcMatrix);
1063 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001064 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001065
1066 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1067 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1068#else
1069
1070 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001071#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001072 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001073#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001074 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1075#endif
1076
1077 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1078 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1079 srcRects[0] = &srcRect;
1080 srcMatrices[0] = srcMatrix;
1081
1082 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1083#endif
1084}
1085
1086void GrContext::drawVertices(const GrPaint& paint,
1087 GrPrimitiveType primitiveType,
1088 int vertexCount,
1089 const GrPoint positions[],
1090 const GrPoint texCoords[],
1091 const GrColor colors[],
1092 const uint16_t indices[],
1093 int indexCount) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001094
1095 GrDrawTarget::AutoReleaseGeometry geo;
1096
1097 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1098
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001099 bool hasTexCoords[GrPaint::kTotalStages] = {
1100 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1101 0 // remaining stages use positions
1102 };
1103
1104 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001105
1106 if (NULL != colors) {
1107 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001108 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001109 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001110
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001111 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001112 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001113 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001114
bsalomon@google.com27847de2011-02-22 20:59:41 +00001115 if (sizeof(GrPoint) != vertexSize) {
1116 if (!geo.set(target, layout, vertexCount, 0)) {
1117 GrPrintf("Failed to get space for vertices!");
1118 return;
1119 }
1120 int texOffsets[GrDrawTarget::kMaxTexCoords];
1121 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001122 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1123 texOffsets,
1124 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001125 void* curVertex = geo.vertices();
1126
1127 for (int i = 0; i < vertexCount; ++i) {
1128 *((GrPoint*)curVertex) = positions[i];
1129
1130 if (texOffsets[0] > 0) {
1131 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1132 }
1133 if (colorOffset > 0) {
1134 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1135 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001136 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001137 }
1138 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001139 // we don't do offscreen AA when we have per-vertex tex coords or colors
1140 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1141 GrRect b;
1142 b.setBounds(positions, vertexCount);
1143 target->getViewMatrix().mapRect(&b);
1144 b.roundOut(&bounds);
1145
1146 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1147 doAA = true;
1148 }
1149 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001150 target->setVertexSourceToArray(layout, positions, vertexCount);
1151 }
1152
1153 if (NULL != indices) {
1154 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001155 }
1156
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001157 if (NULL != indices) {
1158 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001160 target->drawNonIndexed(primitiveType, 0, vertexCount);
1161 }
1162
1163 if (doAA) {
1164 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001165 }
1166}
1167
1168
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001169///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001170
reed@google.com07f3ee12011-05-16 17:21:57 +00001171void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1172 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001173
bsalomon@google.com27847de2011-02-22 20:59:41 +00001174 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001175 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001176
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001177 if (!IsFillInverted(fill) && // will be relaxed soon
1178 !pr->supportsAA(target, path, fill) &&
1179 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001180
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001181 OffscreenRecord record;
1182 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001183
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001184 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001185 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1186 target->getRenderTarget()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001187 if (target->getClip().hasConservativeBounds()) {
1188 GrIRect clipIBounds;
1189 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001190 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001191 return;
1192 }
1193 }
reed@google.com70c136e2011-06-03 19:51:26 +00001194
reed@google.com07f3ee12011-05-16 17:21:57 +00001195 GrRect pathBounds = path.getBounds();
reed@google.com70c136e2011-06-03 19:51:26 +00001196 GrIRect pathIBounds;
reed@google.com07f3ee12011-05-16 17:21:57 +00001197 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001198 if (NULL != translate) {
1199 pathBounds.offset(*translate);
1200 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001201 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1202 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001203 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001204 return;
1205 }
1206 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001207
reed@google.com70c136e2011-06-03 19:51:26 +00001208 // for now, abort antialiasing if our bounds are too big, so we don't
1209 // hit the FBO size limit
1210 if (pathIBounds.width() > GR_MAX_OFFSCREEN_AA_DIM ||
1211 pathIBounds.height() > GR_MAX_OFFSCREEN_AA_DIM) {
1212 goto NO_AA;
1213 }
1214
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001215 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1216 pr->drawPath(target, 0, path, fill, translate);
1217 this->offscreenAAPass2(target, paint, bound, &record);
1218 return;
1219 }
reed@google.com70c136e2011-06-03 19:51:26 +00001220 }
1221
1222// we can fall out of the AA section for some reasons, and land here
1223NO_AA:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001224 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001225
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001226 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001228
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229////////////////////////////////////////////////////////////////////////////////
1230
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001231void GrContext::flush(int flagsBitfield) {
1232 if (kDiscard_FlushBit & flagsBitfield) {
1233 fDrawBuffer->reset();
1234 } else {
1235 flushDrawBuffer();
1236 }
1237
1238 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001239 fGpu->forceRenderTargetFlush();
1240 }
1241}
1242
1243void GrContext::flushText() {
1244 if (kText_DrawCategory == fLastDrawCategory) {
1245 flushDrawBuffer();
1246 }
1247}
1248
1249void GrContext::flushDrawBuffer() {
1250#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001251 if (fDrawBuffer) {
1252 fDrawBuffer->playback(fGpu);
1253 fDrawBuffer->reset();
1254 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255#endif
1256}
1257
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001258bool GrContext::readTexturePixels(GrTexture* texture,
1259 int left, int top, int width, int height,
1260 GrPixelConfig config, void* buffer) {
1261
1262 // TODO: code read pixels for textures that aren't rendertargets
1263
1264 this->flush();
1265 GrRenderTarget* target = texture->asRenderTarget();
1266 if (NULL != target) {
1267 return fGpu->readPixels(target,
1268 left, top, width, height,
1269 config, buffer);
1270 } else {
1271 return false;
1272 }
1273}
1274
1275bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1276 int left, int top, int width, int height,
1277 GrPixelConfig config, void* buffer) {
1278 uint32_t flushFlags = 0;
1279 if (NULL == target) {
1280 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1281 }
1282
1283 this->flush(flushFlags);
1284 return fGpu->readPixels(target,
1285 left, top, width, height,
1286 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287}
1288
1289void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001290 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001291 size_t stride) {
1292
1293 // TODO: when underlying api has a direct way to do this we should use it
1294 // (e.g. glDrawPixels on desktop GL).
1295
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001296 const GrTextureDesc desc = {
1297 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 };
1299 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1300 if (NULL == texture) {
1301 return;
1302 }
1303
1304 this->flush(true);
1305
1306 GrAutoUnref aur(texture);
1307 GrDrawTarget::AutoStateRestore asr(fGpu);
1308
1309 GrMatrix matrix;
1310 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1311 fGpu->setViewMatrix(matrix);
1312
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001313 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1315 fGpu->setAlpha(0xFF);
1316 fGpu->setBlendFunc(kOne_BlendCoeff,
1317 kZero_BlendCoeff);
1318 fGpu->setTexture(0, texture);
1319
1320 GrSamplerState sampler;
1321 sampler.setClampNoFilter();
1322 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1323 sampler.setMatrix(matrix);
1324 fGpu->setSamplerState(0, sampler);
1325
1326 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1327 static const int VCOUNT = 4;
1328
1329 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1330 if (!geo.succeeded()) {
1331 return;
1332 }
1333 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1334 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1335}
1336////////////////////////////////////////////////////////////////////////////////
1337
1338void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001339
1340 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1341 int s = i + GrPaint::kFirstTextureStage;
1342 target->setTexture(s, paint.getTexture(i));
1343 target->setSamplerState(s, *paint.getTextureSampler(i));
1344 }
1345
1346 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1347
1348 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1349 int s = i + GrPaint::kFirstMaskStage;
1350 target->setTexture(s, paint.getMask(i));
1351 target->setSamplerState(s, *paint.getMaskSampler(i));
1352 }
1353
bsalomon@google.com27847de2011-02-22 20:59:41 +00001354 target->setColor(paint.fColor);
1355
1356 if (paint.fDither) {
1357 target->enableState(GrDrawTarget::kDither_StateBit);
1358 } else {
1359 target->disableState(GrDrawTarget::kDither_StateBit);
1360 }
1361 if (paint.fAntiAlias) {
1362 target->enableState(GrDrawTarget::kAntialias_StateBit);
1363 } else {
1364 target->disableState(GrDrawTarget::kAntialias_StateBit);
1365 }
1366 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001367 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001368}
1369
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001370GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001371 DrawCategory category) {
1372 if (category != fLastDrawCategory) {
1373 flushDrawBuffer();
1374 fLastDrawCategory = category;
1375 }
1376 SetPaint(paint, fGpu);
1377 GrDrawTarget* target = fGpu;
1378 switch (category) {
1379 case kText_DrawCategory:
1380#if DEFER_TEXT_RENDERING
1381 target = fDrawBuffer;
1382 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1383#else
1384 target = fGpu;
1385#endif
1386 break;
1387 case kUnbuffered_DrawCategory:
1388 target = fGpu;
1389 break;
1390 case kBuffered_DrawCategory:
1391 target = fDrawBuffer;
1392 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1393 break;
1394 }
1395 return target;
1396}
1397
1398////////////////////////////////////////////////////////////////////////////////
1399
bsalomon@google.com27847de2011-02-22 20:59:41 +00001400void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001401 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402 fGpu->setRenderTarget(target);
1403}
1404
1405GrRenderTarget* GrContext::getRenderTarget() {
1406 return fGpu->getRenderTarget();
1407}
1408
1409const GrRenderTarget* GrContext::getRenderTarget() const {
1410 return fGpu->getRenderTarget();
1411}
1412
1413const GrMatrix& GrContext::getMatrix() const {
1414 return fGpu->getViewMatrix();
1415}
1416
1417void GrContext::setMatrix(const GrMatrix& m) {
1418 fGpu->setViewMatrix(m);
1419}
1420
1421void GrContext::concatMatrix(const GrMatrix& m) const {
1422 fGpu->preConcatViewMatrix(m);
1423}
1424
1425static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1426 intptr_t mask = 1 << shift;
1427 if (pred) {
1428 bits |= mask;
1429 } else {
1430 bits &= ~mask;
1431 }
1432 return bits;
1433}
1434
1435void GrContext::resetStats() {
1436 fGpu->resetStats();
1437}
1438
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001439const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440 return fGpu->getStats();
1441}
1442
1443void GrContext::printStats() const {
1444 fGpu->printStats();
1445}
1446
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001447GrContext::GrContext(GrGpu* gpu) :
1448 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1449 gpu->supportsStencilWrapOps()) {
1450
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451 fGpu = gpu;
1452 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001453 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001454
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001455 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1456 fGpu->setClipPathRenderer(fCustomPathRenderer);
1457
bsalomon@google.com27847de2011-02-22 20:59:41 +00001458 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1459 MAX_TEXTURE_CACHE_BYTES);
1460 fFontCache = new GrFontCache(fGpu);
1461
1462 fLastDrawCategory = kUnbuffered_DrawCategory;
1463
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001464 fDrawBuffer = NULL;
1465 fDrawBufferVBAllocPool = NULL;
1466 fDrawBufferIBAllocPool = NULL;
1467
bsalomon@google.com205d4602011-04-25 12:43:45 +00001468 fAAFillRectIndexBuffer = NULL;
1469 fAAStrokeRectIndexBuffer = NULL;
1470
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001471 this->setupDrawBuffer();
1472}
1473
1474void GrContext::setupDrawBuffer() {
1475
1476 GrAssert(NULL == fDrawBuffer);
1477 GrAssert(NULL == fDrawBufferVBAllocPool);
1478 GrAssert(NULL == fDrawBufferIBAllocPool);
1479
bsalomon@google.com27847de2011-02-22 20:59:41 +00001480#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001481 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001482 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001483 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1484 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001485 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001486 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001487 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001488 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1489
1490 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1491 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001492#endif
1493
1494#if BATCH_RECT_TO_RECT
1495 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1496#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001497}
1498
bsalomon@google.com27847de2011-02-22 20:59:41 +00001499GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1500 GrDrawTarget* target;
1501#if DEFER_TEXT_RENDERING
1502 target = prepareToDraw(paint, kText_DrawCategory);
1503#else
1504 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1505#endif
1506 SetPaint(paint, target);
1507 return target;
1508}
1509
1510const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1511 return fGpu->getQuadIndexBuffer();
1512}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001513
1514GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001515 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001516 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001517 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001518 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1519 return fCustomPathRenderer;
1520 } else {
1521 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1522 return &fDefaultPathRenderer;
1523 }
1524}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001525