blob: ff3119a53d9c57792e8a4f639f82c5073dfe6b4c [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"
22#include "GrPathIter.h"
23#include "GrClipIterator.h"
24#include "GrIndexBuffer.h"
25#include "GrInOrderDrawBuffer.h"
26#include "GrBufferAllocPool.h"
27#include "GrPathRenderer.h"
28
bsalomon@google.com8295dc12011-05-02 12:53:34 +000029#define ENABLE_OFFSCREEN_AA 0
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000030
bsalomon@google.com27847de2011-02-22 20:59:41 +000031#define DEFER_TEXT_RENDERING 1
32
33#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
34
35static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
36static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
37
38static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
39static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
40
41// We are currently only batching Text and drawRectToRect, both
42// of which use the quad index buffer.
43static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
44static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
45
bsalomon@google.com05ef5102011-05-02 21:14:59 +000046GrContext* GrContext::Create(GrEngine engine,
47 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000048 GrContext* ctx = NULL;
49 GrGpu* fGpu = GrGpu::Create(engine, context3D);
50 if (NULL != fGpu) {
51 ctx = new GrContext(fGpu);
52 fGpu->unref();
53 }
54 return ctx;
55}
56
57GrContext* GrContext::CreateGLShaderContext() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +000058 return GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +000059}
60
61GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000068 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000072}
73
bsalomon@google.com8fe72472011-03-30 21:26:44 +000074void GrContext::contextLost() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000075 // abandon first to so destructors
76 // don't try to free the resources in the API.
77 fGpu->abandonResources();
78
bsalomon@google.com8fe72472011-03-30 21:26:44 +000079 delete fDrawBuffer;
80 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000081
bsalomon@google.com8fe72472011-03-30 21:26:44 +000082 delete fDrawBufferVBAllocPool;
83 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000084
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBufferIBAllocPool;
86 fDrawBufferIBAllocPool = NULL;
87
bsalomon@google.com205d4602011-04-25 12:43:45 +000088 GrSafeSetNull(fAAFillRectIndexBuffer);
89 GrSafeSetNull(fAAStrokeRectIndexBuffer);
90
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 fTextureCache->removeAll();
92 fFontCache->freeAll();
93 fGpu->markContextDirty();
94
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 this->setupDrawBuffer();
96}
97
98void GrContext::resetContext() {
99 fGpu->markContextDirty();
100}
101
102void GrContext::freeGpuResources() {
103 this->flush();
104 fTextureCache->removeAll();
105 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000106}
107
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000108////////////////////////////////////////////////////////////////////////////////
109
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000110enum {
111 kNPOTBit = 0x1,
112 kFilterBit = 0x2,
113 kKeylessBit = 0x4,
114};
115
116bool GrContext::finalizeTextureKey(GrTextureKey* key,
117 const GrSamplerState& sampler,
118 bool keyless) const {
119 uint32_t bits = 0;
120 uint16_t width = key->width();
121 uint16_t height = key->height();
122
123 if (!fGpu->npotTextureTileSupport()) {
124 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
125
126 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
127 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
128
129 if (tiled && !isPow2) {
130 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000131 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000132 bits |= kFilterBit;
133 }
134 }
135 }
136
137 if (keyless) {
138 bits |= kKeylessBit;
139 }
140 key->finalize(bits);
141 return 0 != bits;
142}
143
bsalomon@google.com27847de2011-02-22 20:59:41 +0000144GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
145 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000146 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000147 return fTextureCache->findAndLock(*key);
148}
149
150static void stretchImage(void* dst,
151 int dstW,
152 int dstH,
153 void* src,
154 int srcW,
155 int srcH,
156 int bpp) {
157 GrFixed dx = (srcW << 16) / dstW;
158 GrFixed dy = (srcH << 16) / dstH;
159
160 GrFixed y = dy >> 1;
161
162 int dstXLimit = dstW*bpp;
163 for (int j = 0; j < dstH; ++j) {
164 GrFixed x = dx >> 1;
165 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
166 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
167 for (int i = 0; i < dstXLimit; i += bpp) {
168 memcpy((uint8_t*) dstRow + i,
169 (uint8_t*) srcRow + (x>>16)*bpp,
170 bpp);
171 x += dx;
172 }
173 y += dy;
174 }
175}
176
177GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
178 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000180 void* srcData, size_t rowBytes) {
181 GrAssert(key->width() == desc.fWidth);
182 GrAssert(key->height() == desc.fHeight);
183
184#if GR_DUMP_TEXTURE_UPLOAD
185 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
186#endif
187
188 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000190 if (special) {
191 GrTextureEntry* clampEntry;
192 GrTextureKey clampKey(*key);
193 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
194
195 if (NULL == clampEntry) {
196 clampEntry = createAndLockTexture(&clampKey,
197 GrSamplerState::ClampNoFilter(),
198 desc, srcData, rowBytes);
199 GrAssert(NULL != clampEntry);
200 if (NULL == clampEntry) {
201 return NULL;
202 }
203 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000204 GrTextureDesc rtDesc = desc;
205 rtDesc.fFlags = rtDesc.fFlags |
206 kRenderTarget_GrTextureFlagBit |
207 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000208 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
209 fGpu->minRenderTargetWidth()));
210 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
211 fGpu->minRenderTargetHeight()));
212
213 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
214
215 if (NULL != texture) {
216 GrDrawTarget::AutoStateRestore asr(fGpu);
217 fGpu->setRenderTarget(texture->asRenderTarget());
218 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000219 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000220 fGpu->setViewMatrix(GrMatrix::I());
221 fGpu->setAlpha(0xff);
222 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
223 fGpu->disableState(GrDrawTarget::kDither_StateBit |
224 GrDrawTarget::kClip_StateBit |
225 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000226 GrSamplerState::Filter filter;
227 // if filtering is not desired then we want to ensure all
228 // texels in the resampled image are copies of texels from
229 // the original.
230 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
231 filter = GrSamplerState::kNearest_Filter;
232 } else {
233 filter = GrSamplerState::kBilinear_Filter;
234 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000235 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
236 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000237 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000238 fGpu->setSamplerState(0, stretchSampler);
239
240 static const GrVertexLayout layout =
241 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
242 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
243
244 if (arg.succeeded()) {
245 GrPoint* verts = (GrPoint*) arg.vertices();
246 verts[0].setIRectFan(0, 0,
247 texture->width(),
248 texture->height(),
249 2*sizeof(GrPoint));
250 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
251 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
252 0, 4);
253 entry = fTextureCache->createAndLock(*key, texture);
254 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000255 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000256 } else {
257 // TODO: Our CPU stretch doesn't filter. But we create separate
258 // stretched textures when the sampler state is either filtered or
259 // not. Either implement filtered stretch blit on CPU or just create
260 // one when FBO case fails.
261
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000262 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000263 // no longer need to clamp at min RT size.
264 rtDesc.fWidth = GrNextPow2(desc.fWidth);
265 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000266 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000267 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
268 rtDesc.fWidth *
269 rtDesc.fHeight);
270 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
271 srcData, desc.fWidth, desc.fHeight, bpp);
272
273 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
274
275 GrTexture* texture = fGpu->createTexture(rtDesc,
276 stretchedPixels.get(),
277 stretchedRowBytes);
278 GrAssert(NULL != texture);
279 entry = fTextureCache->createAndLock(*key, texture);
280 }
281 fTextureCache->unlock(clampEntry);
282
283 } else {
284 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
285 if (NULL != texture) {
286 entry = fTextureCache->createAndLock(*key, texture);
287 } else {
288 entry = NULL;
289 }
290 }
291 return entry;
292}
293
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000294GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000295 uint32_t p0 = desc.fFormat;
296 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
297 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000298 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
299
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000300 GrTextureEntry* entry = fTextureCache->findAndLock(key);
301 if (NULL == entry) {
302 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
303 if (NULL != texture) {
304 entry = fTextureCache->createAndLock(key, texture);
305 }
306 }
307 // If the caller gives us the same desc/sampler twice we don't want
308 // to return the same texture the second time (unless it was previously
309 // released). So we detach the entry from the cache and reattach at release.
310 if (NULL != entry) {
311 fTextureCache->detach(entry);
312 }
313 return entry;
314}
315
bsalomon@google.com27847de2011-02-22 20:59:41 +0000316void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000317 if (kKeylessBit & entry->key().getPrivateBits()) {
318 fTextureCache->reattachAndUnlock(entry);
319 } else {
320 fTextureCache->unlock(entry);
321 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000322}
323
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000324GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000325 void* srcData,
326 size_t rowBytes) {
327 return fGpu->createTexture(desc, srcData, rowBytes);
328}
329
330void GrContext::getTextureCacheLimits(int* maxTextures,
331 size_t* maxTextureBytes) const {
332 fTextureCache->getLimits(maxTextures, maxTextureBytes);
333}
334
335void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
336 fTextureCache->setLimits(maxTextures, maxTextureBytes);
337}
338
339int GrContext::getMaxTextureDimension() {
340 return fGpu->maxTextureDimension();
341}
342
343///////////////////////////////////////////////////////////////////////////////
344
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000345GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
346 // validate flags here so that GrGpu subclasses don't have to check
347 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
348 0 != desc.fRenderTargetFlags) {
349 return NULL;
350 }
351 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
352 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
353 return NULL;
354 }
355 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
356 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
357 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
358 return NULL;
359 }
360 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000361}
362
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000363GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
364 int stencilBits,
365 bool isMultisampled,
366 int width, int height) {
367#if GR_DEBUG
368 GrPrintf("Using deprecated createPlatformRenderTarget API.");
369#endif
370 return fGpu->createPlatformRenderTarget(platformRenderTarget,
371 stencilBits, isMultisampled,
372 width, height);
373}
374
375GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
376#if GR_DEBUG
377 GrPrintf("Using deprecated createRenderTargetFrom3DApiState API.");
378#endif
379 return fGpu->createRenderTargetFrom3DApiState();
380}
381
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000382///////////////////////////////////////////////////////////////////////////////
383
bsalomon@google.com27847de2011-02-22 20:59:41 +0000384bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
385 int width, int height) {
386 if (!fGpu->supports8BitPalette()) {
387 return false;
388 }
389
390
391 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
392
393 if (!isPow2) {
394 if (!fGpu->npotTextureSupport()) {
395 return false;
396 }
397
398 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
399 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
400 if (tiled && !fGpu->npotTextureTileSupport()) {
401 return false;
402 }
403 }
404 return true;
405}
406
407////////////////////////////////////////////////////////////////////////////////
408
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000409const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
410
bsalomon@google.com27847de2011-02-22 20:59:41 +0000411void GrContext::setClip(const GrClip& clip) {
412 fGpu->setClip(clip);
413 fGpu->enableState(GrDrawTarget::kClip_StateBit);
414}
415
416void GrContext::setClip(const GrIRect& rect) {
417 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000418 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000419 fGpu->setClip(clip);
420}
421
422////////////////////////////////////////////////////////////////////////////////
423
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000424void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000425 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000426 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000427}
428
429void GrContext::drawPaint(const GrPaint& paint) {
430 // set rect to be big enough to fill the space, but not super-huge, so we
431 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000432 GrRect r;
433 r.setLTRB(0, 0,
434 GrIntToScalar(getRenderTarget()->width()),
435 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000436 GrMatrix inverse;
437 if (fGpu->getViewInverse(&inverse)) {
438 inverse.mapRect(&r);
439 } else {
440 GrPrintf("---- fGpu->getViewInverse failed\n");
441 }
442 this->drawRect(paint, r);
443}
444
bsalomon@google.com205d4602011-04-25 12:43:45 +0000445////////////////////////////////////////////////////////////////////////////////
446
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000447bool GrContext::doOffscreenAA(GrDrawTarget* target,
448 const GrPaint& paint,
449 bool isLines) const {
450#if !ENABLE_OFFSCREEN_AA
451 return false;
452#else
453 if (!paint.fAntiAlias) {
454 return false;
455 }
456 if (isLines && fGpu->supportsAALines()) {
457 return false;
458 }
459 if (target->getRenderTarget()->isMultisampled()) {
460 return false;
461 }
462 // we have to be sure that the blend equation is expressible
463 // as simple src / dst coeffecients when the source
464 // is already modulated by the coverage fraction.
465 // We could use dual-source blending to get the correct per-pixel
466 // dst coeffecient for the remaining cases.
467 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
468 kOne_BlendCoeff != paint.fDstBlendCoeff &&
469 kISA_BlendCoeff != paint.fDstBlendCoeff) {
470 return false;
471 }
472 return true;
473#endif
474}
475
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000476bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
477 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000478 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000479 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000480 GrAssert(ENABLE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000481
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000482 GrAssert(NULL == record->fEntry0);
483 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000484
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000485 int boundW = boundRect.width();
486 int boundH = boundRect.height();
487 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000488
489 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000490 if (requireStencil) {
491 desc.fFlags = kRenderTarget_GrTextureFlagBit;
492 } else {
493 desc.fFlags = kRenderTarget_GrTextureFlagBit |
494 kNoStencil_GrTextureFlagBit;
495 }
496
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000497 desc.fFormat = kRGBA_8888_GrPixelConfig;
498
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000499 int scale;
500 // Using MSAA seems to be slower for some yet unknown reason.
501 if (false && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000502 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000503 scale = GR_Scalar1;
504 desc.fAALevel = kMed_GrAALevel;
505 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000506 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
507 OffscreenRecord::k4x4SinglePass_Downsample :
508 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000509 scale = 4;
510 desc.fAALevel = kNone_GrAALevel;
511 }
512
513 desc.fWidth = scale * size;
514 desc.fHeight = scale * size;
515
516 record->fEntry0 = this->lockKeylessTexture(desc);
517
518 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000519 return false;
520 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000521
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000522 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000523 desc.fWidth /= 2;
524 desc.fHeight /= 2;
525 record->fEntry1 = this->lockKeylessTexture(desc);
526 if (NULL == record->fEntry1) {
527 this->unlockTexture(record->fEntry0);
528 record->fEntry0 = NULL;
529 return false;
530 }
531 }
532
533 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
534 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000535
536 target->saveCurrentDrawState(&record->fSavedState);
537
538 GrPaint tempPaint;
539 tempPaint.reset();
540 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000541 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000542
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000543 GrMatrix transM;
544 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
545 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000546 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000547 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000548 target->postConcatViewMatrix(scaleM);
549
550 // clip gets applied in second pass
551 target->disableState(GrDrawTarget::kClip_StateBit);
552
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000553 GrIRect clear(0, 0, scale * boundW, scale * boundH);
554 target->clear(&clear, 0x0);
555
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000556 return true;
557}
558
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000559void GrContext::offscreenAAPass2(GrDrawTarget* target,
560 const GrPaint& paint,
561 const GrIRect& boundRect,
562 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000563
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000564 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000565
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000566 GrSamplerState::Filter filter;
567 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
568 filter = GrSamplerState::k4x4Downsample_Filter;
569 } else {
570 filter = GrSamplerState::kBilinear_Filter;
571 }
572
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000573 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000574 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000575 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000576
577 GrTexture* src = record->fEntry0->texture();
578 int scale;
579
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000580 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
581 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000582 scale = 2;
583 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
584
585 // Do 2x2 downsample from first to second
586 target->setTexture(kOffscreenStage, src);
587 target->setRenderTarget(dst);
588 target->setViewMatrix(GrMatrix::I());
589 sampleM.setScale(scale * GR_Scalar1 / src->width(),
590 scale * GR_Scalar1 / src->height());
591 sampler.setMatrix(sampleM);
592 target->setSamplerState(kOffscreenStage, sampler);
593 GrRect rect(0, 0,
594 scale * boundRect.width(),
595 scale * boundRect.height());
596 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
597
598 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000599 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000600 scale = 1;
601 GrIRect rect(0, 0, boundRect.width(), boundRect.height());
602 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000603 } else {
604 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
605 record->fDownsample);
606 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000607 }
608
609 // setup for draw back to main RT
610 target->restoreDrawState(record->fSavedState);
611 if (NULL != paint.getTexture()) {
612 GrMatrix invVM;
613 if (target->getViewInverse(&invVM)) {
614 target->preConcatSamplerMatrix(0, invVM);
615 }
616 }
617 target->setViewMatrix(GrMatrix::I());
618
619 target->setTexture(kOffscreenStage, src);
620 sampleM.setScale(scale * GR_Scalar1 / src->width(),
621 scale * GR_Scalar1 / src->height());
622 sampler.setMatrix(sampleM);
623 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
624 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000625 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000626
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000627 GrRect dstRect(boundRect);
628 int stages = (1 << kOffscreenStage) | (NULL == paint.getTexture() ? 0 : 1);
629 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000630
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000631 this->unlockTexture(record->fEntry0);
632 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000633 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 this->unlockTexture(record->fEntry1);
635 record->fEntry1 = NULL;
636 }
637 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000638}
639
640////////////////////////////////////////////////////////////////////////////////
641
bsalomon@google.com27847de2011-02-22 20:59:41 +0000642/* create a triangle strip that strokes the specified triangle. There are 8
643 unique vertices, but we repreat the last 2 to close up. Alternatively we
644 could use an indices array, and then only send 8 verts, but not sure that
645 would be faster.
646 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000647static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000648 GrScalar width) {
649 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000650 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000651
652 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
653 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
654 verts[2].set(rect.fRight - rad, rect.fTop + rad);
655 verts[3].set(rect.fRight + rad, rect.fTop - rad);
656 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
657 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
658 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
659 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
660 verts[8] = verts[0];
661 verts[9] = verts[1];
662}
663
bsalomon@google.com205d4602011-04-25 12:43:45 +0000664static GrColor getColorForMesh(const GrPaint& paint) {
665 if (NULL == paint.getTexture()) {
666 return paint.fColor;
667 } else {
668 unsigned a = GrColorUnpackA(paint.fColor);
669 return GrColorPackRGBA(a, a, a, a);
670 }
671}
672
673static void setInsetFan(GrPoint* pts, size_t stride,
674 const GrRect& r, GrScalar dx, GrScalar dy) {
675 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
676}
677
678static const uint16_t gFillAARectIdx[] = {
679 0, 1, 5, 5, 4, 0,
680 1, 2, 6, 6, 5, 1,
681 2, 3, 7, 7, 6, 2,
682 3, 0, 4, 4, 7, 3,
683 4, 5, 6, 6, 7, 4,
684};
685
686int GrContext::aaFillRectIndexCount() const {
687 return GR_ARRAY_COUNT(gFillAARectIdx);
688}
689
690GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
691 if (NULL == fAAFillRectIndexBuffer) {
692 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
693 false);
694 GrAssert(NULL != fAAFillRectIndexBuffer);
695#if GR_DEBUG
696 bool updated =
697#endif
698 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
699 sizeof(gFillAARectIdx));
700 GR_DEBUGASSERT(updated);
701 }
702 return fAAFillRectIndexBuffer;
703}
704
705static const uint16_t gStrokeAARectIdx[] = {
706 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
707 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
708 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
709 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
710
711 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
712 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
713 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
714 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
715
716 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
717 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
718 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
719 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
720};
721
722int GrContext::aaStrokeRectIndexCount() const {
723 return GR_ARRAY_COUNT(gStrokeAARectIdx);
724}
725
726GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
727 if (NULL == fAAStrokeRectIndexBuffer) {
728 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
729 false);
730 GrAssert(NULL != fAAStrokeRectIndexBuffer);
731#if GR_DEBUG
732 bool updated =
733#endif
734 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
735 sizeof(gStrokeAARectIdx));
736 GR_DEBUGASSERT(updated);
737 }
738 return fAAStrokeRectIndexBuffer;
739}
740
741void GrContext::fillAARect(GrDrawTarget* target,
742 const GrPaint& paint,
743 const GrRect& devRect) {
744
745 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
746 if (NULL != paint.getTexture()) {
747 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
748 }
749
750 size_t vsize = GrDrawTarget::VertexSize(layout);
751
752 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
753
754 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
755
756 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
757 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
758
759 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
760 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
761
762 verts += sizeof(GrPoint);
763 for (int i = 0; i < 4; ++i) {
764 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
765 }
766
767 GrColor innerColor = getColorForMesh(paint);
768 verts += 4 * vsize;
769 for (int i = 0; i < 4; ++i) {
770 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
771 }
772
773 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
774
775 target->drawIndexed(kTriangles_PrimitiveType, 0,
776 0, 8, this->aaFillRectIndexCount());
777}
778
779void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
780 const GrRect& devRect, const GrVec& devStrokeSize) {
781 const GrScalar& dx = devStrokeSize.fX;
782 const GrScalar& dy = devStrokeSize.fY;
783 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
784 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
785
786 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
787
788 if (NULL != paint.getTexture()) {
789 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
790 }
791
792 GrScalar spare;
793 {
794 GrScalar w = devRect.width() - dx;
795 GrScalar h = devRect.height() - dy;
796 spare = GrMin(w, h);
797 }
798
799 if (spare <= 0) {
800 GrRect r(devRect);
801 r.inset(-rx, -ry);
802 fillAARect(target, paint, r);
803 return;
804 }
805
806 size_t vsize = GrDrawTarget::VertexSize(layout);
807
808 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
809
810 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
811
812 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
813 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
814 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
815 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
816
817 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
818 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
819 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
820 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
821
822 verts += sizeof(GrPoint);
823 for (int i = 0; i < 4; ++i) {
824 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
825 }
826
827 GrColor innerColor = getColorForMesh(paint);
828 verts += 4 * vsize;
829 for (int i = 0; i < 8; ++i) {
830 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
831 }
832
833 verts += 8 * vsize;
834 for (int i = 0; i < 8; ++i) {
835 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
836 }
837
838 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
839 target->drawIndexed(kTriangles_PrimitiveType,
840 0, 0, 16, aaStrokeRectIndexCount());
841}
842
843static bool apply_aa_to_rect(GrDrawTarget* target,
844 GrGpu* gpu,
845 const GrPaint& paint,
846 const GrRect& rect,
847 GrScalar width,
848 const GrMatrix* matrix,
849 GrMatrix* combinedMatrix,
850 GrRect* devRect) {
851 // we use a simple alpha ramp to do aa on axis-aligned rects
852 // do AA with alpha ramp if the caller requested AA, the rect
853 // will be axis-aligned,the render target is not
854 // multisampled, and the rect won't land on integer coords.
855
856 if (!paint.fAntiAlias) {
857 return false;
858 }
859
860 if (target->getRenderTarget()->isMultisampled()) {
861 return false;
862 }
863
864 if (0 == width && gpu->supportsAALines()) {
865 return false;
866 }
867
868 if (!target->getViewMatrix().preservesAxisAlignment()) {
869 return false;
870 }
871
872 if (NULL != matrix &&
873 !matrix->preservesAxisAlignment()) {
874 return false;
875 }
876
877 *combinedMatrix = target->getViewMatrix();
878 if (NULL != matrix) {
879 combinedMatrix->preConcat(*matrix);
880 GrAssert(combinedMatrix->preservesAxisAlignment());
881 }
882
883 combinedMatrix->mapRect(devRect, rect);
884 devRect->sort();
885
886 if (width < 0) {
887 return !devRect->isIRect();
888 } else {
889 return true;
890 }
891}
892
bsalomon@google.com27847de2011-02-22 20:59:41 +0000893void GrContext::drawRect(const GrPaint& paint,
894 const GrRect& rect,
895 GrScalar width,
896 const GrMatrix* matrix) {
897
898 bool textured = NULL != paint.getTexture();
899
900 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
901
bsalomon@google.com205d4602011-04-25 12:43:45 +0000902 GrRect devRect = rect;
903 GrMatrix combinedMatrix;
904 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
905 &combinedMatrix, &devRect);
906
907 if (doAA) {
908 GrDrawTarget::AutoViewMatrixRestore avm(target);
909 if (textured) {
910 GrMatrix inv;
911 if (combinedMatrix.invert(&inv)) {
912 target->preConcatSamplerMatrix(0, inv);
913 }
914 }
915 target->setViewMatrix(GrMatrix::I());
916 if (width >= 0) {
917 GrVec strokeSize;;
918 if (width > 0) {
919 strokeSize.set(width, width);
920 combinedMatrix.mapVec(&strokeSize);
921 strokeSize.setAbs(strokeSize);
922 } else {
923 strokeSize.set(GR_Scalar1, GR_Scalar1);
924 }
925 strokeAARect(target, paint, devRect, strokeSize);
926 } else {
927 fillAARect(target, paint, devRect);
928 }
929 return;
930 }
931
bsalomon@google.com27847de2011-02-22 20:59:41 +0000932 if (width >= 0) {
933 // TODO: consider making static vertex buffers for these cases.
934 // Hairline could be done by just adding closing vertex to
935 // unitSquareVertexBuffer()
bsalomon@google.com205d4602011-04-25 12:43:45 +0000936 GrVertexLayout layout = textured ?
937 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
938 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000939 static const int worstCaseVertCount = 10;
940 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
941
942 if (!geo.succeeded()) {
943 return;
944 }
945
946 GrPrimitiveType primType;
947 int vertCount;
948 GrPoint* vertex = geo.positions();
949
950 if (width > 0) {
951 vertCount = 10;
952 primType = kTriangleStrip_PrimitiveType;
953 setStrokeRectStrip(vertex, rect, width);
954 } else {
955 // hairline
956 vertCount = 5;
957 primType = kLineStrip_PrimitiveType;
958 vertex[0].set(rect.fLeft, rect.fTop);
959 vertex[1].set(rect.fRight, rect.fTop);
960 vertex[2].set(rect.fRight, rect.fBottom);
961 vertex[3].set(rect.fLeft, rect.fBottom);
962 vertex[4].set(rect.fLeft, rect.fTop);
963 }
964
965 GrDrawTarget::AutoViewMatrixRestore avmr;
966 if (NULL != matrix) {
967 avmr.set(target);
968 target->preConcatViewMatrix(*matrix);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000969 if (textured) {
970 target->preConcatSamplerMatrix(0, *matrix);
971 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000972 }
973
974 target->drawNonIndexed(primType, 0, vertCount);
975 } else {
976 #if GR_STATIC_RECT_VB
977 GrVertexLayout layout = (textured) ?
978 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
979 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000980 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000981 fGpu->getUnitSquareVertexBuffer());
982 GrDrawTarget::AutoViewMatrixRestore avmr(target);
983 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000984 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000985 0, rect.height(), rect.fTop,
986 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000987
988 if (NULL != matrix) {
989 m.postConcat(*matrix);
990 }
991
992 target->preConcatViewMatrix(m);
993
994 if (textured) {
995 target->preConcatSamplerMatrix(0, m);
996 }
997 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
998 #else
999 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
1000 #endif
1001 }
1002}
1003
1004void GrContext::drawRectToRect(const GrPaint& paint,
1005 const GrRect& dstRect,
1006 const GrRect& srcRect,
1007 const GrMatrix* dstMatrix,
1008 const GrMatrix* srcMatrix) {
1009
1010 if (NULL == paint.getTexture()) {
1011 drawRect(paint, dstRect, -1, dstMatrix);
1012 return;
1013 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001014
bsalomon@google.com27847de2011-02-22 20:59:41 +00001015 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1016
1017#if GR_STATIC_RECT_VB
1018 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1019
1020 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1021 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1022
1023 GrMatrix m;
1024
1025 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1026 0, dstRect.height(), dstRect.fTop,
1027 0, 0, GrMatrix::I()[8]);
1028 if (NULL != dstMatrix) {
1029 m.postConcat(*dstMatrix);
1030 }
1031 target->preConcatViewMatrix(m);
1032
1033 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1034 0, srcRect.height(), srcRect.fTop,
1035 0, 0, GrMatrix::I()[8]);
1036 if (NULL != srcMatrix) {
1037 m.postConcat(*srcMatrix);
1038 }
1039 target->preConcatSamplerMatrix(0, m);
1040
1041 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1042 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1043#else
1044
1045 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001046#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001047 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001048#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001049 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1050#endif
1051
1052 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1053 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1054 srcRects[0] = &srcRect;
1055 srcMatrices[0] = srcMatrix;
1056
1057 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1058#endif
1059}
1060
1061void GrContext::drawVertices(const GrPaint& paint,
1062 GrPrimitiveType primitiveType,
1063 int vertexCount,
1064 const GrPoint positions[],
1065 const GrPoint texCoords[],
1066 const GrColor colors[],
1067 const uint16_t indices[],
1068 int indexCount) {
1069 GrVertexLayout layout = 0;
1070 int vertexSize = sizeof(GrPoint);
1071
1072 GrDrawTarget::AutoReleaseGeometry geo;
1073
1074 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1075
1076 if (NULL != paint.getTexture()) {
1077 if (NULL == texCoords) {
1078 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1079 } else {
1080 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
1081 vertexSize += sizeof(GrPoint);
1082 }
1083 }
1084
1085 if (NULL != colors) {
1086 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1087 vertexSize += sizeof(GrColor);
1088 }
1089
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001090 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001091 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001092 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001093
bsalomon@google.com27847de2011-02-22 20:59:41 +00001094 if (sizeof(GrPoint) != vertexSize) {
1095 if (!geo.set(target, layout, vertexCount, 0)) {
1096 GrPrintf("Failed to get space for vertices!");
1097 return;
1098 }
1099 int texOffsets[GrDrawTarget::kMaxTexCoords];
1100 int colorOffset;
1101 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1102 texOffsets,
1103 &colorOffset);
1104 void* curVertex = geo.vertices();
1105
1106 for (int i = 0; i < vertexCount; ++i) {
1107 *((GrPoint*)curVertex) = positions[i];
1108
1109 if (texOffsets[0] > 0) {
1110 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1111 }
1112 if (colorOffset > 0) {
1113 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1114 }
1115 curVertex = (void*)((intptr_t)curVertex + vsize);
1116 }
1117 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001118 // we don't do offscreen AA when we have per-vertex tex coords or colors
1119 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1120 GrRect b;
1121 b.setBounds(positions, vertexCount);
1122 target->getViewMatrix().mapRect(&b);
1123 b.roundOut(&bounds);
1124
1125 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1126 doAA = true;
1127 }
1128 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001129 target->setVertexSourceToArray(layout, positions, vertexCount);
1130 }
1131
1132 if (NULL != indices) {
1133 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001134 }
1135
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001136 if (NULL != indices) {
1137 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001138 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001139 target->drawNonIndexed(primitiveType, 0, vertexCount);
1140 }
1141
1142 if (doAA) {
1143 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001144 }
1145}
1146
1147
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001148///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001149
1150void GrContext::drawPath(const GrPaint& paint,
1151 GrPathIter* path,
1152 GrPathFill fill,
1153 const GrPoint* translate) {
1154
bsalomon@google.com27847de2011-02-22 20:59:41 +00001155 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001156 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001157
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001158 if (!IsFillInverted(fill) && // will be relaxed soon
1159 !pr->supportsAA(target, path, fill) &&
1160 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001161
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001162 OffscreenRecord record;
1163 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001164
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001165 // compute bounds as intersection of rt size, clip, and path
1166 GrIRect bound(0, 0,
1167 target->getRenderTarget()->width(),
1168 target->getRenderTarget()->height());
1169 if (target->getClip().hasConservativeBounds()) {
1170 GrIRect clipIBounds;
1171 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
1172 if (!bound.intersectWith(clipIBounds)) {
1173 return;
1174 }
1175 }
1176 GrRect pathBounds;
1177 if (path->getConservativeBounds(&pathBounds)) {
1178 GrIRect pathIBounds;
1179 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1180 pathBounds.roundOut(&pathIBounds);
1181 if (!bound.intersectWith(pathIBounds)) {
1182 return;
1183 }
1184 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001185
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001186 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1187 pr->drawPath(target, 0, path, fill, translate);
1188 this->offscreenAAPass2(target, paint, bound, &record);
1189 return;
1190 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001191 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001192 GrDrawTarget::StageBitfield enabledStages = 0;
1193 if (NULL != paint.getTexture()) {
1194 enabledStages |= 1;
1195 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001196
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001197 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001199
bsalomon@google.comd302f142011-03-03 13:54:13 +00001200void GrContext::drawPath(const GrPaint& paint,
1201 const GrPath& path,
1202 GrPathFill fill,
1203 const GrPoint* translate) {
1204 GrPath::Iter iter(path);
1205 this->drawPath(paint, &iter, fill, translate);
1206}
1207
1208
bsalomon@google.com27847de2011-02-22 20:59:41 +00001209////////////////////////////////////////////////////////////////////////////////
1210
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001211void GrContext::flush(int flagsBitfield) {
1212 if (kDiscard_FlushBit & flagsBitfield) {
1213 fDrawBuffer->reset();
1214 } else {
1215 flushDrawBuffer();
1216 }
1217
1218 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001219 fGpu->forceRenderTargetFlush();
1220 }
1221}
1222
1223void GrContext::flushText() {
1224 if (kText_DrawCategory == fLastDrawCategory) {
1225 flushDrawBuffer();
1226 }
1227}
1228
1229void GrContext::flushDrawBuffer() {
1230#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1231 fDrawBuffer->playback(fGpu);
1232 fDrawBuffer->reset();
1233#endif
1234}
1235
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001236bool GrContext::readTexturePixels(GrTexture* texture,
1237 int left, int top, int width, int height,
1238 GrPixelConfig config, void* buffer) {
1239
1240 // TODO: code read pixels for textures that aren't rendertargets
1241
1242 this->flush();
1243 GrRenderTarget* target = texture->asRenderTarget();
1244 if (NULL != target) {
1245 return fGpu->readPixels(target,
1246 left, top, width, height,
1247 config, buffer);
1248 } else {
1249 return false;
1250 }
1251}
1252
1253bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1254 int left, int top, int width, int height,
1255 GrPixelConfig config, void* buffer) {
1256 uint32_t flushFlags = 0;
1257 if (NULL == target) {
1258 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1259 }
1260
1261 this->flush(flushFlags);
1262 return fGpu->readPixels(target,
1263 left, top, width, height,
1264 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265}
1266
1267void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001268 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269 size_t stride) {
1270
1271 // TODO: when underlying api has a direct way to do this we should use it
1272 // (e.g. glDrawPixels on desktop GL).
1273
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001274 const GrTextureDesc desc = {
1275 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276 };
1277 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1278 if (NULL == texture) {
1279 return;
1280 }
1281
1282 this->flush(true);
1283
1284 GrAutoUnref aur(texture);
1285 GrDrawTarget::AutoStateRestore asr(fGpu);
1286
1287 GrMatrix matrix;
1288 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1289 fGpu->setViewMatrix(matrix);
1290
1291 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1292 fGpu->setAlpha(0xFF);
1293 fGpu->setBlendFunc(kOne_BlendCoeff,
1294 kZero_BlendCoeff);
1295 fGpu->setTexture(0, texture);
1296
1297 GrSamplerState sampler;
1298 sampler.setClampNoFilter();
1299 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1300 sampler.setMatrix(matrix);
1301 fGpu->setSamplerState(0, sampler);
1302
1303 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1304 static const int VCOUNT = 4;
1305
1306 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1307 if (!geo.succeeded()) {
1308 return;
1309 }
1310 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1311 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1312}
1313////////////////////////////////////////////////////////////////////////////////
1314
1315void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1316 target->setTexture(0, paint.getTexture());
1317 target->setSamplerState(0, paint.fSampler);
1318 target->setColor(paint.fColor);
1319
1320 if (paint.fDither) {
1321 target->enableState(GrDrawTarget::kDither_StateBit);
1322 } else {
1323 target->disableState(GrDrawTarget::kDither_StateBit);
1324 }
1325 if (paint.fAntiAlias) {
1326 target->enableState(GrDrawTarget::kAntialias_StateBit);
1327 } else {
1328 target->disableState(GrDrawTarget::kAntialias_StateBit);
1329 }
1330 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1331}
1332
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001333GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334 DrawCategory category) {
1335 if (category != fLastDrawCategory) {
1336 flushDrawBuffer();
1337 fLastDrawCategory = category;
1338 }
1339 SetPaint(paint, fGpu);
1340 GrDrawTarget* target = fGpu;
1341 switch (category) {
1342 case kText_DrawCategory:
1343#if DEFER_TEXT_RENDERING
1344 target = fDrawBuffer;
1345 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1346#else
1347 target = fGpu;
1348#endif
1349 break;
1350 case kUnbuffered_DrawCategory:
1351 target = fGpu;
1352 break;
1353 case kBuffered_DrawCategory:
1354 target = fDrawBuffer;
1355 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1356 break;
1357 }
1358 return target;
1359}
1360
1361////////////////////////////////////////////////////////////////////////////////
1362
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001364 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365 fGpu->setRenderTarget(target);
1366}
1367
1368GrRenderTarget* GrContext::getRenderTarget() {
1369 return fGpu->getRenderTarget();
1370}
1371
1372const GrRenderTarget* GrContext::getRenderTarget() const {
1373 return fGpu->getRenderTarget();
1374}
1375
1376const GrMatrix& GrContext::getMatrix() const {
1377 return fGpu->getViewMatrix();
1378}
1379
1380void GrContext::setMatrix(const GrMatrix& m) {
1381 fGpu->setViewMatrix(m);
1382}
1383
1384void GrContext::concatMatrix(const GrMatrix& m) const {
1385 fGpu->preConcatViewMatrix(m);
1386}
1387
1388static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1389 intptr_t mask = 1 << shift;
1390 if (pred) {
1391 bits |= mask;
1392 } else {
1393 bits &= ~mask;
1394 }
1395 return bits;
1396}
1397
1398void GrContext::resetStats() {
1399 fGpu->resetStats();
1400}
1401
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001402const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403 return fGpu->getStats();
1404}
1405
1406void GrContext::printStats() const {
1407 fGpu->printStats();
1408}
1409
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001410GrContext::GrContext(GrGpu* gpu) :
1411 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1412 gpu->supportsStencilWrapOps()) {
1413
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414 fGpu = gpu;
1415 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001416 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001417
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001418 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1419 fGpu->setClipPathRenderer(fCustomPathRenderer);
1420
bsalomon@google.com27847de2011-02-22 20:59:41 +00001421 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1422 MAX_TEXTURE_CACHE_BYTES);
1423 fFontCache = new GrFontCache(fGpu);
1424
1425 fLastDrawCategory = kUnbuffered_DrawCategory;
1426
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001427 fDrawBuffer = NULL;
1428 fDrawBufferVBAllocPool = NULL;
1429 fDrawBufferIBAllocPool = NULL;
1430
bsalomon@google.com205d4602011-04-25 12:43:45 +00001431 fAAFillRectIndexBuffer = NULL;
1432 fAAStrokeRectIndexBuffer = NULL;
1433
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001434 this->setupDrawBuffer();
1435}
1436
1437void GrContext::setupDrawBuffer() {
1438
1439 GrAssert(NULL == fDrawBuffer);
1440 GrAssert(NULL == fDrawBufferVBAllocPool);
1441 GrAssert(NULL == fDrawBufferIBAllocPool);
1442
bsalomon@google.com27847de2011-02-22 20:59:41 +00001443#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001444 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001445 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001446 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1447 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001448 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001449 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001450 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1452
1453 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1454 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001455#endif
1456
1457#if BATCH_RECT_TO_RECT
1458 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1459#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460}
1461
bsalomon@google.com27847de2011-02-22 20:59:41 +00001462GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1463 GrDrawTarget* target;
1464#if DEFER_TEXT_RENDERING
1465 target = prepareToDraw(paint, kText_DrawCategory);
1466#else
1467 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1468#endif
1469 SetPaint(paint, target);
1470 return target;
1471}
1472
1473const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1474 return fGpu->getQuadIndexBuffer();
1475}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001476
1477GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1478 GrPathIter* path,
1479 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001480 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001481 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1482 return fCustomPathRenderer;
1483 } else {
1484 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1485 return &fDefaultPathRenderer;
1486 }
1487}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001488