blob: 8baa855dc9eda961d9cab6a71288ef4e7f88b6d9 [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() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000077 // abandon first to so destructors
78 // don't try to free the resources in the API.
79 fGpu->abandonResources();
80
bsalomon@google.com8fe72472011-03-30 21:26:44 +000081 delete fDrawBuffer;
82 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000083
bsalomon@google.com8fe72472011-03-30 21:26:44 +000084 delete fDrawBufferVBAllocPool;
85 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000086
bsalomon@google.com8fe72472011-03-30 21:26:44 +000087 delete fDrawBufferIBAllocPool;
88 fDrawBufferIBAllocPool = NULL;
89
bsalomon@google.com205d4602011-04-25 12:43:45 +000090 GrSafeSetNull(fAAFillRectIndexBuffer);
91 GrSafeSetNull(fAAStrokeRectIndexBuffer);
92
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 fTextureCache->removeAll();
94 fFontCache->freeAll();
95 fGpu->markContextDirty();
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 this->setupDrawBuffer();
98}
99
100void GrContext::resetContext() {
101 fGpu->markContextDirty();
102}
103
104void GrContext::freeGpuResources() {
105 this->flush();
106 fTextureCache->removeAll();
107 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000108}
109
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000110////////////////////////////////////////////////////////////////////////////////
111
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000112int GrContext::PaintStageVertexLayoutBits(
113 const GrPaint& paint,
114 const bool hasTexCoords[GrPaint::kTotalStages]) {
115 int stageMask = paint.getActiveStageMask();
116 int layout = 0;
117 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
118 if ((1 << i) & stageMask) {
119 if (NULL != hasTexCoords && hasTexCoords[i]) {
120 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
121 } else {
122 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
123 }
124 }
125 }
126 return layout;
127}
128
129
130////////////////////////////////////////////////////////////////////////////////
131
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000132enum {
133 kNPOTBit = 0x1,
134 kFilterBit = 0x2,
135 kKeylessBit = 0x4,
136};
137
138bool GrContext::finalizeTextureKey(GrTextureKey* key,
139 const GrSamplerState& sampler,
140 bool keyless) const {
141 uint32_t bits = 0;
142 uint16_t width = key->width();
143 uint16_t height = key->height();
144
145 if (!fGpu->npotTextureTileSupport()) {
146 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
147
148 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
149 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
150
151 if (tiled && !isPow2) {
152 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000153 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000154 bits |= kFilterBit;
155 }
156 }
157 }
158
159 if (keyless) {
160 bits |= kKeylessBit;
161 }
162 key->finalize(bits);
163 return 0 != bits;
164}
165
bsalomon@google.com27847de2011-02-22 20:59:41 +0000166GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
167 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000168 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000169 return fTextureCache->findAndLock(*key);
170}
171
172static void stretchImage(void* dst,
173 int dstW,
174 int dstH,
175 void* src,
176 int srcW,
177 int srcH,
178 int bpp) {
179 GrFixed dx = (srcW << 16) / dstW;
180 GrFixed dy = (srcH << 16) / dstH;
181
182 GrFixed y = dy >> 1;
183
184 int dstXLimit = dstW*bpp;
185 for (int j = 0; j < dstH; ++j) {
186 GrFixed x = dx >> 1;
187 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
188 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
189 for (int i = 0; i < dstXLimit; i += bpp) {
190 memcpy((uint8_t*) dstRow + i,
191 (uint8_t*) srcRow + (x>>16)*bpp,
192 bpp);
193 x += dx;
194 }
195 y += dy;
196 }
197}
198
199GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
200 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000201 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000202 void* srcData, size_t rowBytes) {
203 GrAssert(key->width() == desc.fWidth);
204 GrAssert(key->height() == desc.fHeight);
205
206#if GR_DUMP_TEXTURE_UPLOAD
207 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
208#endif
209
210 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000211 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000212 if (special) {
213 GrTextureEntry* clampEntry;
214 GrTextureKey clampKey(*key);
215 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
216
217 if (NULL == clampEntry) {
218 clampEntry = createAndLockTexture(&clampKey,
219 GrSamplerState::ClampNoFilter(),
220 desc, srcData, rowBytes);
221 GrAssert(NULL != clampEntry);
222 if (NULL == clampEntry) {
223 return NULL;
224 }
225 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000226 GrTextureDesc rtDesc = desc;
227 rtDesc.fFlags = rtDesc.fFlags |
228 kRenderTarget_GrTextureFlagBit |
229 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000230 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
231 fGpu->minRenderTargetWidth()));
232 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
233 fGpu->minRenderTargetHeight()));
234
235 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
236
237 if (NULL != texture) {
238 GrDrawTarget::AutoStateRestore asr(fGpu);
239 fGpu->setRenderTarget(texture->asRenderTarget());
240 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000241 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000242 fGpu->setViewMatrix(GrMatrix::I());
243 fGpu->setAlpha(0xff);
244 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
245 fGpu->disableState(GrDrawTarget::kDither_StateBit |
246 GrDrawTarget::kClip_StateBit |
247 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000248 GrSamplerState::Filter filter;
249 // if filtering is not desired then we want to ensure all
250 // texels in the resampled image are copies of texels from
251 // the original.
252 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
253 filter = GrSamplerState::kNearest_Filter;
254 } else {
255 filter = GrSamplerState::kBilinear_Filter;
256 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000257 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
258 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000259 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000260 fGpu->setSamplerState(0, stretchSampler);
261
262 static const GrVertexLayout layout =
263 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
264 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
265
266 if (arg.succeeded()) {
267 GrPoint* verts = (GrPoint*) arg.vertices();
268 verts[0].setIRectFan(0, 0,
269 texture->width(),
270 texture->height(),
271 2*sizeof(GrPoint));
272 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
273 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
274 0, 4);
275 entry = fTextureCache->createAndLock(*key, texture);
276 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000277 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000278 } else {
279 // TODO: Our CPU stretch doesn't filter. But we create separate
280 // stretched textures when the sampler state is either filtered or
281 // not. Either implement filtered stretch blit on CPU or just create
282 // one when FBO case fails.
283
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000284 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000285 // no longer need to clamp at min RT size.
286 rtDesc.fWidth = GrNextPow2(desc.fWidth);
287 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000288 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000289 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
290 rtDesc.fWidth *
291 rtDesc.fHeight);
292 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
293 srcData, desc.fWidth, desc.fHeight, bpp);
294
295 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
296
297 GrTexture* texture = fGpu->createTexture(rtDesc,
298 stretchedPixels.get(),
299 stretchedRowBytes);
300 GrAssert(NULL != texture);
301 entry = fTextureCache->createAndLock(*key, texture);
302 }
303 fTextureCache->unlock(clampEntry);
304
305 } else {
306 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
307 if (NULL != texture) {
308 entry = fTextureCache->createAndLock(*key, texture);
309 } else {
310 entry = NULL;
311 }
312 }
313 return entry;
314}
315
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000316GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000317 uint32_t p0 = desc.fFormat;
318 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
319 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000320 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
321
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000322 GrTextureEntry* entry = fTextureCache->findAndLock(key);
323 if (NULL == entry) {
324 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
325 if (NULL != texture) {
326 entry = fTextureCache->createAndLock(key, texture);
327 }
328 }
329 // If the caller gives us the same desc/sampler twice we don't want
330 // to return the same texture the second time (unless it was previously
331 // released). So we detach the entry from the cache and reattach at release.
332 if (NULL != entry) {
333 fTextureCache->detach(entry);
334 }
335 return entry;
336}
337
bsalomon@google.com27847de2011-02-22 20:59:41 +0000338void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000339 if (kKeylessBit & entry->key().getPrivateBits()) {
340 fTextureCache->reattachAndUnlock(entry);
341 } else {
342 fTextureCache->unlock(entry);
343 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000344}
345
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000346GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000347 void* srcData,
348 size_t rowBytes) {
349 return fGpu->createTexture(desc, srcData, rowBytes);
350}
351
352void GrContext::getTextureCacheLimits(int* maxTextures,
353 size_t* maxTextureBytes) const {
354 fTextureCache->getLimits(maxTextures, maxTextureBytes);
355}
356
357void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
358 fTextureCache->setLimits(maxTextures, maxTextureBytes);
359}
360
361int GrContext::getMaxTextureDimension() {
362 return fGpu->maxTextureDimension();
363}
364
365///////////////////////////////////////////////////////////////////////////////
366
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000367GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
368 // validate flags here so that GrGpu subclasses don't have to check
369 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
370 0 != desc.fRenderTargetFlags) {
371 return NULL;
372 }
373 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
374 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
375 return NULL;
376 }
377 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
378 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
379 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
380 return NULL;
381 }
382 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000383}
384
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000385GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000386 return fGpu->createRenderTargetFrom3DApiState();
387}
388
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000389///////////////////////////////////////////////////////////////////////////////
390
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
392 int width, int height) {
393 if (!fGpu->supports8BitPalette()) {
394 return false;
395 }
396
397
398 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
399
400 if (!isPow2) {
401 if (!fGpu->npotTextureSupport()) {
402 return false;
403 }
404
405 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
406 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
407 if (tiled && !fGpu->npotTextureTileSupport()) {
408 return false;
409 }
410 }
411 return true;
412}
413
414////////////////////////////////////////////////////////////////////////////////
415
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000416const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
417
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418void GrContext::setClip(const GrClip& clip) {
419 fGpu->setClip(clip);
420 fGpu->enableState(GrDrawTarget::kClip_StateBit);
421}
422
423void GrContext::setClip(const GrIRect& rect) {
424 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000425 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000426 fGpu->setClip(clip);
427}
428
429////////////////////////////////////////////////////////////////////////////////
430
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000431void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000432 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000433 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000434}
435
436void GrContext::drawPaint(const GrPaint& paint) {
437 // set rect to be big enough to fill the space, but not super-huge, so we
438 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000439 GrRect r;
440 r.setLTRB(0, 0,
441 GrIntToScalar(getRenderTarget()->width()),
442 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000443 GrMatrix inverse;
444 if (fGpu->getViewInverse(&inverse)) {
445 inverse.mapRect(&r);
446 } else {
447 GrPrintf("---- fGpu->getViewInverse failed\n");
448 }
449 this->drawRect(paint, r);
450}
451
bsalomon@google.com205d4602011-04-25 12:43:45 +0000452////////////////////////////////////////////////////////////////////////////////
453
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000454bool GrContext::doOffscreenAA(GrDrawTarget* target,
455 const GrPaint& paint,
456 bool isLines) const {
reed@google.com70c136e2011-06-03 19:51:26 +0000457#if GR_MAX_OFFSCREEN_AA_DIM==0
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000458 return false;
459#else
460 if (!paint.fAntiAlias) {
461 return false;
462 }
463 if (isLines && fGpu->supportsAALines()) {
464 return false;
465 }
466 if (target->getRenderTarget()->isMultisampled()) {
467 return false;
468 }
469 // we have to be sure that the blend equation is expressible
470 // as simple src / dst coeffecients when the source
471 // is already modulated by the coverage fraction.
472 // We could use dual-source blending to get the correct per-pixel
473 // dst coeffecient for the remaining cases.
474 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
475 kOne_BlendCoeff != paint.fDstBlendCoeff &&
476 kISA_BlendCoeff != paint.fDstBlendCoeff) {
477 return false;
478 }
479 return true;
480#endif
481}
482
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000483bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
484 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000485 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000486 OffscreenRecord* record) {
reed@google.com70c136e2011-06-03 19:51:26 +0000487 GrAssert(GR_MAX_OFFSCREEN_AA_DIM > 0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000488
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000489 GrAssert(NULL == record->fEntry0);
490 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000491
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000492 int boundW = boundRect.width();
493 int boundH = boundRect.height();
494 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000495
496 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000497 if (requireStencil) {
498 desc.fFlags = kRenderTarget_GrTextureFlagBit;
499 } else {
500 desc.fFlags = kRenderTarget_GrTextureFlagBit |
501 kNoStencil_GrTextureFlagBit;
502 }
503
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000504 desc.fFormat = kRGBA_8888_GrPixelConfig;
505
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000506 int scale;
507 // Using MSAA seems to be slower for some yet unknown reason.
508 if (false && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000509 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000510 scale = GR_Scalar1;
511 desc.fAALevel = kMed_GrAALevel;
512 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000513 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
514 OffscreenRecord::k4x4SinglePass_Downsample :
515 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000516 scale = 4;
517 desc.fAALevel = kNone_GrAALevel;
518 }
519
520 desc.fWidth = scale * size;
521 desc.fHeight = scale * size;
522
523 record->fEntry0 = this->lockKeylessTexture(desc);
524
525 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000526 return false;
527 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000528
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000529 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000530 desc.fWidth /= 2;
531 desc.fHeight /= 2;
532 record->fEntry1 = this->lockKeylessTexture(desc);
533 if (NULL == record->fEntry1) {
534 this->unlockTexture(record->fEntry0);
535 record->fEntry0 = NULL;
536 return false;
537 }
538 }
539
540 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
541 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000542
543 target->saveCurrentDrawState(&record->fSavedState);
544
545 GrPaint tempPaint;
546 tempPaint.reset();
547 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000548 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000549
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000550 GrMatrix transM;
551 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
552 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000553 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000554 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000555 target->postConcatViewMatrix(scaleM);
556
557 // clip gets applied in second pass
558 target->disableState(GrDrawTarget::kClip_StateBit);
559
reed@google.com20efde72011-05-09 17:00:02 +0000560 GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000561 target->clear(&clear, 0x0);
562
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000563 return true;
564}
565
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000566void GrContext::offscreenAAPass2(GrDrawTarget* target,
567 const GrPaint& paint,
568 const GrIRect& boundRect,
569 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000570
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000571 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000572
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000573 GrSamplerState::Filter filter;
574 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
575 filter = GrSamplerState::k4x4Downsample_Filter;
576 } else {
577 filter = GrSamplerState::kBilinear_Filter;
578 }
579
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000580 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000581 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000582 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000583
584 GrTexture* src = record->fEntry0->texture();
585 int scale;
586
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000587 enum {
588 kOffscreenStage = GrPaint::kTotalStages,
589 };
590
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000591 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
592 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000593 scale = 2;
594 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
595
596 // Do 2x2 downsample from first to second
597 target->setTexture(kOffscreenStage, src);
598 target->setRenderTarget(dst);
599 target->setViewMatrix(GrMatrix::I());
600 sampleM.setScale(scale * GR_Scalar1 / src->width(),
601 scale * GR_Scalar1 / src->height());
602 sampler.setMatrix(sampleM);
603 target->setSamplerState(kOffscreenStage, sampler);
reed@google.com20efde72011-05-09 17:00:02 +0000604 GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
605 scale * boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000606 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
607
608 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000609 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000610 scale = 1;
reed@google.com20efde72011-05-09 17:00:02 +0000611 GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000612 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000613 } else {
614 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
615 record->fDownsample);
616 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000617 }
618
619 // setup for draw back to main RT
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000620 int stageMask = paint.getActiveStageMask();
621
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000622 target->restoreDrawState(record->fSavedState);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000623
624 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000625 GrMatrix invVM;
626 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000627 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000628 }
629 }
630 target->setViewMatrix(GrMatrix::I());
631
632 target->setTexture(kOffscreenStage, src);
633 sampleM.setScale(scale * GR_Scalar1 / src->width(),
634 scale * GR_Scalar1 / src->height());
635 sampler.setMatrix(sampleM);
636 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
637 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000638 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000639
reed@google.com20efde72011-05-09 17:00:02 +0000640 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000641 int stages = (1 << kOffscreenStage) | stageMask;
reed@google.com20efde72011-05-09 17:00:02 +0000642 dstRect.set(boundRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000643 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000644
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000645 this->unlockTexture(record->fEntry0);
646 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000647 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000648 this->unlockTexture(record->fEntry1);
649 record->fEntry1 = NULL;
650 }
651 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000652}
653
654////////////////////////////////////////////////////////////////////////////////
655
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656/* create a triangle strip that strokes the specified triangle. There are 8
657 unique vertices, but we repreat the last 2 to close up. Alternatively we
658 could use an indices array, and then only send 8 verts, but not sure that
659 would be faster.
660 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000661static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000662 GrScalar width) {
663 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000664 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000665
666 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
667 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
668 verts[2].set(rect.fRight - rad, rect.fTop + rad);
669 verts[3].set(rect.fRight + rad, rect.fTop - rad);
670 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
671 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
672 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
673 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
674 verts[8] = verts[0];
675 verts[9] = verts[1];
676}
677
bsalomon@google.com205d4602011-04-25 12:43:45 +0000678static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000679 // FIXME: This was copied from SkGpuDevice, seems like
680 // we should have already smeared a in caller if that
681 // is what is desired.
682 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000683 unsigned a = GrColorUnpackA(paint.fColor);
684 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000685 } else {
686 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000687 }
688}
689
690static void setInsetFan(GrPoint* pts, size_t stride,
691 const GrRect& r, GrScalar dx, GrScalar dy) {
692 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
693}
694
695static const uint16_t gFillAARectIdx[] = {
696 0, 1, 5, 5, 4, 0,
697 1, 2, 6, 6, 5, 1,
698 2, 3, 7, 7, 6, 2,
699 3, 0, 4, 4, 7, 3,
700 4, 5, 6, 6, 7, 4,
701};
702
703int GrContext::aaFillRectIndexCount() const {
704 return GR_ARRAY_COUNT(gFillAARectIdx);
705}
706
707GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
708 if (NULL == fAAFillRectIndexBuffer) {
709 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
710 false);
711 GrAssert(NULL != fAAFillRectIndexBuffer);
712#if GR_DEBUG
713 bool updated =
714#endif
715 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
716 sizeof(gFillAARectIdx));
717 GR_DEBUGASSERT(updated);
718 }
719 return fAAFillRectIndexBuffer;
720}
721
722static const uint16_t gStrokeAARectIdx[] = {
723 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
724 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
725 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
726 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
727
728 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
729 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
730 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
731 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
732
733 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
734 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
735 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
736 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
737};
738
739int GrContext::aaStrokeRectIndexCount() const {
740 return GR_ARRAY_COUNT(gStrokeAARectIdx);
741}
742
743GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
744 if (NULL == fAAStrokeRectIndexBuffer) {
745 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
746 false);
747 GrAssert(NULL != fAAStrokeRectIndexBuffer);
748#if GR_DEBUG
749 bool updated =
750#endif
751 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
752 sizeof(gStrokeAARectIdx));
753 GR_DEBUGASSERT(updated);
754 }
755 return fAAStrokeRectIndexBuffer;
756}
757
758void GrContext::fillAARect(GrDrawTarget* target,
759 const GrPaint& paint,
760 const GrRect& devRect) {
761
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000762 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
763 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000764
765 size_t vsize = GrDrawTarget::VertexSize(layout);
766
767 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
768
769 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
770
771 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
772 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
773
774 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
775 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
776
777 verts += sizeof(GrPoint);
778 for (int i = 0; i < 4; ++i) {
779 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
780 }
781
782 GrColor innerColor = getColorForMesh(paint);
783 verts += 4 * vsize;
784 for (int i = 0; i < 4; ++i) {
785 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
786 }
787
788 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
789
790 target->drawIndexed(kTriangles_PrimitiveType, 0,
791 0, 8, this->aaFillRectIndexCount());
792}
793
794void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
795 const GrRect& devRect, const GrVec& devStrokeSize) {
796 const GrScalar& dx = devStrokeSize.fX;
797 const GrScalar& dy = devStrokeSize.fY;
798 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
799 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
800
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000801 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
802 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000803
804 GrScalar spare;
805 {
806 GrScalar w = devRect.width() - dx;
807 GrScalar h = devRect.height() - dy;
808 spare = GrMin(w, h);
809 }
810
811 if (spare <= 0) {
812 GrRect r(devRect);
813 r.inset(-rx, -ry);
814 fillAARect(target, paint, r);
815 return;
816 }
817
818 size_t vsize = GrDrawTarget::VertexSize(layout);
819
820 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
821
822 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
823
824 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
825 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
826 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
827 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
828
829 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
830 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
831 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
832 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
833
834 verts += sizeof(GrPoint);
835 for (int i = 0; i < 4; ++i) {
836 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
837 }
838
839 GrColor innerColor = getColorForMesh(paint);
840 verts += 4 * vsize;
841 for (int i = 0; i < 8; ++i) {
842 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
843 }
844
845 verts += 8 * vsize;
846 for (int i = 0; i < 8; ++i) {
847 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
848 }
849
850 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
851 target->drawIndexed(kTriangles_PrimitiveType,
852 0, 0, 16, aaStrokeRectIndexCount());
853}
854
reed@google.com20efde72011-05-09 17:00:02 +0000855/**
856 * Returns true if the rects edges are integer-aligned.
857 */
858static bool isIRect(const GrRect& r) {
859 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
860 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
861}
862
bsalomon@google.com205d4602011-04-25 12:43:45 +0000863static bool apply_aa_to_rect(GrDrawTarget* target,
864 GrGpu* gpu,
865 const GrPaint& paint,
866 const GrRect& rect,
867 GrScalar width,
868 const GrMatrix* matrix,
869 GrMatrix* combinedMatrix,
870 GrRect* devRect) {
871 // we use a simple alpha ramp to do aa on axis-aligned rects
872 // do AA with alpha ramp if the caller requested AA, the rect
873 // will be axis-aligned,the render target is not
874 // multisampled, and the rect won't land on integer coords.
875
876 if (!paint.fAntiAlias) {
877 return false;
878 }
879
880 if (target->getRenderTarget()->isMultisampled()) {
881 return false;
882 }
883
884 if (0 == width && gpu->supportsAALines()) {
885 return false;
886 }
887
888 if (!target->getViewMatrix().preservesAxisAlignment()) {
889 return false;
890 }
891
892 if (NULL != matrix &&
893 !matrix->preservesAxisAlignment()) {
894 return false;
895 }
896
897 *combinedMatrix = target->getViewMatrix();
898 if (NULL != matrix) {
899 combinedMatrix->preConcat(*matrix);
900 GrAssert(combinedMatrix->preservesAxisAlignment());
901 }
902
903 combinedMatrix->mapRect(devRect, rect);
904 devRect->sort();
905
906 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000907 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 } else {
909 return true;
910 }
911}
912
bsalomon@google.com27847de2011-02-22 20:59:41 +0000913void GrContext::drawRect(const GrPaint& paint,
914 const GrRect& rect,
915 GrScalar width,
916 const GrMatrix* matrix) {
917
bsalomon@google.com27847de2011-02-22 20:59:41 +0000918
919 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000920 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000921
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922 GrRect devRect = rect;
923 GrMatrix combinedMatrix;
924 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
925 &combinedMatrix, &devRect);
926
927 if (doAA) {
928 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000929 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000930 GrMatrix inv;
931 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000932 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000933 }
934 }
935 target->setViewMatrix(GrMatrix::I());
936 if (width >= 0) {
937 GrVec strokeSize;;
938 if (width > 0) {
939 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000940 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000941 strokeSize.setAbs(strokeSize);
942 } else {
943 strokeSize.set(GR_Scalar1, GR_Scalar1);
944 }
945 strokeAARect(target, paint, devRect, strokeSize);
946 } else {
947 fillAARect(target, paint, devRect);
948 }
949 return;
950 }
951
bsalomon@google.com27847de2011-02-22 20:59:41 +0000952 if (width >= 0) {
953 // TODO: consider making static vertex buffers for these cases.
954 // Hairline could be done by just adding closing vertex to
955 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000956 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
957
bsalomon@google.com27847de2011-02-22 20:59:41 +0000958 static const int worstCaseVertCount = 10;
959 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
960
961 if (!geo.succeeded()) {
962 return;
963 }
964
965 GrPrimitiveType primType;
966 int vertCount;
967 GrPoint* vertex = geo.positions();
968
969 if (width > 0) {
970 vertCount = 10;
971 primType = kTriangleStrip_PrimitiveType;
972 setStrokeRectStrip(vertex, rect, width);
973 } else {
974 // hairline
975 vertCount = 5;
976 primType = kLineStrip_PrimitiveType;
977 vertex[0].set(rect.fLeft, rect.fTop);
978 vertex[1].set(rect.fRight, rect.fTop);
979 vertex[2].set(rect.fRight, rect.fBottom);
980 vertex[3].set(rect.fLeft, rect.fBottom);
981 vertex[4].set(rect.fLeft, rect.fTop);
982 }
983
984 GrDrawTarget::AutoViewMatrixRestore avmr;
985 if (NULL != matrix) {
986 avmr.set(target);
987 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000988 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000989 }
990
991 target->drawNonIndexed(primType, 0, vertCount);
992 } else {
993 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000994 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
995
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000996 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000997 fGpu->getUnitSquareVertexBuffer());
998 GrDrawTarget::AutoViewMatrixRestore avmr(target);
999 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001000 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001001 0, rect.height(), rect.fTop,
1002 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001003
1004 if (NULL != matrix) {
1005 m.postConcat(*matrix);
1006 }
1007
1008 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001009 target->preConcatSamplerMatrices(stageMask, m);
1010
bsalomon@google.com27847de2011-02-22 20:59:41 +00001011 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1012 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001013 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001014 #endif
1015 }
1016}
1017
1018void GrContext::drawRectToRect(const GrPaint& paint,
1019 const GrRect& dstRect,
1020 const GrRect& srcRect,
1021 const GrMatrix* dstMatrix,
1022 const GrMatrix* srcMatrix) {
1023
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001024 // srcRect refers to paint's first texture
1025 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001026 drawRect(paint, dstRect, -1, dstMatrix);
1027 return;
1028 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001029
bsalomon@google.com27847de2011-02-22 20:59:41 +00001030 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1031
1032#if GR_STATIC_RECT_VB
1033 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001034
1035 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001036 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1037
1038 GrMatrix m;
1039
1040 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1041 0, dstRect.height(), dstRect.fTop,
1042 0, 0, GrMatrix::I()[8]);
1043 if (NULL != dstMatrix) {
1044 m.postConcat(*dstMatrix);
1045 }
1046 target->preConcatViewMatrix(m);
1047
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001048 // srcRect refers to first stage
1049 int otherStageMask = paint.getActiveStageMask() &
1050 (~(1 << GrPaint::kFirstTextureStage));
1051 if (otherStageMask) {
1052 target->preConcatSamplerMatrices(otherStageMask, m);
1053 }
1054
bsalomon@google.com27847de2011-02-22 20:59:41 +00001055 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1056 0, srcRect.height(), srcRect.fTop,
1057 0, 0, GrMatrix::I()[8]);
1058 if (NULL != srcMatrix) {
1059 m.postConcat(*srcMatrix);
1060 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001061 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001062
1063 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1064 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1065#else
1066
1067 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001068#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001069 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001070#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001071 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1072#endif
1073
1074 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1075 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1076 srcRects[0] = &srcRect;
1077 srcMatrices[0] = srcMatrix;
1078
1079 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1080#endif
1081}
1082
1083void GrContext::drawVertices(const GrPaint& paint,
1084 GrPrimitiveType primitiveType,
1085 int vertexCount,
1086 const GrPoint positions[],
1087 const GrPoint texCoords[],
1088 const GrColor colors[],
1089 const uint16_t indices[],
1090 int indexCount) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001091
1092 GrDrawTarget::AutoReleaseGeometry geo;
1093
1094 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1095
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001096 bool hasTexCoords[GrPaint::kTotalStages] = {
1097 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1098 0 // remaining stages use positions
1099 };
1100
1101 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001102
1103 if (NULL != colors) {
1104 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001105 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001106 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001107
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001108 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001109 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001110 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001111
bsalomon@google.com27847de2011-02-22 20:59:41 +00001112 if (sizeof(GrPoint) != vertexSize) {
1113 if (!geo.set(target, layout, vertexCount, 0)) {
1114 GrPrintf("Failed to get space for vertices!");
1115 return;
1116 }
1117 int texOffsets[GrDrawTarget::kMaxTexCoords];
1118 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001119 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1120 texOffsets,
1121 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001122 void* curVertex = geo.vertices();
1123
1124 for (int i = 0; i < vertexCount; ++i) {
1125 *((GrPoint*)curVertex) = positions[i];
1126
1127 if (texOffsets[0] > 0) {
1128 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1129 }
1130 if (colorOffset > 0) {
1131 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1132 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001133 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001134 }
1135 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001136 // we don't do offscreen AA when we have per-vertex tex coords or colors
1137 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1138 GrRect b;
1139 b.setBounds(positions, vertexCount);
1140 target->getViewMatrix().mapRect(&b);
1141 b.roundOut(&bounds);
1142
1143 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1144 doAA = true;
1145 }
1146 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001147 target->setVertexSourceToArray(layout, positions, vertexCount);
1148 }
1149
1150 if (NULL != indices) {
1151 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001152 }
1153
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001154 if (NULL != indices) {
1155 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001156 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001157 target->drawNonIndexed(primitiveType, 0, vertexCount);
1158 }
1159
1160 if (doAA) {
1161 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001162 }
1163}
1164
1165
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001166///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167
reed@google.com07f3ee12011-05-16 17:21:57 +00001168void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1169 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001170
bsalomon@google.com27847de2011-02-22 20:59:41 +00001171 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001172 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001173
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001174 if (!IsFillInverted(fill) && // will be relaxed soon
1175 !pr->supportsAA(target, path, fill) &&
1176 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001177
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001178 OffscreenRecord record;
1179 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001180
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001181 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001182 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1183 target->getRenderTarget()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001184 if (target->getClip().hasConservativeBounds()) {
1185 GrIRect clipIBounds;
1186 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001187 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001188 return;
1189 }
1190 }
reed@google.com70c136e2011-06-03 19:51:26 +00001191
reed@google.com07f3ee12011-05-16 17:21:57 +00001192 GrRect pathBounds = path.getBounds();
reed@google.com70c136e2011-06-03 19:51:26 +00001193 GrIRect pathIBounds;
reed@google.com07f3ee12011-05-16 17:21:57 +00001194 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001195 if (NULL != translate) {
1196 pathBounds.offset(*translate);
1197 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001198 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1199 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001200 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001201 return;
1202 }
1203 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001204
reed@google.com70c136e2011-06-03 19:51:26 +00001205 // for now, abort antialiasing if our bounds are too big, so we don't
1206 // hit the FBO size limit
1207 if (pathIBounds.width() > GR_MAX_OFFSCREEN_AA_DIM ||
1208 pathIBounds.height() > GR_MAX_OFFSCREEN_AA_DIM) {
1209 goto NO_AA;
1210 }
1211
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001212 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1213 pr->drawPath(target, 0, path, fill, translate);
1214 this->offscreenAAPass2(target, paint, bound, &record);
1215 return;
1216 }
reed@google.com70c136e2011-06-03 19:51:26 +00001217 }
1218
1219// we can fall out of the AA section for some reasons, and land here
1220NO_AA:
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001221 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001222
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001223 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001224}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001225
bsalomon@google.com27847de2011-02-22 20:59:41 +00001226////////////////////////////////////////////////////////////////////////////////
1227
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001228void GrContext::flush(int flagsBitfield) {
1229 if (kDiscard_FlushBit & flagsBitfield) {
1230 fDrawBuffer->reset();
1231 } else {
1232 flushDrawBuffer();
1233 }
1234
1235 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001236 fGpu->forceRenderTargetFlush();
1237 }
1238}
1239
1240void GrContext::flushText() {
1241 if (kText_DrawCategory == fLastDrawCategory) {
1242 flushDrawBuffer();
1243 }
1244}
1245
1246void GrContext::flushDrawBuffer() {
1247#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1248 fDrawBuffer->playback(fGpu);
1249 fDrawBuffer->reset();
1250#endif
1251}
1252
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001253bool GrContext::readTexturePixels(GrTexture* texture,
1254 int left, int top, int width, int height,
1255 GrPixelConfig config, void* buffer) {
1256
1257 // TODO: code read pixels for textures that aren't rendertargets
1258
1259 this->flush();
1260 GrRenderTarget* target = texture->asRenderTarget();
1261 if (NULL != target) {
1262 return fGpu->readPixels(target,
1263 left, top, width, height,
1264 config, buffer);
1265 } else {
1266 return false;
1267 }
1268}
1269
1270bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1271 int left, int top, int width, int height,
1272 GrPixelConfig config, void* buffer) {
1273 uint32_t flushFlags = 0;
1274 if (NULL == target) {
1275 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1276 }
1277
1278 this->flush(flushFlags);
1279 return fGpu->readPixels(target,
1280 left, top, width, height,
1281 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001282}
1283
1284void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001285 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001286 size_t stride) {
1287
1288 // TODO: when underlying api has a direct way to do this we should use it
1289 // (e.g. glDrawPixels on desktop GL).
1290
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001291 const GrTextureDesc desc = {
1292 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001293 };
1294 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1295 if (NULL == texture) {
1296 return;
1297 }
1298
1299 this->flush(true);
1300
1301 GrAutoUnref aur(texture);
1302 GrDrawTarget::AutoStateRestore asr(fGpu);
1303
1304 GrMatrix matrix;
1305 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1306 fGpu->setViewMatrix(matrix);
1307
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001308 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001309 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1310 fGpu->setAlpha(0xFF);
1311 fGpu->setBlendFunc(kOne_BlendCoeff,
1312 kZero_BlendCoeff);
1313 fGpu->setTexture(0, texture);
1314
1315 GrSamplerState sampler;
1316 sampler.setClampNoFilter();
1317 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1318 sampler.setMatrix(matrix);
1319 fGpu->setSamplerState(0, sampler);
1320
1321 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1322 static const int VCOUNT = 4;
1323
1324 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1325 if (!geo.succeeded()) {
1326 return;
1327 }
1328 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1329 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1330}
1331////////////////////////////////////////////////////////////////////////////////
1332
1333void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001334
1335 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1336 int s = i + GrPaint::kFirstTextureStage;
1337 target->setTexture(s, paint.getTexture(i));
1338 target->setSamplerState(s, *paint.getTextureSampler(i));
1339 }
1340
1341 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1342
1343 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1344 int s = i + GrPaint::kFirstMaskStage;
1345 target->setTexture(s, paint.getMask(i));
1346 target->setSamplerState(s, *paint.getMaskSampler(i));
1347 }
1348
bsalomon@google.com27847de2011-02-22 20:59:41 +00001349 target->setColor(paint.fColor);
1350
1351 if (paint.fDither) {
1352 target->enableState(GrDrawTarget::kDither_StateBit);
1353 } else {
1354 target->disableState(GrDrawTarget::kDither_StateBit);
1355 }
1356 if (paint.fAntiAlias) {
1357 target->enableState(GrDrawTarget::kAntialias_StateBit);
1358 } else {
1359 target->disableState(GrDrawTarget::kAntialias_StateBit);
1360 }
1361 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001362 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363}
1364
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001365GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001366 DrawCategory category) {
1367 if (category != fLastDrawCategory) {
1368 flushDrawBuffer();
1369 fLastDrawCategory = category;
1370 }
1371 SetPaint(paint, fGpu);
1372 GrDrawTarget* target = fGpu;
1373 switch (category) {
1374 case kText_DrawCategory:
1375#if DEFER_TEXT_RENDERING
1376 target = fDrawBuffer;
1377 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1378#else
1379 target = fGpu;
1380#endif
1381 break;
1382 case kUnbuffered_DrawCategory:
1383 target = fGpu;
1384 break;
1385 case kBuffered_DrawCategory:
1386 target = fDrawBuffer;
1387 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1388 break;
1389 }
1390 return target;
1391}
1392
1393////////////////////////////////////////////////////////////////////////////////
1394
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001396 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397 fGpu->setRenderTarget(target);
1398}
1399
1400GrRenderTarget* GrContext::getRenderTarget() {
1401 return fGpu->getRenderTarget();
1402}
1403
1404const GrRenderTarget* GrContext::getRenderTarget() const {
1405 return fGpu->getRenderTarget();
1406}
1407
1408const GrMatrix& GrContext::getMatrix() const {
1409 return fGpu->getViewMatrix();
1410}
1411
1412void GrContext::setMatrix(const GrMatrix& m) {
1413 fGpu->setViewMatrix(m);
1414}
1415
1416void GrContext::concatMatrix(const GrMatrix& m) const {
1417 fGpu->preConcatViewMatrix(m);
1418}
1419
1420static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1421 intptr_t mask = 1 << shift;
1422 if (pred) {
1423 bits |= mask;
1424 } else {
1425 bits &= ~mask;
1426 }
1427 return bits;
1428}
1429
1430void GrContext::resetStats() {
1431 fGpu->resetStats();
1432}
1433
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001434const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001435 return fGpu->getStats();
1436}
1437
1438void GrContext::printStats() const {
1439 fGpu->printStats();
1440}
1441
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001442GrContext::GrContext(GrGpu* gpu) :
1443 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1444 gpu->supportsStencilWrapOps()) {
1445
bsalomon@google.com27847de2011-02-22 20:59:41 +00001446 fGpu = gpu;
1447 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001448 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001449
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001450 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1451 fGpu->setClipPathRenderer(fCustomPathRenderer);
1452
bsalomon@google.com27847de2011-02-22 20:59:41 +00001453 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1454 MAX_TEXTURE_CACHE_BYTES);
1455 fFontCache = new GrFontCache(fGpu);
1456
1457 fLastDrawCategory = kUnbuffered_DrawCategory;
1458
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001459 fDrawBuffer = NULL;
1460 fDrawBufferVBAllocPool = NULL;
1461 fDrawBufferIBAllocPool = NULL;
1462
bsalomon@google.com205d4602011-04-25 12:43:45 +00001463 fAAFillRectIndexBuffer = NULL;
1464 fAAStrokeRectIndexBuffer = NULL;
1465
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001466 this->setupDrawBuffer();
1467}
1468
1469void GrContext::setupDrawBuffer() {
1470
1471 GrAssert(NULL == fDrawBuffer);
1472 GrAssert(NULL == fDrawBufferVBAllocPool);
1473 GrAssert(NULL == fDrawBufferIBAllocPool);
1474
bsalomon@google.com27847de2011-02-22 20:59:41 +00001475#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001476 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001477 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001478 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1479 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001480 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001481 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001482 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001483 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1484
1485 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1486 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001487#endif
1488
1489#if BATCH_RECT_TO_RECT
1490 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1491#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001492}
1493
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1495 GrDrawTarget* target;
1496#if DEFER_TEXT_RENDERING
1497 target = prepareToDraw(paint, kText_DrawCategory);
1498#else
1499 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1500#endif
1501 SetPaint(paint, target);
1502 return target;
1503}
1504
1505const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1506 return fGpu->getQuadIndexBuffer();
1507}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001508
1509GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001510 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001511 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001512 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001513 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1514 return fCustomPathRenderer;
1515 } else {
1516 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1517 return &fDefaultPathRenderer;
1518 }
1519}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001520