blob: ab5ac06839a88e92fdadcdaf92c1c4f6f54aa5d7 [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
bsalomon@google.com27847de2011-02-22 20:59:41 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000018#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000019#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022#include "GrClipIterator.h"
23#include "GrIndexBuffer.h"
24#include "GrInOrderDrawBuffer.h"
25#include "GrBufferAllocPool.h"
26#include "GrPathRenderer.h"
27
bsalomon@google.com91958362011-06-13 17:58:13 +000028// Using MSAA seems to be slower for some yet unknown reason.
29#define PREFER_MSAA_OFFSCREEN_AA 0
30#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000031
bsalomon@google.com27847de2011-02-22 20:59:41 +000032#define DEFER_TEXT_RENDERING 1
33
34#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
35
36static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
38
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
bsalomon@google.com05ef5102011-05-02 21:14:59 +000047GrContext* GrContext::Create(GrEngine engine,
48 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000049 GrContext* ctx = NULL;
50 GrGpu* fGpu = GrGpu::Create(engine, context3D);
51 if (NULL != fGpu) {
52 ctx = new GrContext(fGpu);
53 fGpu->unref();
54 }
55 return ctx;
56}
57
58GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000059 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000060}
61
62GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000063 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000064 delete fTextureCache;
65 delete fFontCache;
66 delete fDrawBuffer;
67 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000068 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000069 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000070 GrSafeUnref(fAAFillRectIndexBuffer);
71 GrSafeUnref(fAAStrokeRectIndexBuffer);
72 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBuffer;
86 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000087
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBufferVBAllocPool;
89 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferIBAllocPool;
92 fDrawBufferIBAllocPool = NULL;
93
bsalomon@google.com205d4602011-04-25 12:43:45 +000094 GrSafeSetNull(fAAFillRectIndexBuffer);
95 GrSafeSetNull(fAAStrokeRectIndexBuffer);
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 fTextureCache->removeAll();
98 fFontCache->freeAll();
99 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100}
101
102void GrContext::resetContext() {
103 fGpu->markContextDirty();
104}
105
106void GrContext::freeGpuResources() {
107 this->flush();
108 fTextureCache->removeAll();
109 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000110}
111
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000112////////////////////////////////////////////////////////////////////////////////
113
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000114int GrContext::PaintStageVertexLayoutBits(
115 const GrPaint& paint,
116 const bool hasTexCoords[GrPaint::kTotalStages]) {
117 int stageMask = paint.getActiveStageMask();
118 int layout = 0;
119 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
120 if ((1 << i) & stageMask) {
121 if (NULL != hasTexCoords && hasTexCoords[i]) {
122 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
123 } else {
124 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
125 }
126 }
127 }
128 return layout;
129}
130
131
132////////////////////////////////////////////////////////////////////////////////
133
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000134enum {
135 kNPOTBit = 0x1,
136 kFilterBit = 0x2,
137 kKeylessBit = 0x4,
138};
139
140bool GrContext::finalizeTextureKey(GrTextureKey* key,
141 const GrSamplerState& sampler,
142 bool keyless) const {
143 uint32_t bits = 0;
144 uint16_t width = key->width();
145 uint16_t height = key->height();
146
147 if (!fGpu->npotTextureTileSupport()) {
148 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
149
150 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
151 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
152
153 if (tiled && !isPow2) {
154 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000155 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000156 bits |= kFilterBit;
157 }
158 }
159 }
160
161 if (keyless) {
162 bits |= kKeylessBit;
163 }
164 key->finalize(bits);
165 return 0 != bits;
166}
167
bsalomon@google.com27847de2011-02-22 20:59:41 +0000168GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
169 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000170 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000171 return fTextureCache->findAndLock(*key);
172}
173
174static void stretchImage(void* dst,
175 int dstW,
176 int dstH,
177 void* src,
178 int srcW,
179 int srcH,
180 int bpp) {
181 GrFixed dx = (srcW << 16) / dstW;
182 GrFixed dy = (srcH << 16) / dstH;
183
184 GrFixed y = dy >> 1;
185
186 int dstXLimit = dstW*bpp;
187 for (int j = 0; j < dstH; ++j) {
188 GrFixed x = dx >> 1;
189 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
190 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
191 for (int i = 0; i < dstXLimit; i += bpp) {
192 memcpy((uint8_t*) dstRow + i,
193 (uint8_t*) srcRow + (x>>16)*bpp,
194 bpp);
195 x += dx;
196 }
197 y += dy;
198 }
199}
200
201GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
202 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000203 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000204 void* srcData, size_t rowBytes) {
205 GrAssert(key->width() == desc.fWidth);
206 GrAssert(key->height() == desc.fHeight);
207
208#if GR_DUMP_TEXTURE_UPLOAD
209 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
210#endif
211
212 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000213 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000214 if (special) {
215 GrTextureEntry* clampEntry;
216 GrTextureKey clampKey(*key);
217 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
218
219 if (NULL == clampEntry) {
220 clampEntry = createAndLockTexture(&clampKey,
221 GrSamplerState::ClampNoFilter(),
222 desc, srcData, rowBytes);
223 GrAssert(NULL != clampEntry);
224 if (NULL == clampEntry) {
225 return NULL;
226 }
227 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000228 GrTextureDesc rtDesc = desc;
229 rtDesc.fFlags = rtDesc.fFlags |
230 kRenderTarget_GrTextureFlagBit |
231 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000232 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
233 fGpu->minRenderTargetWidth()));
234 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
235 fGpu->minRenderTargetHeight()));
236
237 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
238
239 if (NULL != texture) {
240 GrDrawTarget::AutoStateRestore asr(fGpu);
241 fGpu->setRenderTarget(texture->asRenderTarget());
242 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000243 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000244 fGpu->setViewMatrix(GrMatrix::I());
245 fGpu->setAlpha(0xff);
246 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
247 fGpu->disableState(GrDrawTarget::kDither_StateBit |
248 GrDrawTarget::kClip_StateBit |
249 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000250 GrSamplerState::Filter filter;
251 // if filtering is not desired then we want to ensure all
252 // texels in the resampled image are copies of texels from
253 // the original.
254 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
255 filter = GrSamplerState::kNearest_Filter;
256 } else {
257 filter = GrSamplerState::kBilinear_Filter;
258 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000259 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
260 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000261 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000262 fGpu->setSamplerState(0, stretchSampler);
263
264 static const GrVertexLayout layout =
265 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
266 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
267
268 if (arg.succeeded()) {
269 GrPoint* verts = (GrPoint*) arg.vertices();
270 verts[0].setIRectFan(0, 0,
271 texture->width(),
272 texture->height(),
273 2*sizeof(GrPoint));
274 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
275 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
276 0, 4);
277 entry = fTextureCache->createAndLock(*key, texture);
278 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000279 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000280 } else {
281 // TODO: Our CPU stretch doesn't filter. But we create separate
282 // stretched textures when the sampler state is either filtered or
283 // not. Either implement filtered stretch blit on CPU or just create
284 // one when FBO case fails.
285
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000286 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000287 // no longer need to clamp at min RT size.
288 rtDesc.fWidth = GrNextPow2(desc.fWidth);
289 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000290 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000291 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
292 rtDesc.fWidth *
293 rtDesc.fHeight);
294 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
295 srcData, desc.fWidth, desc.fHeight, bpp);
296
297 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
298
299 GrTexture* texture = fGpu->createTexture(rtDesc,
300 stretchedPixels.get(),
301 stretchedRowBytes);
302 GrAssert(NULL != texture);
303 entry = fTextureCache->createAndLock(*key, texture);
304 }
305 fTextureCache->unlock(clampEntry);
306
307 } else {
308 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
309 if (NULL != texture) {
310 entry = fTextureCache->createAndLock(*key, texture);
311 } else {
312 entry = NULL;
313 }
314 }
315 return entry;
316}
317
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000318GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000319 uint32_t p0 = desc.fFormat;
320 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
321 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000322 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
323
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000324 GrTextureEntry* entry = fTextureCache->findAndLock(key);
325 if (NULL == entry) {
326 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
327 if (NULL != texture) {
328 entry = fTextureCache->createAndLock(key, texture);
329 }
330 }
331 // If the caller gives us the same desc/sampler twice we don't want
332 // to return the same texture the second time (unless it was previously
333 // released). So we detach the entry from the cache and reattach at release.
334 if (NULL != entry) {
335 fTextureCache->detach(entry);
336 }
337 return entry;
338}
339
bsalomon@google.com27847de2011-02-22 20:59:41 +0000340void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000341 if (kKeylessBit & entry->key().getPrivateBits()) {
342 fTextureCache->reattachAndUnlock(entry);
343 } else {
344 fTextureCache->unlock(entry);
345 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000346}
347
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000348GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000349 void* srcData,
350 size_t rowBytes) {
351 return fGpu->createTexture(desc, srcData, rowBytes);
352}
353
354void GrContext::getTextureCacheLimits(int* maxTextures,
355 size_t* maxTextureBytes) const {
356 fTextureCache->getLimits(maxTextures, maxTextureBytes);
357}
358
359void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
360 fTextureCache->setLimits(maxTextures, maxTextureBytes);
361}
362
bsalomon@google.com91958362011-06-13 17:58:13 +0000363int GrContext::getMaxTextureSize() const {
364 return fGpu->maxTextureSize();
365}
366
367int GrContext::getMaxRenderTargetSize() const {
368 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000369}
370
371///////////////////////////////////////////////////////////////////////////////
372
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000373GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
374 // validate flags here so that GrGpu subclasses don't have to check
375 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
376 0 != desc.fRenderTargetFlags) {
377 return NULL;
378 }
379 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
380 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
381 return NULL;
382 }
383 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
384 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
385 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
386 return NULL;
387 }
388 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389}
390
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000391GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000392 return fGpu->createRenderTargetFrom3DApiState();
393}
394
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000395///////////////////////////////////////////////////////////////////////////////
396
bsalomon@google.com27847de2011-02-22 20:59:41 +0000397bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
398 int width, int height) {
399 if (!fGpu->supports8BitPalette()) {
400 return false;
401 }
402
403
404 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
405
406 if (!isPow2) {
407 if (!fGpu->npotTextureSupport()) {
408 return false;
409 }
410
411 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
412 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
413 if (tiled && !fGpu->npotTextureTileSupport()) {
414 return false;
415 }
416 }
417 return true;
418}
419
420////////////////////////////////////////////////////////////////////////////////
421
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000422const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
423
bsalomon@google.com27847de2011-02-22 20:59:41 +0000424void GrContext::setClip(const GrClip& clip) {
425 fGpu->setClip(clip);
426 fGpu->enableState(GrDrawTarget::kClip_StateBit);
427}
428
429void GrContext::setClip(const GrIRect& rect) {
430 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000431 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000432 fGpu->setClip(clip);
433}
434
435////////////////////////////////////////////////////////////////////////////////
436
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000437void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000438 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000439 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000440}
441
442void GrContext::drawPaint(const GrPaint& paint) {
443 // set rect to be big enough to fill the space, but not super-huge, so we
444 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000445 GrRect r;
446 r.setLTRB(0, 0,
447 GrIntToScalar(getRenderTarget()->width()),
448 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000449 GrMatrix inverse;
450 if (fGpu->getViewInverse(&inverse)) {
451 inverse.mapRect(&r);
452 } else {
453 GrPrintf("---- fGpu->getViewInverse failed\n");
454 }
455 this->drawRect(paint, r);
456}
457
bsalomon@google.com205d4602011-04-25 12:43:45 +0000458////////////////////////////////////////////////////////////////////////////////
459
bsalomon@google.com91958362011-06-13 17:58:13 +0000460struct GrContext::OffscreenRecord {
461 OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; }
462 ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); }
463
464 enum Downsample {
465 k4x4TwoPass_Downsample,
466 k4x4SinglePass_Downsample,
467 kFSAA_Downsample
468 } fDownsample;
469 int fTileSize;
470 int fTileCountX;
471 int fTileCountY;
472 int fScale;
473 GrTextureEntry* fEntry0;
474 GrTextureEntry* fEntry1;
475 GrDrawTarget::SavedDrawState fSavedState;
476};
477
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000478bool GrContext::doOffscreenAA(GrDrawTarget* target,
479 const GrPaint& paint,
480 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000481#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000482 return false;
483#else
484 if (!paint.fAntiAlias) {
485 return false;
486 }
487 if (isLines && fGpu->supportsAALines()) {
488 return false;
489 }
490 if (target->getRenderTarget()->isMultisampled()) {
491 return false;
492 }
493 // we have to be sure that the blend equation is expressible
494 // as simple src / dst coeffecients when the source
495 // is already modulated by the coverage fraction.
496 // We could use dual-source blending to get the correct per-pixel
497 // dst coeffecient for the remaining cases.
498 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
499 kOne_BlendCoeff != paint.fDstBlendCoeff &&
500 kISA_BlendCoeff != paint.fDstBlendCoeff) {
501 return false;
502 }
503 return true;
504#endif
505}
506
bsalomon@google.com91958362011-06-13 17:58:13 +0000507bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000508 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000509 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000510 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000511
512 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000513
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000514 GrAssert(NULL == record->fEntry0);
515 GrAssert(NULL == record->fEntry1);
bsalomon@google.com91958362011-06-13 17:58:13 +0000516 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000517
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000518 int boundW = boundRect.width();
519 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000520
521 record->fTileSize = (int)GrNextPow2(GrMax(boundW, boundH));
522 record->fTileSize = GrMax(64, record->fTileSize);
523 record->fTileSize = GrMin(fMaxOffscreenAASize, record->fTileSize);
524
525 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSize);
526 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSize);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000527
528 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000529 if (requireStencil) {
530 desc.fFlags = kRenderTarget_GrTextureFlagBit;
531 } else {
532 desc.fFlags = kRenderTarget_GrTextureFlagBit |
533 kNoStencil_GrTextureFlagBit;
534 }
535
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000536 desc.fFormat = kRGBA_8888_GrPixelConfig;
537
bsalomon@google.com91958362011-06-13 17:58:13 +0000538 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000539 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000540 record->fScale = GR_Scalar1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000541 desc.fAALevel = kMed_GrAALevel;
542 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000543 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
544 OffscreenRecord::k4x4SinglePass_Downsample :
545 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000546 record->fScale = OFFSCREEN_SSAA_SCALE;
547 // both downsample paths assume this
548 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000549 desc.fAALevel = kNone_GrAALevel;
550 }
551
bsalomon@google.com91958362011-06-13 17:58:13 +0000552 desc.fWidth = record->fScale * record->fTileSize;
553 desc.fHeight = record->fScale * record->fTileSize;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000554
555 record->fEntry0 = this->lockKeylessTexture(desc);
556
557 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000558 return false;
559 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000560
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000561 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000562 desc.fWidth /= 2;
563 desc.fHeight /= 2;
564 record->fEntry1 = this->lockKeylessTexture(desc);
565 if (NULL == record->fEntry1) {
566 this->unlockTexture(record->fEntry0);
567 record->fEntry0 = NULL;
568 return false;
569 }
570 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000571 target->saveCurrentDrawState(&record->fSavedState);
572 return true;
573}
574
575void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
576 const GrIRect& boundRect,
577 int tileX, int tileY,
578 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000579
580 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
581 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000582
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000583 GrPaint tempPaint;
584 tempPaint.reset();
585 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000586 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000587
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000588 GrMatrix transM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000589 int left = boundRect.fLeft + tileX * record->fTileSize;
590 int top = boundRect.fTop + tileY * record->fTileSize;
591 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000592 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000593 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000594 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000595 target->postConcatViewMatrix(scaleM);
596
597 // clip gets applied in second pass
598 target->disableState(GrDrawTarget::kClip_StateBit);
599
bsalomon@google.com91958362011-06-13 17:58:13 +0000600 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
601 record->fTileSize;
602 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
603 record->fTileSize;
604 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
605 record->fScale * h);
606#if 0
607 // visualize tile boundaries by setting edges of offscreen to white
608 // and interior to tranparent. black.
609 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000610
bsalomon@google.com91958362011-06-13 17:58:13 +0000611 static const int gOffset = 2;
612 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
613 record->fScale * w - gOffset,
614 record->fScale * h - gOffset);
615 target->clear(&clear2, 0x0);
616#else
617 target->clear(&clear, 0x0);
618#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000619}
620
bsalomon@google.com91958362011-06-13 17:58:13 +0000621void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000622 const GrPaint& paint,
623 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000624 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000625 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000626
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000627 GrAssert(NULL != record->fEntry0);
bsalomon@google.com91958362011-06-13 17:58:13 +0000628
629 GrIRect tileRect;
630 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSize;
631 tileRect.fTop = boundRect.fTop + tileY * record->fTileSize,
632 tileRect.fRight = (tileX == record->fTileCountX-1) ?
633 boundRect.fRight :
634 tileRect.fLeft + record->fTileSize;
635 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
636 boundRect.fBottom :
637 tileRect.fTop + record->fTileSize;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000638
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000639 GrSamplerState::Filter filter;
640 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
641 filter = GrSamplerState::k4x4Downsample_Filter;
642 } else {
643 filter = GrSamplerState::kBilinear_Filter;
644 }
645
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000646 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000647 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000648 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000649
650 GrTexture* src = record->fEntry0->texture();
651 int scale;
652
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000653 enum {
654 kOffscreenStage = GrPaint::kTotalStages,
655 };
656
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000657 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
658 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000659 scale = 2;
660 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
661
662 // Do 2x2 downsample from first to second
663 target->setTexture(kOffscreenStage, src);
664 target->setRenderTarget(dst);
665 target->setViewMatrix(GrMatrix::I());
666 sampleM.setScale(scale * GR_Scalar1 / src->width(),
667 scale * GR_Scalar1 / src->height());
668 sampler.setMatrix(sampleM);
669 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000670 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
671 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000672 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
673
674 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000675 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000676 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000677 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000678 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000679 } else {
680 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
681 record->fDownsample);
682 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000683 }
684
bsalomon@google.com91958362011-06-13 17:58:13 +0000685 // setup for draw back to main RT, we use the original
686 // draw state setup by the caller plus an additional coverage
687 // stage to handle the AA resolve. Also, we use an identity
688 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000689 int stageMask = paint.getActiveStageMask();
690
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000691 target->restoreDrawState(record->fSavedState);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000692
693 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000694 GrMatrix invVM;
695 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000696 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000697 }
698 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000699 // This is important when tiling, otherwise second tile's
700 // pass 1 view matrix will be incorrect.
701 GrDrawTarget::AutoViewMatrixRestore avmr(target);
702
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000703 target->setViewMatrix(GrMatrix::I());
704
705 target->setTexture(kOffscreenStage, src);
706 sampleM.setScale(scale * GR_Scalar1 / src->width(),
707 scale * GR_Scalar1 / src->height());
708 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000709 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000710 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000711 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000712
reed@google.com20efde72011-05-09 17:00:02 +0000713 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000714 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000715 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000716 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000717}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000718
bsalomon@google.com91958362011-06-13 17:58:13 +0000719void GrContext::cleanupOffscreenAA(GrDrawTarget* target, OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000720 this->unlockTexture(record->fEntry0);
721 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000722 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000723 this->unlockTexture(record->fEntry1);
724 record->fEntry1 = NULL;
725 }
726 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000727}
728
729////////////////////////////////////////////////////////////////////////////////
730
bsalomon@google.com27847de2011-02-22 20:59:41 +0000731/* create a triangle strip that strokes the specified triangle. There are 8
732 unique vertices, but we repreat the last 2 to close up. Alternatively we
733 could use an indices array, and then only send 8 verts, but not sure that
734 would be faster.
735 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000736static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000737 GrScalar width) {
738 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000739 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000740
741 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
742 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
743 verts[2].set(rect.fRight - rad, rect.fTop + rad);
744 verts[3].set(rect.fRight + rad, rect.fTop - rad);
745 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
746 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
747 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
748 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
749 verts[8] = verts[0];
750 verts[9] = verts[1];
751}
752
bsalomon@google.com205d4602011-04-25 12:43:45 +0000753static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000754 // FIXME: This was copied from SkGpuDevice, seems like
755 // we should have already smeared a in caller if that
756 // is what is desired.
757 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000758 unsigned a = GrColorUnpackA(paint.fColor);
759 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000760 } else {
761 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000762 }
763}
764
765static void setInsetFan(GrPoint* pts, size_t stride,
766 const GrRect& r, GrScalar dx, GrScalar dy) {
767 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
768}
769
770static const uint16_t gFillAARectIdx[] = {
771 0, 1, 5, 5, 4, 0,
772 1, 2, 6, 6, 5, 1,
773 2, 3, 7, 7, 6, 2,
774 3, 0, 4, 4, 7, 3,
775 4, 5, 6, 6, 7, 4,
776};
777
778int GrContext::aaFillRectIndexCount() const {
779 return GR_ARRAY_COUNT(gFillAARectIdx);
780}
781
782GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
783 if (NULL == fAAFillRectIndexBuffer) {
784 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
785 false);
786 GrAssert(NULL != fAAFillRectIndexBuffer);
787#if GR_DEBUG
788 bool updated =
789#endif
790 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
791 sizeof(gFillAARectIdx));
792 GR_DEBUGASSERT(updated);
793 }
794 return fAAFillRectIndexBuffer;
795}
796
797static const uint16_t gStrokeAARectIdx[] = {
798 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
799 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
800 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
801 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
802
803 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
804 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
805 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
806 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
807
808 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
809 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
810 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
811 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
812};
813
814int GrContext::aaStrokeRectIndexCount() const {
815 return GR_ARRAY_COUNT(gStrokeAARectIdx);
816}
817
818GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
819 if (NULL == fAAStrokeRectIndexBuffer) {
820 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
821 false);
822 GrAssert(NULL != fAAStrokeRectIndexBuffer);
823#if GR_DEBUG
824 bool updated =
825#endif
826 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
827 sizeof(gStrokeAARectIdx));
828 GR_DEBUGASSERT(updated);
829 }
830 return fAAStrokeRectIndexBuffer;
831}
832
833void GrContext::fillAARect(GrDrawTarget* target,
834 const GrPaint& paint,
835 const GrRect& devRect) {
836
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000837 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
838 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000839
840 size_t vsize = GrDrawTarget::VertexSize(layout);
841
842 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
843
844 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
845
846 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
847 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
848
849 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
850 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
851
852 verts += sizeof(GrPoint);
853 for (int i = 0; i < 4; ++i) {
854 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
855 }
856
857 GrColor innerColor = getColorForMesh(paint);
858 verts += 4 * vsize;
859 for (int i = 0; i < 4; ++i) {
860 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
861 }
862
863 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
864
865 target->drawIndexed(kTriangles_PrimitiveType, 0,
866 0, 8, this->aaFillRectIndexCount());
867}
868
869void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
870 const GrRect& devRect, const GrVec& devStrokeSize) {
871 const GrScalar& dx = devStrokeSize.fX;
872 const GrScalar& dy = devStrokeSize.fY;
873 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
874 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
875
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000876 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
877 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000878
879 GrScalar spare;
880 {
881 GrScalar w = devRect.width() - dx;
882 GrScalar h = devRect.height() - dy;
883 spare = GrMin(w, h);
884 }
885
886 if (spare <= 0) {
887 GrRect r(devRect);
888 r.inset(-rx, -ry);
889 fillAARect(target, paint, r);
890 return;
891 }
892
893 size_t vsize = GrDrawTarget::VertexSize(layout);
894
895 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
896
897 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
898
899 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
900 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
901 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
902 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
903
904 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
905 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
906 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
907 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
908
909 verts += sizeof(GrPoint);
910 for (int i = 0; i < 4; ++i) {
911 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
912 }
913
914 GrColor innerColor = getColorForMesh(paint);
915 verts += 4 * vsize;
916 for (int i = 0; i < 8; ++i) {
917 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
918 }
919
920 verts += 8 * vsize;
921 for (int i = 0; i < 8; ++i) {
922 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
923 }
924
925 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
926 target->drawIndexed(kTriangles_PrimitiveType,
927 0, 0, 16, aaStrokeRectIndexCount());
928}
929
reed@google.com20efde72011-05-09 17:00:02 +0000930/**
931 * Returns true if the rects edges are integer-aligned.
932 */
933static bool isIRect(const GrRect& r) {
934 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
935 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
936}
937
bsalomon@google.com205d4602011-04-25 12:43:45 +0000938static bool apply_aa_to_rect(GrDrawTarget* target,
939 GrGpu* gpu,
940 const GrPaint& paint,
941 const GrRect& rect,
942 GrScalar width,
943 const GrMatrix* matrix,
944 GrMatrix* combinedMatrix,
945 GrRect* devRect) {
946 // we use a simple alpha ramp to do aa on axis-aligned rects
947 // do AA with alpha ramp if the caller requested AA, the rect
948 // will be axis-aligned,the render target is not
949 // multisampled, and the rect won't land on integer coords.
950
951 if (!paint.fAntiAlias) {
952 return false;
953 }
954
955 if (target->getRenderTarget()->isMultisampled()) {
956 return false;
957 }
958
959 if (0 == width && gpu->supportsAALines()) {
960 return false;
961 }
962
963 if (!target->getViewMatrix().preservesAxisAlignment()) {
964 return false;
965 }
966
967 if (NULL != matrix &&
968 !matrix->preservesAxisAlignment()) {
969 return false;
970 }
971
972 *combinedMatrix = target->getViewMatrix();
973 if (NULL != matrix) {
974 combinedMatrix->preConcat(*matrix);
975 GrAssert(combinedMatrix->preservesAxisAlignment());
976 }
977
978 combinedMatrix->mapRect(devRect, rect);
979 devRect->sort();
980
981 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000982 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000983 } else {
984 return true;
985 }
986}
987
bsalomon@google.com27847de2011-02-22 20:59:41 +0000988void GrContext::drawRect(const GrPaint& paint,
989 const GrRect& rect,
990 GrScalar width,
991 const GrMatrix* matrix) {
992
bsalomon@google.com27847de2011-02-22 20:59:41 +0000993
994 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000995 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000996
bsalomon@google.com205d4602011-04-25 12:43:45 +0000997 GrRect devRect = rect;
998 GrMatrix combinedMatrix;
999 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1000 &combinedMatrix, &devRect);
1001
1002 if (doAA) {
1003 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001004 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001005 GrMatrix inv;
1006 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001007 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001008 }
1009 }
1010 target->setViewMatrix(GrMatrix::I());
1011 if (width >= 0) {
1012 GrVec strokeSize;;
1013 if (width > 0) {
1014 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001015 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001016 strokeSize.setAbs(strokeSize);
1017 } else {
1018 strokeSize.set(GR_Scalar1, GR_Scalar1);
1019 }
1020 strokeAARect(target, paint, devRect, strokeSize);
1021 } else {
1022 fillAARect(target, paint, devRect);
1023 }
1024 return;
1025 }
1026
bsalomon@google.com27847de2011-02-22 20:59:41 +00001027 if (width >= 0) {
1028 // TODO: consider making static vertex buffers for these cases.
1029 // Hairline could be done by just adding closing vertex to
1030 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001031 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1032
bsalomon@google.com27847de2011-02-22 20:59:41 +00001033 static const int worstCaseVertCount = 10;
1034 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1035
1036 if (!geo.succeeded()) {
1037 return;
1038 }
1039
1040 GrPrimitiveType primType;
1041 int vertCount;
1042 GrPoint* vertex = geo.positions();
1043
1044 if (width > 0) {
1045 vertCount = 10;
1046 primType = kTriangleStrip_PrimitiveType;
1047 setStrokeRectStrip(vertex, rect, width);
1048 } else {
1049 // hairline
1050 vertCount = 5;
1051 primType = kLineStrip_PrimitiveType;
1052 vertex[0].set(rect.fLeft, rect.fTop);
1053 vertex[1].set(rect.fRight, rect.fTop);
1054 vertex[2].set(rect.fRight, rect.fBottom);
1055 vertex[3].set(rect.fLeft, rect.fBottom);
1056 vertex[4].set(rect.fLeft, rect.fTop);
1057 }
1058
1059 GrDrawTarget::AutoViewMatrixRestore avmr;
1060 if (NULL != matrix) {
1061 avmr.set(target);
1062 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001063 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001064 }
1065
1066 target->drawNonIndexed(primType, 0, vertCount);
1067 } else {
1068 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001069 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1070
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001071 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001072 fGpu->getUnitSquareVertexBuffer());
1073 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1074 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001075 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001076 0, rect.height(), rect.fTop,
1077 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001078
1079 if (NULL != matrix) {
1080 m.postConcat(*matrix);
1081 }
1082
1083 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001084 target->preConcatSamplerMatrices(stageMask, m);
1085
bsalomon@google.com27847de2011-02-22 20:59:41 +00001086 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1087 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001088 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001089 #endif
1090 }
1091}
1092
1093void GrContext::drawRectToRect(const GrPaint& paint,
1094 const GrRect& dstRect,
1095 const GrRect& srcRect,
1096 const GrMatrix* dstMatrix,
1097 const GrMatrix* srcMatrix) {
1098
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001099 // srcRect refers to paint's first texture
1100 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001101 drawRect(paint, dstRect, -1, dstMatrix);
1102 return;
1103 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001104
bsalomon@google.com27847de2011-02-22 20:59:41 +00001105 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1106
1107#if GR_STATIC_RECT_VB
1108 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001109
1110 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001111 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1112
1113 GrMatrix m;
1114
1115 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1116 0, dstRect.height(), dstRect.fTop,
1117 0, 0, GrMatrix::I()[8]);
1118 if (NULL != dstMatrix) {
1119 m.postConcat(*dstMatrix);
1120 }
1121 target->preConcatViewMatrix(m);
1122
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001123 // srcRect refers to first stage
1124 int otherStageMask = paint.getActiveStageMask() &
1125 (~(1 << GrPaint::kFirstTextureStage));
1126 if (otherStageMask) {
1127 target->preConcatSamplerMatrices(otherStageMask, m);
1128 }
1129
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1131 0, srcRect.height(), srcRect.fTop,
1132 0, 0, GrMatrix::I()[8]);
1133 if (NULL != srcMatrix) {
1134 m.postConcat(*srcMatrix);
1135 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001136 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001137
1138 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1139 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1140#else
1141
1142 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001143#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001144 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001145#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1147#endif
1148
1149 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1150 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1151 srcRects[0] = &srcRect;
1152 srcMatrices[0] = srcMatrix;
1153
1154 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1155#endif
1156}
1157
1158void GrContext::drawVertices(const GrPaint& paint,
1159 GrPrimitiveType primitiveType,
1160 int vertexCount,
1161 const GrPoint positions[],
1162 const GrPoint texCoords[],
1163 const GrColor colors[],
1164 const uint16_t indices[],
1165 int indexCount) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001166
1167 GrDrawTarget::AutoReleaseGeometry geo;
1168
1169 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1170
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001171 bool hasTexCoords[GrPaint::kTotalStages] = {
1172 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1173 0 // remaining stages use positions
1174 };
1175
1176 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001177
1178 if (NULL != colors) {
1179 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001180 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001181 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001182
1183 if (sizeof(GrPoint) != vertexSize) {
1184 if (!geo.set(target, layout, vertexCount, 0)) {
1185 GrPrintf("Failed to get space for vertices!");
1186 return;
1187 }
1188 int texOffsets[GrDrawTarget::kMaxTexCoords];
1189 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001190 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1191 texOffsets,
1192 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193 void* curVertex = geo.vertices();
1194
1195 for (int i = 0; i < vertexCount; ++i) {
1196 *((GrPoint*)curVertex) = positions[i];
1197
1198 if (texOffsets[0] > 0) {
1199 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1200 }
1201 if (colorOffset > 0) {
1202 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1203 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001204 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001205 }
1206 } else {
1207 target->setVertexSourceToArray(layout, positions, vertexCount);
1208 }
1209
bsalomon@google.com91958362011-06-13 17:58:13 +00001210 // we don't currently apply offscreen AA to this path. Need improved
1211 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001212
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001213 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001214 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001215 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001216 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001217 target->drawNonIndexed(primitiveType, 0, vertexCount);
1218 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001219}
1220
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001221///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001222
reed@google.com07f3ee12011-05-16 17:21:57 +00001223void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1224 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001225
bsalomon@google.com27847de2011-02-22 20:59:41 +00001226 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001227 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001228
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001229 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001230 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001231
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001232 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001233
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001234 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001235 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1236 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001237 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001238 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001239 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001240 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001241 return;
1242 }
1243 }
reed@google.com70c136e2011-06-03 19:51:26 +00001244
reed@google.com07f3ee12011-05-16 17:21:57 +00001245 GrRect pathBounds = path.getBounds();
1246 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001247 if (NULL != translate) {
1248 pathBounds.offset(*translate);
1249 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001250 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001251 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001252 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001253 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001254 return;
1255 }
1256 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001257 OffscreenRecord record;
1258 if (this->prepareForOffscreenAA(target, needsStencil, bound, &record)) {
1259 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1260 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1261 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
1262 pr->drawPath(target, 0, path, fill, translate);
1263 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1264 }
1265 }
1266 this->cleanupOffscreenAA(target, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001267 if (IsFillInverted(fill) && bound != clipIBounds) {
1268 int stageMask = paint.getActiveStageMask();
1269 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1270 GrRect rect;
1271 if (clipIBounds.fTop < bound.fTop) {
1272 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1273 clipIBounds.fRight, bound.fTop);
1274 target->drawSimpleRect(rect, NULL, stageMask);
1275 }
1276 if (clipIBounds.fLeft < bound.fLeft) {
1277 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1278 bound.fLeft, bound.fBottom);
1279 target->drawSimpleRect(rect, NULL, stageMask);
1280 }
1281 if (clipIBounds.fRight > bound.fRight) {
1282 rect.setLTRB(bound.fRight, bound.fTop,
1283 clipIBounds.fRight, bound.fBottom);
1284 target->drawSimpleRect(rect, NULL, stageMask);
1285 }
1286 if (clipIBounds.fBottom > bound.fBottom) {
1287 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1288 clipIBounds.fRight, clipIBounds.fBottom);
1289 target->drawSimpleRect(rect, NULL, stageMask);
1290 }
1291 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001292 return;
1293 }
reed@google.com70c136e2011-06-03 19:51:26 +00001294 }
1295
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001296 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001297
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001298 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001299}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001300
bsalomon@google.com27847de2011-02-22 20:59:41 +00001301////////////////////////////////////////////////////////////////////////////////
1302
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001303void GrContext::flush(int flagsBitfield) {
1304 if (kDiscard_FlushBit & flagsBitfield) {
1305 fDrawBuffer->reset();
1306 } else {
1307 flushDrawBuffer();
1308 }
1309
1310 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001311 fGpu->forceRenderTargetFlush();
1312 }
1313}
1314
1315void GrContext::flushText() {
1316 if (kText_DrawCategory == fLastDrawCategory) {
1317 flushDrawBuffer();
1318 }
1319}
1320
1321void GrContext::flushDrawBuffer() {
1322#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001323 if (fDrawBuffer) {
1324 fDrawBuffer->playback(fGpu);
1325 fDrawBuffer->reset();
1326 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327#endif
1328}
1329
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001330bool GrContext::readTexturePixels(GrTexture* texture,
1331 int left, int top, int width, int height,
1332 GrPixelConfig config, void* buffer) {
1333
1334 // TODO: code read pixels for textures that aren't rendertargets
1335
1336 this->flush();
1337 GrRenderTarget* target = texture->asRenderTarget();
1338 if (NULL != target) {
1339 return fGpu->readPixels(target,
1340 left, top, width, height,
1341 config, buffer);
1342 } else {
1343 return false;
1344 }
1345}
1346
1347bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1348 int left, int top, int width, int height,
1349 GrPixelConfig config, void* buffer) {
1350 uint32_t flushFlags = 0;
1351 if (NULL == target) {
1352 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1353 }
1354
1355 this->flush(flushFlags);
1356 return fGpu->readPixels(target,
1357 left, top, width, height,
1358 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359}
1360
1361void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001362 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363 size_t stride) {
1364
1365 // TODO: when underlying api has a direct way to do this we should use it
1366 // (e.g. glDrawPixels on desktop GL).
1367
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001368 const GrTextureDesc desc = {
1369 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370 };
1371 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1372 if (NULL == texture) {
1373 return;
1374 }
1375
1376 this->flush(true);
1377
1378 GrAutoUnref aur(texture);
1379 GrDrawTarget::AutoStateRestore asr(fGpu);
1380
1381 GrMatrix matrix;
1382 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1383 fGpu->setViewMatrix(matrix);
1384
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001385 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001386 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1387 fGpu->setAlpha(0xFF);
1388 fGpu->setBlendFunc(kOne_BlendCoeff,
1389 kZero_BlendCoeff);
1390 fGpu->setTexture(0, texture);
1391
1392 GrSamplerState sampler;
1393 sampler.setClampNoFilter();
1394 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1395 sampler.setMatrix(matrix);
1396 fGpu->setSamplerState(0, sampler);
1397
1398 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1399 static const int VCOUNT = 4;
1400
1401 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1402 if (!geo.succeeded()) {
1403 return;
1404 }
1405 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1406 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1407}
1408////////////////////////////////////////////////////////////////////////////////
1409
1410void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001411
1412 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1413 int s = i + GrPaint::kFirstTextureStage;
1414 target->setTexture(s, paint.getTexture(i));
1415 target->setSamplerState(s, *paint.getTextureSampler(i));
1416 }
1417
1418 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1419
1420 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1421 int s = i + GrPaint::kFirstMaskStage;
1422 target->setTexture(s, paint.getMask(i));
1423 target->setSamplerState(s, *paint.getMaskSampler(i));
1424 }
1425
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426 target->setColor(paint.fColor);
1427
1428 if (paint.fDither) {
1429 target->enableState(GrDrawTarget::kDither_StateBit);
1430 } else {
1431 target->disableState(GrDrawTarget::kDither_StateBit);
1432 }
1433 if (paint.fAntiAlias) {
1434 target->enableState(GrDrawTarget::kAntialias_StateBit);
1435 } else {
1436 target->disableState(GrDrawTarget::kAntialias_StateBit);
1437 }
1438 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001439 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440}
1441
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001442GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001443 DrawCategory category) {
1444 if (category != fLastDrawCategory) {
1445 flushDrawBuffer();
1446 fLastDrawCategory = category;
1447 }
1448 SetPaint(paint, fGpu);
1449 GrDrawTarget* target = fGpu;
1450 switch (category) {
1451 case kText_DrawCategory:
1452#if DEFER_TEXT_RENDERING
1453 target = fDrawBuffer;
1454 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1455#else
1456 target = fGpu;
1457#endif
1458 break;
1459 case kUnbuffered_DrawCategory:
1460 target = fGpu;
1461 break;
1462 case kBuffered_DrawCategory:
1463 target = fDrawBuffer;
1464 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1465 break;
1466 }
1467 return target;
1468}
1469
1470////////////////////////////////////////////////////////////////////////////////
1471
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001473 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001474 fGpu->setRenderTarget(target);
1475}
1476
1477GrRenderTarget* GrContext::getRenderTarget() {
1478 return fGpu->getRenderTarget();
1479}
1480
1481const GrRenderTarget* GrContext::getRenderTarget() const {
1482 return fGpu->getRenderTarget();
1483}
1484
1485const GrMatrix& GrContext::getMatrix() const {
1486 return fGpu->getViewMatrix();
1487}
1488
1489void GrContext::setMatrix(const GrMatrix& m) {
1490 fGpu->setViewMatrix(m);
1491}
1492
1493void GrContext::concatMatrix(const GrMatrix& m) const {
1494 fGpu->preConcatViewMatrix(m);
1495}
1496
1497static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1498 intptr_t mask = 1 << shift;
1499 if (pred) {
1500 bits |= mask;
1501 } else {
1502 bits &= ~mask;
1503 }
1504 return bits;
1505}
1506
1507void GrContext::resetStats() {
1508 fGpu->resetStats();
1509}
1510
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001511const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001512 return fGpu->getStats();
1513}
1514
1515void GrContext::printStats() const {
1516 fGpu->printStats();
1517}
1518
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001519GrContext::GrContext(GrGpu* gpu) :
1520 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1521 gpu->supportsStencilWrapOps()) {
1522
bsalomon@google.com27847de2011-02-22 20:59:41 +00001523 fGpu = gpu;
1524 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001525 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001526
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001527 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1528 fGpu->setClipPathRenderer(fCustomPathRenderer);
1529
bsalomon@google.com27847de2011-02-22 20:59:41 +00001530 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1531 MAX_TEXTURE_CACHE_BYTES);
1532 fFontCache = new GrFontCache(fGpu);
1533
1534 fLastDrawCategory = kUnbuffered_DrawCategory;
1535
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001536 fDrawBuffer = NULL;
1537 fDrawBufferVBAllocPool = NULL;
1538 fDrawBufferIBAllocPool = NULL;
1539
bsalomon@google.com205d4602011-04-25 12:43:45 +00001540 fAAFillRectIndexBuffer = NULL;
1541 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001542
1543 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1544 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1545 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1546 }
1547 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001548
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001549 this->setupDrawBuffer();
1550}
1551
1552void GrContext::setupDrawBuffer() {
1553
1554 GrAssert(NULL == fDrawBuffer);
1555 GrAssert(NULL == fDrawBufferVBAllocPool);
1556 GrAssert(NULL == fDrawBufferIBAllocPool);
1557
bsalomon@google.com27847de2011-02-22 20:59:41 +00001558#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001559 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001560 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001561 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1562 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001563 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001564 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001565 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001566 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1567
1568 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1569 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001570#endif
1571
1572#if BATCH_RECT_TO_RECT
1573 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1574#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001575}
1576
bsalomon@google.com27847de2011-02-22 20:59:41 +00001577GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1578 GrDrawTarget* target;
1579#if DEFER_TEXT_RENDERING
1580 target = prepareToDraw(paint, kText_DrawCategory);
1581#else
1582 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1583#endif
1584 SetPaint(paint, target);
1585 return target;
1586}
1587
1588const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1589 return fGpu->getQuadIndexBuffer();
1590}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001591
1592GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001593 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001594 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001595 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001596 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1597 return fCustomPathRenderer;
1598 } else {
1599 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1600 return &fDefaultPathRenderer;
1601 }
1602}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001603