blob: 773c5738d16fc5ee46eea360173ef6886e46a4ae [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.com8295dc12011-05-02 12:53:34 +00001229 if (!IsFillInverted(fill) && // will be relaxed soon
1230 !pr->supportsAA(target, path, fill) &&
1231 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001232
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001233 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001234
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001235 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001236 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1237 target->getRenderTarget()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001238 if (target->getClip().hasConservativeBounds()) {
1239 GrIRect clipIBounds;
1240 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001241 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001242 return;
1243 }
1244 }
reed@google.com70c136e2011-06-03 19:51:26 +00001245
reed@google.com07f3ee12011-05-16 17:21:57 +00001246 GrRect pathBounds = path.getBounds();
1247 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001248 if (NULL != translate) {
1249 pathBounds.offset(*translate);
1250 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001251 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001252 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001253 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001254 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001255 return;
1256 }
1257 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001258 OffscreenRecord record;
1259 if (this->prepareForOffscreenAA(target, needsStencil, bound, &record)) {
1260 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1261 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1262 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
1263 pr->drawPath(target, 0, path, fill, translate);
1264 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1265 }
1266 }
1267 this->cleanupOffscreenAA(target, &record);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001268 return;
1269 }
reed@google.com70c136e2011-06-03 19:51:26 +00001270 }
1271
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001272 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001273
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001274 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001275}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001276
bsalomon@google.com27847de2011-02-22 20:59:41 +00001277////////////////////////////////////////////////////////////////////////////////
1278
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001279void GrContext::flush(int flagsBitfield) {
1280 if (kDiscard_FlushBit & flagsBitfield) {
1281 fDrawBuffer->reset();
1282 } else {
1283 flushDrawBuffer();
1284 }
1285
1286 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 fGpu->forceRenderTargetFlush();
1288 }
1289}
1290
1291void GrContext::flushText() {
1292 if (kText_DrawCategory == fLastDrawCategory) {
1293 flushDrawBuffer();
1294 }
1295}
1296
1297void GrContext::flushDrawBuffer() {
1298#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001299 if (fDrawBuffer) {
1300 fDrawBuffer->playback(fGpu);
1301 fDrawBuffer->reset();
1302 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001303#endif
1304}
1305
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001306bool GrContext::readTexturePixels(GrTexture* texture,
1307 int left, int top, int width, int height,
1308 GrPixelConfig config, void* buffer) {
1309
1310 // TODO: code read pixels for textures that aren't rendertargets
1311
1312 this->flush();
1313 GrRenderTarget* target = texture->asRenderTarget();
1314 if (NULL != target) {
1315 return fGpu->readPixels(target,
1316 left, top, width, height,
1317 config, buffer);
1318 } else {
1319 return false;
1320 }
1321}
1322
1323bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1324 int left, int top, int width, int height,
1325 GrPixelConfig config, void* buffer) {
1326 uint32_t flushFlags = 0;
1327 if (NULL == target) {
1328 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1329 }
1330
1331 this->flush(flushFlags);
1332 return fGpu->readPixels(target,
1333 left, top, width, height,
1334 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001335}
1336
1337void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001338 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001339 size_t stride) {
1340
1341 // TODO: when underlying api has a direct way to do this we should use it
1342 // (e.g. glDrawPixels on desktop GL).
1343
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001344 const GrTextureDesc desc = {
1345 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001346 };
1347 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1348 if (NULL == texture) {
1349 return;
1350 }
1351
1352 this->flush(true);
1353
1354 GrAutoUnref aur(texture);
1355 GrDrawTarget::AutoStateRestore asr(fGpu);
1356
1357 GrMatrix matrix;
1358 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1359 fGpu->setViewMatrix(matrix);
1360
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001361 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001362 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1363 fGpu->setAlpha(0xFF);
1364 fGpu->setBlendFunc(kOne_BlendCoeff,
1365 kZero_BlendCoeff);
1366 fGpu->setTexture(0, texture);
1367
1368 GrSamplerState sampler;
1369 sampler.setClampNoFilter();
1370 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1371 sampler.setMatrix(matrix);
1372 fGpu->setSamplerState(0, sampler);
1373
1374 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1375 static const int VCOUNT = 4;
1376
1377 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1378 if (!geo.succeeded()) {
1379 return;
1380 }
1381 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1382 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1383}
1384////////////////////////////////////////////////////////////////////////////////
1385
1386void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001387
1388 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1389 int s = i + GrPaint::kFirstTextureStage;
1390 target->setTexture(s, paint.getTexture(i));
1391 target->setSamplerState(s, *paint.getTextureSampler(i));
1392 }
1393
1394 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1395
1396 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1397 int s = i + GrPaint::kFirstMaskStage;
1398 target->setTexture(s, paint.getMask(i));
1399 target->setSamplerState(s, *paint.getMaskSampler(i));
1400 }
1401
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402 target->setColor(paint.fColor);
1403
1404 if (paint.fDither) {
1405 target->enableState(GrDrawTarget::kDither_StateBit);
1406 } else {
1407 target->disableState(GrDrawTarget::kDither_StateBit);
1408 }
1409 if (paint.fAntiAlias) {
1410 target->enableState(GrDrawTarget::kAntialias_StateBit);
1411 } else {
1412 target->disableState(GrDrawTarget::kAntialias_StateBit);
1413 }
1414 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001415 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416}
1417
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001418GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419 DrawCategory category) {
1420 if (category != fLastDrawCategory) {
1421 flushDrawBuffer();
1422 fLastDrawCategory = category;
1423 }
1424 SetPaint(paint, fGpu);
1425 GrDrawTarget* target = fGpu;
1426 switch (category) {
1427 case kText_DrawCategory:
1428#if DEFER_TEXT_RENDERING
1429 target = fDrawBuffer;
1430 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1431#else
1432 target = fGpu;
1433#endif
1434 break;
1435 case kUnbuffered_DrawCategory:
1436 target = fGpu;
1437 break;
1438 case kBuffered_DrawCategory:
1439 target = fDrawBuffer;
1440 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1441 break;
1442 }
1443 return target;
1444}
1445
1446////////////////////////////////////////////////////////////////////////////////
1447
bsalomon@google.com27847de2011-02-22 20:59:41 +00001448void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001449 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001450 fGpu->setRenderTarget(target);
1451}
1452
1453GrRenderTarget* GrContext::getRenderTarget() {
1454 return fGpu->getRenderTarget();
1455}
1456
1457const GrRenderTarget* GrContext::getRenderTarget() const {
1458 return fGpu->getRenderTarget();
1459}
1460
1461const GrMatrix& GrContext::getMatrix() const {
1462 return fGpu->getViewMatrix();
1463}
1464
1465void GrContext::setMatrix(const GrMatrix& m) {
1466 fGpu->setViewMatrix(m);
1467}
1468
1469void GrContext::concatMatrix(const GrMatrix& m) const {
1470 fGpu->preConcatViewMatrix(m);
1471}
1472
1473static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1474 intptr_t mask = 1 << shift;
1475 if (pred) {
1476 bits |= mask;
1477 } else {
1478 bits &= ~mask;
1479 }
1480 return bits;
1481}
1482
1483void GrContext::resetStats() {
1484 fGpu->resetStats();
1485}
1486
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001487const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001488 return fGpu->getStats();
1489}
1490
1491void GrContext::printStats() const {
1492 fGpu->printStats();
1493}
1494
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001495GrContext::GrContext(GrGpu* gpu) :
1496 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1497 gpu->supportsStencilWrapOps()) {
1498
bsalomon@google.com27847de2011-02-22 20:59:41 +00001499 fGpu = gpu;
1500 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001501 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001502
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001503 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1504 fGpu->setClipPathRenderer(fCustomPathRenderer);
1505
bsalomon@google.com27847de2011-02-22 20:59:41 +00001506 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1507 MAX_TEXTURE_CACHE_BYTES);
1508 fFontCache = new GrFontCache(fGpu);
1509
1510 fLastDrawCategory = kUnbuffered_DrawCategory;
1511
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001512 fDrawBuffer = NULL;
1513 fDrawBufferVBAllocPool = NULL;
1514 fDrawBufferIBAllocPool = NULL;
1515
bsalomon@google.com205d4602011-04-25 12:43:45 +00001516 fAAFillRectIndexBuffer = NULL;
1517 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001518
1519 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1520 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1521 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1522 }
1523 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001524
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001525 this->setupDrawBuffer();
1526}
1527
1528void GrContext::setupDrawBuffer() {
1529
1530 GrAssert(NULL == fDrawBuffer);
1531 GrAssert(NULL == fDrawBufferVBAllocPool);
1532 GrAssert(NULL == fDrawBufferIBAllocPool);
1533
bsalomon@google.com27847de2011-02-22 20:59:41 +00001534#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001535 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001536 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001537 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1538 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001539 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001540 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001541 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001542 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1543
1544 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1545 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546#endif
1547
1548#if BATCH_RECT_TO_RECT
1549 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1550#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001551}
1552
bsalomon@google.com27847de2011-02-22 20:59:41 +00001553GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1554 GrDrawTarget* target;
1555#if DEFER_TEXT_RENDERING
1556 target = prepareToDraw(paint, kText_DrawCategory);
1557#else
1558 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1559#endif
1560 SetPaint(paint, target);
1561 return target;
1562}
1563
1564const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1565 return fGpu->getQuadIndexBuffer();
1566}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001567
1568GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001569 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001570 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001571 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001572 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1573 return fCustomPathRenderer;
1574 } else {
1575 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1576 return &fDefaultPathRenderer;
1577 }
1578}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001579