blob: 2f34e5a174ac8f4878366d38b01d18c4b8c804de [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
tomhudson@google.com278cbb42011-06-30 19:37:01 +000017#include "GrBufferAllocPool.h"
18#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000019#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000020#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000021#include "GrIndexBuffer.h"
22#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000024#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000025#include "GrResourceCache.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000026#include "GrTextStrike.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000027#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000028
bsalomon@google.com91958362011-06-13 17:58:13 +000029// Using MSAA seems to be slower for some yet unknown reason.
30#define PREFER_MSAA_OFFSCREEN_AA 0
31#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000032
bsalomon@google.com27847de2011-02-22 20:59:41 +000033#define DEFER_TEXT_RENDERING 1
34
35#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
36
37static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
39
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.com05ef5102011-05-02 21:14:59 +000048GrContext* GrContext::Create(GrEngine engine,
49 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000050 GrContext* ctx = NULL;
51 GrGpu* fGpu = GrGpu::Create(engine, context3D);
52 if (NULL != fGpu) {
53 ctx = new GrContext(fGpu);
54 fGpu->unref();
55 }
56 return ctx;
57}
58
59GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000060 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000061}
62
63GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000064 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000065 delete fTextureCache;
66 delete fFontCache;
67 delete fDrawBuffer;
68 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000069 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000070 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000071 GrSafeUnref(fAAFillRectIndexBuffer);
72 GrSafeUnref(fAAStrokeRectIndexBuffer);
73 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com8fe72472011-03-30 21:26:44 +000086 delete fDrawBuffer;
87 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000088
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBufferVBAllocPool;
90 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferIBAllocPool;
93 fDrawBufferIBAllocPool = NULL;
94
bsalomon@google.com205d4602011-04-25 12:43:45 +000095 GrSafeSetNull(fAAFillRectIndexBuffer);
96 GrSafeSetNull(fAAStrokeRectIndexBuffer);
97
bsalomon@google.com8fe72472011-03-30 21:26:44 +000098 fTextureCache->removeAll();
99 fFontCache->freeAll();
100 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101}
102
103void GrContext::resetContext() {
104 fGpu->markContextDirty();
105}
106
107void GrContext::freeGpuResources() {
108 this->flush();
109 fTextureCache->removeAll();
110 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000111}
112
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000113////////////////////////////////////////////////////////////////////////////////
114
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000115int GrContext::PaintStageVertexLayoutBits(
116 const GrPaint& paint,
117 const bool hasTexCoords[GrPaint::kTotalStages]) {
118 int stageMask = paint.getActiveStageMask();
119 int layout = 0;
120 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
121 if ((1 << i) & stageMask) {
122 if (NULL != hasTexCoords && hasTexCoords[i]) {
123 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
124 } else {
125 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
126 }
127 }
128 }
129 return layout;
130}
131
132
133////////////////////////////////////////////////////////////////////////////////
134
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000135enum {
136 kNPOTBit = 0x1,
137 kFilterBit = 0x2,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000138 kScratchBit = 0x4,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000139};
140
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000141GrTexture* GrContext::TextureCacheEntry::texture() const {
142 if (NULL == fEntry) {
143 return NULL;
144 } else {
145 return (GrTexture*) fEntry->resource();
146 }
147}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000148
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000149namespace {
150// returns true if this is a "special" texture because of gpu NPOT limitations
151bool gen_texture_key_values(const GrGpu* gpu,
152 const GrSamplerState& sampler,
153 GrContext::TextureKey clientKey,
154 int width,
155 int height,
156 bool scratch,
157 uint32_t v[4]) {
158 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
159 // we assume we only need 16 bits of width and height
160 // assert that texture creation will fail anyway if this assumption
161 // would cause key collisions.
162 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
163 v[0] = clientKey & 0xffffffffUL;
164 v[1] = (clientKey >> 32) & 0xffffffffUL;
165 v[2] = width | (height << 16);
166
167 v[3] = 0;
168 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000169 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
170
171 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
172 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
173
174 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000175 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000176 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000177 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178 }
179 }
180 }
181
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000182 if (scratch) {
183 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000185
186 return v[3] & kNPOTBit;
187}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000188}
189
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000190GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
191 int width,
192 int height,
193 const GrSamplerState& sampler) {
194 uint32_t v[4];
195 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
196 GrResourceKey resourceKey(v);
197 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000198}
199
200static void stretchImage(void* dst,
201 int dstW,
202 int dstH,
203 void* src,
204 int srcW,
205 int srcH,
206 int bpp) {
207 GrFixed dx = (srcW << 16) / dstW;
208 GrFixed dy = (srcH << 16) / dstH;
209
210 GrFixed y = dy >> 1;
211
212 int dstXLimit = dstW*bpp;
213 for (int j = 0; j < dstH; ++j) {
214 GrFixed x = dx >> 1;
215 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
216 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
217 for (int i = 0; i < dstXLimit; i += bpp) {
218 memcpy((uint8_t*) dstRow + i,
219 (uint8_t*) srcRow + (x>>16)*bpp,
220 bpp);
221 x += dx;
222 }
223 y += dy;
224 }
225}
226
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000227GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000228 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000229 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000230 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000231 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000232
233#if GR_DUMP_TEXTURE_UPLOAD
234 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
235#endif
236
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000237 TextureCacheEntry entry;
238 uint32_t v[4];
239 bool special = gen_texture_key_values(fGpu, sampler, key,
240 desc.fWidth, desc.fHeight, false, v);
241 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000242
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000243 if (special) {
244 TextureCacheEntry clampEntry =
245 findAndLockTexture(key, desc.fWidth, desc.fHeight,
246 GrSamplerState::ClampNoFilter());
247
248 if (NULL == clampEntry.texture()) {
249 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000250 GrSamplerState::ClampNoFilter(),
251 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000252 GrAssert(NULL != clampEntry.texture());
253 if (NULL == clampEntry.texture()) {
254 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000255 }
256 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000257 GrTextureDesc rtDesc = desc;
258 rtDesc.fFlags = rtDesc.fFlags |
259 kRenderTarget_GrTextureFlagBit |
260 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000261 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
262 fGpu->minRenderTargetWidth()));
263 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
264 fGpu->minRenderTargetHeight()));
265
266 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
267
268 if (NULL != texture) {
269 GrDrawTarget::AutoStateRestore asr(fGpu);
270 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000271 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000272 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000273 fGpu->setViewMatrix(GrMatrix::I());
274 fGpu->setAlpha(0xff);
275 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
276 fGpu->disableState(GrDrawTarget::kDither_StateBit |
277 GrDrawTarget::kClip_StateBit |
278 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000279 GrSamplerState::Filter filter;
280 // if filtering is not desired then we want to ensure all
281 // texels in the resampled image are copies of texels from
282 // the original.
283 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
284 filter = GrSamplerState::kNearest_Filter;
285 } else {
286 filter = GrSamplerState::kBilinear_Filter;
287 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000288 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
289 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000290 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000291 fGpu->setSamplerState(0, stretchSampler);
292
293 static const GrVertexLayout layout =
294 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
295 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
296
297 if (arg.succeeded()) {
298 GrPoint* verts = (GrPoint*) arg.vertices();
299 verts[0].setIRectFan(0, 0,
300 texture->width(),
301 texture->height(),
302 2*sizeof(GrPoint));
303 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
304 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
305 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000306 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000307 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000308 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000309 } else {
310 // TODO: Our CPU stretch doesn't filter. But we create separate
311 // stretched textures when the sampler state is either filtered or
312 // not. Either implement filtered stretch blit on CPU or just create
313 // one when FBO case fails.
314
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000315 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000316 // no longer need to clamp at min RT size.
317 rtDesc.fWidth = GrNextPow2(desc.fWidth);
318 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000319 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000320 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000321 rtDesc.fWidth *
322 rtDesc.fHeight);
323 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
324 srcData, desc.fWidth, desc.fHeight, bpp);
325
326 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
327
328 GrTexture* texture = fGpu->createTexture(rtDesc,
329 stretchedPixels.get(),
330 stretchedRowBytes);
331 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000332 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000333 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000334 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000335
336 } else {
337 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
338 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000339 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000340 }
341 }
342 return entry;
343}
344
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000345namespace {
346inline void gen_scratch_tex_key_values(const GrGpu* gpu,
347 const GrTextureDesc& desc,
348 uint32_t v[4]) {
349 // Instead of a client-provided key of the texture contents
350 // we create a key of from the descriptor.
351 GrContext::TextureKey descKey = desc.fAALevel |
352 (desc.fFlags << 8) |
353 ((uint64_t) desc.fFormat << 32);
354 // this code path isn't friendly to tiling with NPOT restricitons
355 // We just pass ClampNoFilter()
356 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
357 desc.fWidth, desc.fHeight, true, v);
358}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000359}
360
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000361GrContext::TextureCacheEntry GrContext::lockScratchTexture(
362 const GrTextureDesc& inDesc,
363 ScratchTexMatch match) {
364
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000365 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000366 if (kExact_ScratchTexMatch != match) {
367 // bin by pow2 with a reasonable min
368 static const int MIN_SIZE = 256;
369 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
370 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
371 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000372
373 uint32_t p0 = desc.fFormat;
374 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
375
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000376 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000377 int origWidth = desc.fWidth;
378 int origHeight = desc.fHeight;
379 bool doubledW = false;
380 bool doubledH = false;
381
382 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000383 uint32_t v[4];
384 gen_scratch_tex_key_values(fGpu, desc, v);
385 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000386 entry = fTextureCache->findAndLock(key);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000387 // if we miss, relax the fit of the flags...
388 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000389 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000390 break;
391 }
392 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
393 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
394 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
395 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
396 } else if (!doubledW) {
397 desc.fFlags = inDesc.fFlags;
398 desc.fWidth *= 2;
399 doubledW = true;
400 } else if (!doubledH) {
401 desc.fFlags = inDesc.fFlags;
402 desc.fWidth = origWidth;
403 desc.fHeight *= 2;
404 doubledH = true;
405 } else {
406 break;
407 }
408
409 } while (true);
410
411 if (NULL == entry) {
412 desc.fFlags = inDesc.fFlags;
413 desc.fWidth = origWidth;
414 desc.fHeight = origHeight;
415 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
416 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000417 uint32_t v[4];
418 gen_scratch_tex_key_values(fGpu, desc, v);
419 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000420 entry = fTextureCache->createAndLock(key, texture);
421 }
422 }
423
424 // If the caller gives us the same desc/sampler twice we don't want
425 // to return the same texture the second time (unless it was previously
426 // released). So we detach the entry from the cache and reattach at release.
427 if (NULL != entry) {
428 fTextureCache->detach(entry);
429 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000430 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000431}
432
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000433void GrContext::unlockTexture(TextureCacheEntry entry) {
434 // If this is a scratch texture we detached it from the cache
435 // while it was locked (to avoid two callers simultaneously getting
436 // the same texture).
437 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
438 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000439 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000440 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000441 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000442}
443
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000444GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000445 void* srcData,
446 size_t rowBytes) {
447 return fGpu->createTexture(desc, srcData, rowBytes);
448}
449
450void GrContext::getTextureCacheLimits(int* maxTextures,
451 size_t* maxTextureBytes) const {
452 fTextureCache->getLimits(maxTextures, maxTextureBytes);
453}
454
455void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
456 fTextureCache->setLimits(maxTextures, maxTextureBytes);
457}
458
bsalomon@google.com91958362011-06-13 17:58:13 +0000459int GrContext::getMaxTextureSize() const {
460 return fGpu->maxTextureSize();
461}
462
463int GrContext::getMaxRenderTargetSize() const {
464 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000465}
466
467///////////////////////////////////////////////////////////////////////////////
468
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000469GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
470 // validate flags here so that GrGpu subclasses don't have to check
471 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
472 0 != desc.fRenderTargetFlags) {
473 return NULL;
474 }
475 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
476 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
477 return NULL;
478 }
479 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
480 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
481 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
482 return NULL;
483 }
484 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000485}
486
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000487GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000488 return fGpu->createRenderTargetFrom3DApiState();
489}
490
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000491///////////////////////////////////////////////////////////////////////////////
492
bsalomon@google.com27847de2011-02-22 20:59:41 +0000493bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
494 int width, int height) {
495 if (!fGpu->supports8BitPalette()) {
496 return false;
497 }
498
499
500 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
501
502 if (!isPow2) {
503 if (!fGpu->npotTextureSupport()) {
504 return false;
505 }
506
507 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
508 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
509 if (tiled && !fGpu->npotTextureTileSupport()) {
510 return false;
511 }
512 }
513 return true;
514}
515
516////////////////////////////////////////////////////////////////////////////////
517
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000518const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
519
bsalomon@google.com27847de2011-02-22 20:59:41 +0000520void GrContext::setClip(const GrClip& clip) {
521 fGpu->setClip(clip);
522 fGpu->enableState(GrDrawTarget::kClip_StateBit);
523}
524
525void GrContext::setClip(const GrIRect& rect) {
526 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000527 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000528 fGpu->setClip(clip);
529}
530
531////////////////////////////////////////////////////////////////////////////////
532
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000533void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000534 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000535 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000536}
537
538void GrContext::drawPaint(const GrPaint& paint) {
539 // set rect to be big enough to fill the space, but not super-huge, so we
540 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000541 GrRect r;
542 r.setLTRB(0, 0,
543 GrIntToScalar(getRenderTarget()->width()),
544 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000545 GrMatrix inverse;
546 if (fGpu->getViewInverse(&inverse)) {
547 inverse.mapRect(&r);
548 } else {
549 GrPrintf("---- fGpu->getViewInverse failed\n");
550 }
551 this->drawRect(paint, r);
552}
553
bsalomon@google.com205d4602011-04-25 12:43:45 +0000554////////////////////////////////////////////////////////////////////////////////
555
bsalomon@google.com91958362011-06-13 17:58:13 +0000556struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000557 enum Downsample {
558 k4x4TwoPass_Downsample,
559 k4x4SinglePass_Downsample,
560 kFSAA_Downsample
561 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000562 int fTileSizeX;
563 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000564 int fTileCountX;
565 int fTileCountY;
566 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000567 GrAutoScratchTexture fOffscreen0;
568 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000569 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000570 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000571};
572
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000573bool GrContext::doOffscreenAA(GrDrawTarget* target,
574 const GrPaint& paint,
575 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000576#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000577 return false;
578#else
579 if (!paint.fAntiAlias) {
580 return false;
581 }
582 if (isLines && fGpu->supportsAALines()) {
583 return false;
584 }
585 if (target->getRenderTarget()->isMultisampled()) {
586 return false;
587 }
588 // we have to be sure that the blend equation is expressible
589 // as simple src / dst coeffecients when the source
590 // is already modulated by the coverage fraction.
591 // We could use dual-source blending to get the correct per-pixel
592 // dst coeffecient for the remaining cases.
593 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
594 kOne_BlendCoeff != paint.fDstBlendCoeff &&
595 kISA_BlendCoeff != paint.fDstBlendCoeff) {
596 return false;
597 }
598 return true;
599#endif
600}
601
bsalomon@google.com91958362011-06-13 17:58:13 +0000602bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000603 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000604 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000605 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000606 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000607
608 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000609
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000610 GrAssert(NULL == record->fOffscreen0.texture());
611 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000612 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000613
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000614 int boundW = boundRect.width();
615 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000616
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000617 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000618
619 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
620 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
621
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000622 if (requireStencil) {
623 desc.fFlags = kRenderTarget_GrTextureFlagBit;
624 } else {
625 desc.fFlags = kRenderTarget_GrTextureFlagBit |
626 kNoStencil_GrTextureFlagBit;
627 }
628
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000629 desc.fFormat = kRGBA_8888_GrPixelConfig;
630
bsalomon@google.com91958362011-06-13 17:58:13 +0000631 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000632 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000633 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 desc.fAALevel = kMed_GrAALevel;
635 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000636 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
637 OffscreenRecord::k4x4SinglePass_Downsample :
638 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000639 record->fScale = OFFSCREEN_SSAA_SCALE;
640 // both downsample paths assume this
641 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000642 desc.fAALevel = kNone_GrAALevel;
643 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000644 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
645 // of simple circles?
646 if (pr) {
647 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
648 }
649
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000650 desc.fWidth *= record->fScale;
651 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000652 record->fOffscreen0.set(this, desc);
653 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000654 return false;
655 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000656 // the approximate lookup might have given us some slop space, might as well
657 // use it when computing the tiles size.
658 // these are scale values, will adjust after considering
659 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000660 record->fTileSizeX = record->fOffscreen0.texture()->width();
661 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000662
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000663 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000664 desc.fWidth /= 2;
665 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000666 record->fOffscreen1.set(this, desc);
667 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000668 return false;
669 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000670 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000671 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000672 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000673 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000674 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000675 record->fTileSizeX /= record->fScale;
676 record->fTileSizeY /= record->fScale;
677
678 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
679 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
680
tomhudson@google.com237a4612011-07-19 15:44:00 +0000681 record->fClip = target->getClip();
682
bsalomon@google.com91958362011-06-13 17:58:13 +0000683 target->saveCurrentDrawState(&record->fSavedState);
684 return true;
685}
686
687void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
688 const GrIRect& boundRect,
689 int tileX, int tileY,
690 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000691
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000692 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000693 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000694
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000695 GrPaint tempPaint;
696 tempPaint.reset();
697 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000699
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000700 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000701 int left = boundRect.fLeft + tileX * record->fTileSizeX;
702 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000703 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000704 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000705 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000706 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000707 target->postConcatViewMatrix(scaleM);
708
bsalomon@google.com91958362011-06-13 17:58:13 +0000709 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000710 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000711 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000712 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000713 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
714 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000715 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000716#if 0
717 // visualize tile boundaries by setting edges of offscreen to white
718 // and interior to tranparent. black.
719 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000720
bsalomon@google.com91958362011-06-13 17:58:13 +0000721 static const int gOffset = 2;
722 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
723 record->fScale * w - gOffset,
724 record->fScale * h - gOffset);
725 target->clear(&clear2, 0x0);
726#else
727 target->clear(&clear, 0x0);
728#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729}
730
bsalomon@google.com91958362011-06-13 17:58:13 +0000731void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000732 const GrPaint& paint,
733 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000734 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000735 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000736 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000737 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000738 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000739 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000740 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
741 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000742 tileRect.fRight = (tileX == record->fTileCountX-1) ?
743 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000744 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000745 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
746 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000747 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000748
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000749 GrSamplerState::Filter filter;
750 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
751 filter = GrSamplerState::k4x4Downsample_Filter;
752 } else {
753 filter = GrSamplerState::kBilinear_Filter;
754 }
755
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000756 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000757 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000758 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000759
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000760 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000761 int scale;
762
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000763 enum {
764 kOffscreenStage = GrPaint::kTotalStages,
765 };
766
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000767 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000768 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000769 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000770 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000771
772 // Do 2x2 downsample from first to second
773 target->setTexture(kOffscreenStage, src);
774 target->setRenderTarget(dst);
775 target->setViewMatrix(GrMatrix::I());
776 sampleM.setScale(scale * GR_Scalar1 / src->width(),
777 scale * GR_Scalar1 / src->height());
778 sampler.setMatrix(sampleM);
779 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000780 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
781 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000782 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
783
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000784 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000785 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000787 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000788 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000789 } else {
790 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
791 record->fDownsample);
792 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000793 }
794
bsalomon@google.com91958362011-06-13 17:58:13 +0000795 // setup for draw back to main RT, we use the original
796 // draw state setup by the caller plus an additional coverage
797 // stage to handle the AA resolve. Also, we use an identity
798 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000799 int stageMask = paint.getActiveStageMask();
800
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000801 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000802 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000803
804 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000805 GrMatrix invVM;
806 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000807 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000808 }
809 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000810 // This is important when tiling, otherwise second tile's
811 // pass 1 view matrix will be incorrect.
812 GrDrawTarget::AutoViewMatrixRestore avmr(target);
813
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000814 target->setViewMatrix(GrMatrix::I());
815
816 target->setTexture(kOffscreenStage, src);
817 sampleM.setScale(scale * GR_Scalar1 / src->width(),
818 scale * GR_Scalar1 / src->height());
819 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000820 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000821 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000822 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000823
reed@google.com20efde72011-05-09 17:00:02 +0000824 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000825 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000826 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000827 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000828}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000829
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000830void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
831 GrPathRenderer* pr,
832 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000833 if (pr) {
834 // Counterpart of scale() in prepareForOffscreenAA()
835 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
836 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000837 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000838}
839
840////////////////////////////////////////////////////////////////////////////////
841
bsalomon@google.com27847de2011-02-22 20:59:41 +0000842/* create a triangle strip that strokes the specified triangle. There are 8
843 unique vertices, but we repreat the last 2 to close up. Alternatively we
844 could use an indices array, and then only send 8 verts, but not sure that
845 would be faster.
846 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000847static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000848 GrScalar width) {
849 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000850 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000851
852 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
853 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
854 verts[2].set(rect.fRight - rad, rect.fTop + rad);
855 verts[3].set(rect.fRight + rad, rect.fTop - rad);
856 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
857 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
858 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
859 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
860 verts[8] = verts[0];
861 verts[9] = verts[1];
862}
863
bsalomon@google.com205d4602011-04-25 12:43:45 +0000864static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000865 // FIXME: This was copied from SkGpuDevice, seems like
866 // we should have already smeared a in caller if that
867 // is what is desired.
868 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000869 unsigned a = GrColorUnpackA(paint.fColor);
870 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000871 } else {
872 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000873 }
874}
875
876static void setInsetFan(GrPoint* pts, size_t stride,
877 const GrRect& r, GrScalar dx, GrScalar dy) {
878 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
879}
880
881static const uint16_t gFillAARectIdx[] = {
882 0, 1, 5, 5, 4, 0,
883 1, 2, 6, 6, 5, 1,
884 2, 3, 7, 7, 6, 2,
885 3, 0, 4, 4, 7, 3,
886 4, 5, 6, 6, 7, 4,
887};
888
889int GrContext::aaFillRectIndexCount() const {
890 return GR_ARRAY_COUNT(gFillAARectIdx);
891}
892
893GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
894 if (NULL == fAAFillRectIndexBuffer) {
895 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
896 false);
897 GrAssert(NULL != fAAFillRectIndexBuffer);
898#if GR_DEBUG
899 bool updated =
900#endif
901 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
902 sizeof(gFillAARectIdx));
903 GR_DEBUGASSERT(updated);
904 }
905 return fAAFillRectIndexBuffer;
906}
907
908static const uint16_t gStrokeAARectIdx[] = {
909 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
910 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
911 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
912 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
913
914 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
915 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
916 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
917 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
918
919 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
920 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
921 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
922 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
923};
924
925int GrContext::aaStrokeRectIndexCount() const {
926 return GR_ARRAY_COUNT(gStrokeAARectIdx);
927}
928
929GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
930 if (NULL == fAAStrokeRectIndexBuffer) {
931 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
932 false);
933 GrAssert(NULL != fAAStrokeRectIndexBuffer);
934#if GR_DEBUG
935 bool updated =
936#endif
937 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
938 sizeof(gStrokeAARectIdx));
939 GR_DEBUGASSERT(updated);
940 }
941 return fAAStrokeRectIndexBuffer;
942}
943
944void GrContext::fillAARect(GrDrawTarget* target,
945 const GrPaint& paint,
946 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000947 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
948 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000949
950 size_t vsize = GrDrawTarget::VertexSize(layout);
951
952 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
953
954 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
955
956 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
957 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
958
959 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
960 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
961
962 verts += sizeof(GrPoint);
963 for (int i = 0; i < 4; ++i) {
964 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
965 }
966
967 GrColor innerColor = getColorForMesh(paint);
968 verts += 4 * vsize;
969 for (int i = 0; i < 4; ++i) {
970 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
971 }
972
973 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
974
975 target->drawIndexed(kTriangles_PrimitiveType, 0,
976 0, 8, this->aaFillRectIndexCount());
977}
978
979void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
980 const GrRect& devRect, const GrVec& devStrokeSize) {
981 const GrScalar& dx = devStrokeSize.fX;
982 const GrScalar& dy = devStrokeSize.fY;
983 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
984 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
985
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000986 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
987 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000988
989 GrScalar spare;
990 {
991 GrScalar w = devRect.width() - dx;
992 GrScalar h = devRect.height() - dy;
993 spare = GrMin(w, h);
994 }
995
996 if (spare <= 0) {
997 GrRect r(devRect);
998 r.inset(-rx, -ry);
999 fillAARect(target, paint, r);
1000 return;
1001 }
1002
1003 size_t vsize = GrDrawTarget::VertexSize(layout);
1004
1005 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
1006
1007 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1008
1009 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1010 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1011 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1012 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1013
1014 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1015 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1016 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1017 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1018
1019 verts += sizeof(GrPoint);
1020 for (int i = 0; i < 4; ++i) {
1021 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1022 }
1023
1024 GrColor innerColor = getColorForMesh(paint);
1025 verts += 4 * vsize;
1026 for (int i = 0; i < 8; ++i) {
1027 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1028 }
1029
1030 verts += 8 * vsize;
1031 for (int i = 0; i < 8; ++i) {
1032 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1033 }
1034
1035 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1036 target->drawIndexed(kTriangles_PrimitiveType,
1037 0, 0, 16, aaStrokeRectIndexCount());
1038}
1039
reed@google.com20efde72011-05-09 17:00:02 +00001040/**
1041 * Returns true if the rects edges are integer-aligned.
1042 */
1043static bool isIRect(const GrRect& r) {
1044 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1045 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1046}
1047
bsalomon@google.com205d4602011-04-25 12:43:45 +00001048static bool apply_aa_to_rect(GrDrawTarget* target,
1049 GrGpu* gpu,
1050 const GrPaint& paint,
1051 const GrRect& rect,
1052 GrScalar width,
1053 const GrMatrix* matrix,
1054 GrMatrix* combinedMatrix,
1055 GrRect* devRect) {
1056 // we use a simple alpha ramp to do aa on axis-aligned rects
1057 // do AA with alpha ramp if the caller requested AA, the rect
1058 // will be axis-aligned,the render target is not
1059 // multisampled, and the rect won't land on integer coords.
1060
1061 if (!paint.fAntiAlias) {
1062 return false;
1063 }
1064
1065 if (target->getRenderTarget()->isMultisampled()) {
1066 return false;
1067 }
1068
1069 if (0 == width && gpu->supportsAALines()) {
1070 return false;
1071 }
1072
1073 if (!target->getViewMatrix().preservesAxisAlignment()) {
1074 return false;
1075 }
1076
1077 if (NULL != matrix &&
1078 !matrix->preservesAxisAlignment()) {
1079 return false;
1080 }
1081
1082 *combinedMatrix = target->getViewMatrix();
1083 if (NULL != matrix) {
1084 combinedMatrix->preConcat(*matrix);
1085 GrAssert(combinedMatrix->preservesAxisAlignment());
1086 }
1087
1088 combinedMatrix->mapRect(devRect, rect);
1089 devRect->sort();
1090
1091 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001092 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001093 } else {
1094 return true;
1095 }
1096}
1097
bsalomon@google.com27847de2011-02-22 20:59:41 +00001098void GrContext::drawRect(const GrPaint& paint,
1099 const GrRect& rect,
1100 GrScalar width,
1101 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001102 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001103
1104 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001105 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001106
bsalomon@google.com205d4602011-04-25 12:43:45 +00001107 GrRect devRect = rect;
1108 GrMatrix combinedMatrix;
1109 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1110 &combinedMatrix, &devRect);
1111
1112 if (doAA) {
1113 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001114 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001115 GrMatrix inv;
1116 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001117 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001118 }
1119 }
1120 target->setViewMatrix(GrMatrix::I());
1121 if (width >= 0) {
1122 GrVec strokeSize;;
1123 if (width > 0) {
1124 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001125 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001126 strokeSize.setAbs(strokeSize);
1127 } else {
1128 strokeSize.set(GR_Scalar1, GR_Scalar1);
1129 }
1130 strokeAARect(target, paint, devRect, strokeSize);
1131 } else {
1132 fillAARect(target, paint, devRect);
1133 }
1134 return;
1135 }
1136
bsalomon@google.com27847de2011-02-22 20:59:41 +00001137 if (width >= 0) {
1138 // TODO: consider making static vertex buffers for these cases.
1139 // Hairline could be done by just adding closing vertex to
1140 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001141 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1142
bsalomon@google.com27847de2011-02-22 20:59:41 +00001143 static const int worstCaseVertCount = 10;
1144 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1145
1146 if (!geo.succeeded()) {
1147 return;
1148 }
1149
1150 GrPrimitiveType primType;
1151 int vertCount;
1152 GrPoint* vertex = geo.positions();
1153
1154 if (width > 0) {
1155 vertCount = 10;
1156 primType = kTriangleStrip_PrimitiveType;
1157 setStrokeRectStrip(vertex, rect, width);
1158 } else {
1159 // hairline
1160 vertCount = 5;
1161 primType = kLineStrip_PrimitiveType;
1162 vertex[0].set(rect.fLeft, rect.fTop);
1163 vertex[1].set(rect.fRight, rect.fTop);
1164 vertex[2].set(rect.fRight, rect.fBottom);
1165 vertex[3].set(rect.fLeft, rect.fBottom);
1166 vertex[4].set(rect.fLeft, rect.fTop);
1167 }
1168
1169 GrDrawTarget::AutoViewMatrixRestore avmr;
1170 if (NULL != matrix) {
1171 avmr.set(target);
1172 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001173 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001174 }
1175
1176 target->drawNonIndexed(primType, 0, vertCount);
1177 } else {
1178 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001179 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1180
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001181 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001182 fGpu->getUnitSquareVertexBuffer());
1183 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1184 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001185 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001186 0, rect.height(), rect.fTop,
1187 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001188
1189 if (NULL != matrix) {
1190 m.postConcat(*matrix);
1191 }
1192
1193 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001194 target->preConcatSamplerMatrices(stageMask, m);
1195
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1197 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001198 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001199 #endif
1200 }
1201}
1202
1203void GrContext::drawRectToRect(const GrPaint& paint,
1204 const GrRect& dstRect,
1205 const GrRect& srcRect,
1206 const GrMatrix* dstMatrix,
1207 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001208 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001209
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001210 // srcRect refers to paint's first texture
1211 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001212 drawRect(paint, dstRect, -1, dstMatrix);
1213 return;
1214 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001215
bsalomon@google.com27847de2011-02-22 20:59:41 +00001216 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1217
1218#if GR_STATIC_RECT_VB
1219 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001220
1221 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001222 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1223
1224 GrMatrix m;
1225
1226 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1227 0, dstRect.height(), dstRect.fTop,
1228 0, 0, GrMatrix::I()[8]);
1229 if (NULL != dstMatrix) {
1230 m.postConcat(*dstMatrix);
1231 }
1232 target->preConcatViewMatrix(m);
1233
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001234 // srcRect refers to first stage
1235 int otherStageMask = paint.getActiveStageMask() &
1236 (~(1 << GrPaint::kFirstTextureStage));
1237 if (otherStageMask) {
1238 target->preConcatSamplerMatrices(otherStageMask, m);
1239 }
1240
bsalomon@google.com27847de2011-02-22 20:59:41 +00001241 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1242 0, srcRect.height(), srcRect.fTop,
1243 0, 0, GrMatrix::I()[8]);
1244 if (NULL != srcMatrix) {
1245 m.postConcat(*srcMatrix);
1246 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001247 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001248
1249 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1250 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1251#else
1252
1253 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001254#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001256#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001257 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1258#endif
1259
1260 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1261 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1262 srcRects[0] = &srcRect;
1263 srcMatrices[0] = srcMatrix;
1264
1265 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1266#endif
1267}
1268
1269void GrContext::drawVertices(const GrPaint& paint,
1270 GrPrimitiveType primitiveType,
1271 int vertexCount,
1272 const GrPoint positions[],
1273 const GrPoint texCoords[],
1274 const GrColor colors[],
1275 const uint16_t indices[],
1276 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001277 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001278
1279 GrDrawTarget::AutoReleaseGeometry geo;
1280
1281 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1282
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001283 bool hasTexCoords[GrPaint::kTotalStages] = {
1284 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1285 0 // remaining stages use positions
1286 };
1287
1288 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001289
1290 if (NULL != colors) {
1291 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001293 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294
1295 if (sizeof(GrPoint) != vertexSize) {
1296 if (!geo.set(target, layout, vertexCount, 0)) {
1297 GrPrintf("Failed to get space for vertices!");
1298 return;
1299 }
1300 int texOffsets[GrDrawTarget::kMaxTexCoords];
1301 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001302 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1303 texOffsets,
1304 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001305 void* curVertex = geo.vertices();
1306
1307 for (int i = 0; i < vertexCount; ++i) {
1308 *((GrPoint*)curVertex) = positions[i];
1309
1310 if (texOffsets[0] > 0) {
1311 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1312 }
1313 if (colorOffset > 0) {
1314 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1315 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001316 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317 }
1318 } else {
1319 target->setVertexSourceToArray(layout, positions, vertexCount);
1320 }
1321
bsalomon@google.com91958362011-06-13 17:58:13 +00001322 // we don't currently apply offscreen AA to this path. Need improved
1323 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001324
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001325 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001326 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001327 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001328 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001329 target->drawNonIndexed(primitiveType, 0, vertexCount);
1330 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331}
1332
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001333///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334
reed@google.com07f3ee12011-05-16 17:21:57 +00001335void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1336 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001337
bsalomon@google.com27847de2011-02-22 20:59:41 +00001338 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comee435122011-07-01 14:57:55 +00001339 GrPathRenderer* pr = this->getPathRenderer(path, fill);
1340 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1341 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001342
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001343 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001344 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001345
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001346 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001347
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001348 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001349 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1350 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001351 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001352 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001353 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001354 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001355 return;
1356 }
1357 }
reed@google.com70c136e2011-06-03 19:51:26 +00001358
reed@google.com07f3ee12011-05-16 17:21:57 +00001359 GrRect pathBounds = path.getBounds();
1360 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001361 if (NULL != translate) {
1362 pathBounds.offset(*translate);
1363 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001364 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001365 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001366 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001367 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001368 return;
1369 }
1370 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001371 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001372 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1373 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001374 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1375 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1376 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001377 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001378 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1379 }
1380 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001381 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001382 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001383 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1384 GrRect rect;
1385 if (clipIBounds.fTop < bound.fTop) {
1386 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1387 clipIBounds.fRight, bound.fTop);
1388 target->drawSimpleRect(rect, NULL, stageMask);
1389 }
1390 if (clipIBounds.fLeft < bound.fLeft) {
1391 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1392 bound.fLeft, bound.fBottom);
1393 target->drawSimpleRect(rect, NULL, stageMask);
1394 }
1395 if (clipIBounds.fRight > bound.fRight) {
1396 rect.setLTRB(bound.fRight, bound.fTop,
1397 clipIBounds.fRight, bound.fBottom);
1398 target->drawSimpleRect(rect, NULL, stageMask);
1399 }
1400 if (clipIBounds.fBottom > bound.fBottom) {
1401 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1402 clipIBounds.fRight, clipIBounds.fBottom);
1403 target->drawSimpleRect(rect, NULL, stageMask);
1404 }
1405 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001406 return;
1407 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001408 }
1409 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001411
bsalomon@google.com27847de2011-02-22 20:59:41 +00001412////////////////////////////////////////////////////////////////////////////////
1413
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001414void GrContext::flush(int flagsBitfield) {
1415 if (kDiscard_FlushBit & flagsBitfield) {
1416 fDrawBuffer->reset();
1417 } else {
1418 flushDrawBuffer();
1419 }
1420
1421 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001422 fGpu->forceRenderTargetFlush();
1423 }
1424}
1425
1426void GrContext::flushText() {
1427 if (kText_DrawCategory == fLastDrawCategory) {
1428 flushDrawBuffer();
1429 }
1430}
1431
1432void GrContext::flushDrawBuffer() {
1433#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001434 if (fDrawBuffer) {
1435 fDrawBuffer->playback(fGpu);
1436 fDrawBuffer->reset();
1437 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001438#endif
1439}
1440
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001441bool GrContext::readTexturePixels(GrTexture* texture,
1442 int left, int top, int width, int height,
1443 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001444 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001445
1446 // TODO: code read pixels for textures that aren't rendertargets
1447
1448 this->flush();
1449 GrRenderTarget* target = texture->asRenderTarget();
1450 if (NULL != target) {
1451 return fGpu->readPixels(target,
1452 left, top, width, height,
1453 config, buffer);
1454 } else {
1455 return false;
1456 }
1457}
1458
1459bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1460 int left, int top, int width, int height,
1461 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001462 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001463 uint32_t flushFlags = 0;
1464 if (NULL == target) {
1465 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1466 }
1467
1468 this->flush(flushFlags);
1469 return fGpu->readPixels(target,
1470 left, top, width, height,
1471 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472}
1473
1474void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001475 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001476 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001477 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001478
1479 // TODO: when underlying api has a direct way to do this we should use it
1480 // (e.g. glDrawPixels on desktop GL).
1481
bsalomon@google.com5c638652011-07-18 19:31:59 +00001482 this->flush(true);
1483
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001484 const GrTextureDesc desc = {
1485 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001486 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001487 GrAutoScratchTexture ast(this, desc);
1488 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001489 if (NULL == texture) {
1490 return;
1491 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001492 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001493
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494 GrDrawTarget::AutoStateRestore asr(fGpu);
1495
1496 GrMatrix matrix;
1497 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1498 fGpu->setViewMatrix(matrix);
1499
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001500 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1502 fGpu->setAlpha(0xFF);
1503 fGpu->setBlendFunc(kOne_BlendCoeff,
1504 kZero_BlendCoeff);
1505 fGpu->setTexture(0, texture);
1506
1507 GrSamplerState sampler;
1508 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001509 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001510 sampler.setMatrix(matrix);
1511 fGpu->setSamplerState(0, sampler);
1512
1513 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1514 static const int VCOUNT = 4;
1515
1516 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1517 if (!geo.succeeded()) {
1518 return;
1519 }
1520 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1521 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1522}
1523////////////////////////////////////////////////////////////////////////////////
1524
1525void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001526
1527 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1528 int s = i + GrPaint::kFirstTextureStage;
1529 target->setTexture(s, paint.getTexture(i));
1530 target->setSamplerState(s, *paint.getTextureSampler(i));
1531 }
1532
1533 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1534
1535 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1536 int s = i + GrPaint::kFirstMaskStage;
1537 target->setTexture(s, paint.getMask(i));
1538 target->setSamplerState(s, *paint.getMaskSampler(i));
1539 }
1540
bsalomon@google.com27847de2011-02-22 20:59:41 +00001541 target->setColor(paint.fColor);
1542
1543 if (paint.fDither) {
1544 target->enableState(GrDrawTarget::kDither_StateBit);
1545 } else {
1546 target->disableState(GrDrawTarget::kDither_StateBit);
1547 }
1548 if (paint.fAntiAlias) {
1549 target->enableState(GrDrawTarget::kAntialias_StateBit);
1550 } else {
1551 target->disableState(GrDrawTarget::kAntialias_StateBit);
1552 }
1553 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001554 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001555}
1556
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001557GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001558 DrawCategory category) {
1559 if (category != fLastDrawCategory) {
1560 flushDrawBuffer();
1561 fLastDrawCategory = category;
1562 }
1563 SetPaint(paint, fGpu);
1564 GrDrawTarget* target = fGpu;
1565 switch (category) {
1566 case kText_DrawCategory:
1567#if DEFER_TEXT_RENDERING
1568 target = fDrawBuffer;
1569 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1570#else
1571 target = fGpu;
1572#endif
1573 break;
1574 case kUnbuffered_DrawCategory:
1575 target = fGpu;
1576 break;
1577 case kBuffered_DrawCategory:
1578 target = fDrawBuffer;
1579 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1580 break;
1581 }
1582 return target;
1583}
1584
1585////////////////////////////////////////////////////////////////////////////////
1586
bsalomon@google.com27847de2011-02-22 20:59:41 +00001587void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001588 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001589 fGpu->setRenderTarget(target);
1590}
1591
1592GrRenderTarget* GrContext::getRenderTarget() {
1593 return fGpu->getRenderTarget();
1594}
1595
1596const GrRenderTarget* GrContext::getRenderTarget() const {
1597 return fGpu->getRenderTarget();
1598}
1599
1600const GrMatrix& GrContext::getMatrix() const {
1601 return fGpu->getViewMatrix();
1602}
1603
1604void GrContext::setMatrix(const GrMatrix& m) {
1605 fGpu->setViewMatrix(m);
1606}
1607
1608void GrContext::concatMatrix(const GrMatrix& m) const {
1609 fGpu->preConcatViewMatrix(m);
1610}
1611
1612static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1613 intptr_t mask = 1 << shift;
1614 if (pred) {
1615 bits |= mask;
1616 } else {
1617 bits &= ~mask;
1618 }
1619 return bits;
1620}
1621
1622void GrContext::resetStats() {
1623 fGpu->resetStats();
1624}
1625
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001626const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001627 return fGpu->getStats();
1628}
1629
1630void GrContext::printStats() const {
1631 fGpu->printStats();
1632}
1633
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001634GrContext::GrContext(GrGpu* gpu) :
1635 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1636 gpu->supportsStencilWrapOps()) {
1637
bsalomon@google.com27847de2011-02-22 20:59:41 +00001638 fGpu = gpu;
1639 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001640 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001641
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001642 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1643 fGpu->setClipPathRenderer(fCustomPathRenderer);
1644
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001645 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1646 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001647 fFontCache = new GrFontCache(fGpu);
1648
1649 fLastDrawCategory = kUnbuffered_DrawCategory;
1650
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001651 fDrawBuffer = NULL;
1652 fDrawBufferVBAllocPool = NULL;
1653 fDrawBufferIBAllocPool = NULL;
1654
bsalomon@google.com205d4602011-04-25 12:43:45 +00001655 fAAFillRectIndexBuffer = NULL;
1656 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001657
1658 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1659 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1660 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1661 }
1662 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001663
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001664 this->setupDrawBuffer();
1665}
1666
1667void GrContext::setupDrawBuffer() {
1668
1669 GrAssert(NULL == fDrawBuffer);
1670 GrAssert(NULL == fDrawBufferVBAllocPool);
1671 GrAssert(NULL == fDrawBufferIBAllocPool);
1672
bsalomon@google.com27847de2011-02-22 20:59:41 +00001673#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001674 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001675 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001676 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1677 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001678 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001679 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001680 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001681 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1682
1683 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1684 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001685#endif
1686
1687#if BATCH_RECT_TO_RECT
1688 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1689#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001690}
1691
bsalomon@google.com27847de2011-02-22 20:59:41 +00001692GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1693 GrDrawTarget* target;
1694#if DEFER_TEXT_RENDERING
1695 target = prepareToDraw(paint, kText_DrawCategory);
1696#else
1697 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1698#endif
1699 SetPaint(paint, target);
1700 return target;
1701}
1702
1703const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1704 return fGpu->getQuadIndexBuffer();
1705}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001706
bsalomon@google.comee435122011-07-01 14:57:55 +00001707GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001708 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001709 if (NULL != fCustomPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +00001710 fCustomPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001711 return fCustomPathRenderer;
1712 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +00001713 GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001714 return &fDefaultPathRenderer;
1715 }
1716}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001717
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001718void GrContext::convolveInX(GrTexture* texture,
1719 const SkRect& rect,
1720 const float* kernel,
1721 int kernelWidth) {
1722 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1723 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1724}
1725
1726void GrContext::convolveInY(GrTexture* texture,
1727 const SkRect& rect,
1728 const float* kernel,
1729 int kernelWidth) {
1730 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1731 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1732}
1733
1734void GrContext::convolve(GrTexture* texture,
1735 const SkRect& rect,
1736 float imageIncrement[2],
1737 const float* kernel,
1738 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001739 GrDrawTarget::AutoStateRestore asr(fGpu);
1740 GrMatrix sampleM;
1741 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1742 GrSamplerState::kClamp_WrapMode,
1743 GrSamplerState::kConvolution_Filter);
1744 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001745 sampleM.setScale(GR_Scalar1 / texture->width(),
1746 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001747 sampler.setMatrix(sampleM);
1748 fGpu->setSamplerState(0, sampler);
1749 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001750 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001751 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001752 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1753}