blob: ee38d725bcdb2b4b9728be1519a445929b61fbc9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000021#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023
bsalomon@google.com91958362011-06-13 17:58:13 +000024// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000027
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000032static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
33static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000034
35static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
36static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
37
38// We are currently only batching Text and drawRectToRect, both
39// of which use the quad index buffer.
40static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
41static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
42
bsalomon@google.com05ef5102011-05-02 21:14:59 +000043GrContext* GrContext::Create(GrEngine engine,
44 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000045 GrContext* ctx = NULL;
46 GrGpu* fGpu = GrGpu::Create(engine, context3D);
47 if (NULL != fGpu) {
48 ctx = new GrContext(fGpu);
49 fGpu->unref();
50 }
51 return ctx;
52}
53
54GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000055 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000056}
57
58GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000059 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000060 delete fTextureCache;
61 delete fFontCache;
62 delete fDrawBuffer;
63 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000064 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000065
bsalomon@google.com205d4602011-04-25 12:43:45 +000066 GrSafeUnref(fAAFillRectIndexBuffer);
67 GrSafeUnref(fAAStrokeRectIndexBuffer);
68 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000069 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000070}
71
bsalomon@google.com8fe72472011-03-30 21:26:44 +000072void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000073 contextDestroyed();
74 this->setupDrawBuffer();
75}
76
77void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000078 // abandon first to so destructors
79 // don't try to free the resources in the API.
80 fGpu->abandonResources();
81
bsalomon@google.com30085192011-08-19 15:42:31 +000082 // a path renderer may be holding onto resources that
83 // are now unusable
84 GrSafeSetNull(fPathRendererChain);
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.com30085192011-08-19 15:42:31 +0000111 // a path renderer may be holding onto resources
112 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000113}
114
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000115////////////////////////////////////////////////////////////////////////////////
116
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000117int GrContext::PaintStageVertexLayoutBits(
118 const GrPaint& paint,
119 const bool hasTexCoords[GrPaint::kTotalStages]) {
120 int stageMask = paint.getActiveStageMask();
121 int layout = 0;
122 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
123 if ((1 << i) & stageMask) {
124 if (NULL != hasTexCoords && hasTexCoords[i]) {
125 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
126 } else {
127 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
128 }
129 }
130 }
131 return layout;
132}
133
134
135////////////////////////////////////////////////////////////////////////////////
136
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000137enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000138 // flags for textures
139 kNPOTBit = 0x1,
140 kFilterBit = 0x2,
141 kScratchBit = 0x4,
142
143 // resource type
144 kTextureBit = 0x8,
145 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000146};
147
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000148GrTexture* GrContext::TextureCacheEntry::texture() const {
149 if (NULL == fEntry) {
150 return NULL;
151 } else {
152 return (GrTexture*) fEntry->resource();
153 }
154}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000155
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000156namespace {
157// returns true if this is a "special" texture because of gpu NPOT limitations
158bool gen_texture_key_values(const GrGpu* gpu,
159 const GrSamplerState& sampler,
160 GrContext::TextureKey clientKey,
161 int width,
162 int height,
163 bool scratch,
164 uint32_t v[4]) {
165 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
166 // we assume we only need 16 bits of width and height
167 // assert that texture creation will fail anyway if this assumption
168 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000169 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000170 v[0] = clientKey & 0xffffffffUL;
171 v[1] = (clientKey >> 32) & 0xffffffffUL;
172 v[2] = width | (height << 16);
173
174 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000175 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000176 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
177
178 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
179 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
180
181 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000182 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000183 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000184 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000185 }
186 }
187 }
188
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000189 if (scratch) {
190 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000191 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000192
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000193 v[3] |= kTextureBit;
194
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000195 return v[3] & kNPOTBit;
196}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197
198// we should never have more than one stencil buffer with same combo of
199// (width,height,samplecount)
200void gen_stencil_key_values(int width, int height,
201 int sampleCnt, uint32_t v[4]) {
202 v[0] = width;
203 v[1] = height;
204 v[2] = sampleCnt;
205 v[3] = kStencilBufferBit;
206}
207
208void gen_stencil_key_values(const GrStencilBuffer* sb,
209 uint32_t v[4]) {
210 gen_stencil_key_values(sb->width(), sb->height(),
211 sb->numSamples(), v);
212}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000213}
214
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000215GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
216 int width,
217 int height,
218 const GrSamplerState& sampler) {
219 uint32_t v[4];
220 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
221 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000222 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
223 GrResourceCache::kNested_LockType));
224}
225
226GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
227 uint32_t v[4];
228 gen_stencil_key_values(sb, v);
229 GrResourceKey resourceKey(v);
230 return fTextureCache->createAndLock(resourceKey, sb);
231}
232
233GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
234 int sampleCnt) {
235 uint32_t v[4];
236 gen_stencil_key_values(width, height, sampleCnt, v);
237 GrResourceKey resourceKey(v);
238 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
239 GrResourceCache::kSingle_LockType);
240 if (NULL != entry) {
241 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
242 return sb;
243 } else {
244 return NULL;
245 }
246}
247
248void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
249 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000250}
251
252static void stretchImage(void* dst,
253 int dstW,
254 int dstH,
255 void* src,
256 int srcW,
257 int srcH,
258 int bpp) {
259 GrFixed dx = (srcW << 16) / dstW;
260 GrFixed dy = (srcH << 16) / dstH;
261
262 GrFixed y = dy >> 1;
263
264 int dstXLimit = dstW*bpp;
265 for (int j = 0; j < dstH; ++j) {
266 GrFixed x = dx >> 1;
267 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
268 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
269 for (int i = 0; i < dstXLimit; i += bpp) {
270 memcpy((uint8_t*) dstRow + i,
271 (uint8_t*) srcRow + (x>>16)*bpp,
272 bpp);
273 x += dx;
274 }
275 y += dy;
276 }
277}
278
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000279GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000280 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000281 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000282 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000283 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000284
285#if GR_DUMP_TEXTURE_UPLOAD
286 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
287#endif
288
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000289 TextureCacheEntry entry;
290 uint32_t v[4];
291 bool special = gen_texture_key_values(fGpu, sampler, key,
292 desc.fWidth, desc.fHeight, false, v);
293 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000294
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000295 if (special) {
296 TextureCacheEntry clampEntry =
297 findAndLockTexture(key, desc.fWidth, desc.fHeight,
298 GrSamplerState::ClampNoFilter());
299
300 if (NULL == clampEntry.texture()) {
301 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000302 GrSamplerState::ClampNoFilter(),
303 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000304 GrAssert(NULL != clampEntry.texture());
305 if (NULL == clampEntry.texture()) {
306 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000307 }
308 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000309 GrTextureDesc rtDesc = desc;
310 rtDesc.fFlags = rtDesc.fFlags |
311 kRenderTarget_GrTextureFlagBit |
312 kNoStencil_GrTextureFlagBit;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000313 rtDesc.fWidth =
314 GrNextPow2(GrMax<int>(desc.fWidth,
315 fGpu->getCaps().fMinRenderTargetWidth));
316 rtDesc.fHeight =
317 GrNextPow2(GrMax<int>(desc.fHeight,
318 fGpu->getCaps().fMinRenderTargetHeight));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000319
320 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
321
322 if (NULL != texture) {
323 GrDrawTarget::AutoStateRestore asr(fGpu);
324 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000325 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000326 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000327 fGpu->setViewMatrix(GrMatrix::I());
328 fGpu->setAlpha(0xff);
329 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
330 fGpu->disableState(GrDrawTarget::kDither_StateBit |
331 GrDrawTarget::kClip_StateBit |
332 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000333 GrSamplerState::Filter filter;
334 // if filtering is not desired then we want to ensure all
335 // texels in the resampled image are copies of texels from
336 // the original.
337 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
338 filter = GrSamplerState::kNearest_Filter;
339 } else {
340 filter = GrSamplerState::kBilinear_Filter;
341 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000342 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
343 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000344 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000345 fGpu->setSamplerState(0, stretchSampler);
346
347 static const GrVertexLayout layout =
348 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
349 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
350
351 if (arg.succeeded()) {
352 GrPoint* verts = (GrPoint*) arg.vertices();
353 verts[0].setIRectFan(0, 0,
354 texture->width(),
355 texture->height(),
356 2*sizeof(GrPoint));
357 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
358 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
359 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000360 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000361 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000362 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000363 } else {
364 // TODO: Our CPU stretch doesn't filter. But we create separate
365 // stretched textures when the sampler state is either filtered or
366 // not. Either implement filtered stretch blit on CPU or just create
367 // one when FBO case fails.
368
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000369 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000370 // no longer need to clamp at min RT size.
371 rtDesc.fWidth = GrNextPow2(desc.fWidth);
372 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000373 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000374 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000375 rtDesc.fWidth *
376 rtDesc.fHeight);
377 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
378 srcData, desc.fWidth, desc.fHeight, bpp);
379
380 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
381
382 GrTexture* texture = fGpu->createTexture(rtDesc,
383 stretchedPixels.get(),
384 stretchedRowBytes);
385 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000386 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000387 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000388 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389
390 } else {
391 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
392 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000393 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000394 }
395 }
396 return entry;
397}
398
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000399namespace {
400inline void gen_scratch_tex_key_values(const GrGpu* gpu,
401 const GrTextureDesc& desc,
402 uint32_t v[4]) {
403 // Instead of a client-provided key of the texture contents
404 // we create a key of from the descriptor.
405 GrContext::TextureKey descKey = desc.fAALevel |
406 (desc.fFlags << 8) |
407 ((uint64_t) desc.fFormat << 32);
408 // this code path isn't friendly to tiling with NPOT restricitons
409 // We just pass ClampNoFilter()
410 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
411 desc.fWidth, desc.fHeight, true, v);
412}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000413}
414
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000415GrContext::TextureCacheEntry GrContext::lockScratchTexture(
416 const GrTextureDesc& inDesc,
417 ScratchTexMatch match) {
418
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000419 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000420 if (kExact_ScratchTexMatch != match) {
421 // bin by pow2 with a reasonable min
422 static const int MIN_SIZE = 256;
423 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
424 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
425 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000426
427 uint32_t p0 = desc.fFormat;
428 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
429
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000430 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000431 int origWidth = desc.fWidth;
432 int origHeight = desc.fHeight;
433 bool doubledW = false;
434 bool doubledH = false;
435
436 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000437 uint32_t v[4];
438 gen_scratch_tex_key_values(fGpu, desc, v);
439 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000440 entry = fTextureCache->findAndLock(key,
441 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 // if we miss, relax the fit of the flags...
443 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000444 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000445 break;
446 }
447 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
448 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
449 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
450 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
451 } else if (!doubledW) {
452 desc.fFlags = inDesc.fFlags;
453 desc.fWidth *= 2;
454 doubledW = true;
455 } else if (!doubledH) {
456 desc.fFlags = inDesc.fFlags;
457 desc.fWidth = origWidth;
458 desc.fHeight *= 2;
459 doubledH = true;
460 } else {
461 break;
462 }
463
464 } while (true);
465
466 if (NULL == entry) {
467 desc.fFlags = inDesc.fFlags;
468 desc.fWidth = origWidth;
469 desc.fHeight = origHeight;
470 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
471 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000472 uint32_t v[4];
473 gen_scratch_tex_key_values(fGpu, desc, v);
474 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000475 entry = fTextureCache->createAndLock(key, texture);
476 }
477 }
478
479 // If the caller gives us the same desc/sampler twice we don't want
480 // to return the same texture the second time (unless it was previously
481 // released). So we detach the entry from the cache and reattach at release.
482 if (NULL != entry) {
483 fTextureCache->detach(entry);
484 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000486}
487
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000488void GrContext::unlockTexture(TextureCacheEntry entry) {
489 // If this is a scratch texture we detached it from the cache
490 // while it was locked (to avoid two callers simultaneously getting
491 // the same texture).
492 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
493 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000494 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000495 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000496 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000497}
498
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000499GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000500 void* srcData,
501 size_t rowBytes) {
502 return fGpu->createTexture(desc, srcData, rowBytes);
503}
504
505void GrContext::getTextureCacheLimits(int* maxTextures,
506 size_t* maxTextureBytes) const {
507 fTextureCache->getLimits(maxTextures, maxTextureBytes);
508}
509
510void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
511 fTextureCache->setLimits(maxTextures, maxTextureBytes);
512}
513
bsalomon@google.com91958362011-06-13 17:58:13 +0000514int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000515 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000516}
517
518int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000519 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000520}
521
522///////////////////////////////////////////////////////////////////////////////
523
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000524GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
525 // validate flags here so that GrGpu subclasses don't have to check
526 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
527 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000528 return NULL;
529 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000530 if (desc.fSampleCnt &&
531 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000532 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000533 }
534 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
535 desc.fSampleCnt &&
536 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
537 return NULL;
538 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000539 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000540}
541
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000542///////////////////////////////////////////////////////////////////////////////
543
bsalomon@google.com27847de2011-02-22 20:59:41 +0000544bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000545 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000546 const GrDrawTarget::Caps& caps = fGpu->getCaps();
547 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000548 return false;
549 }
550
bsalomon@google.com27847de2011-02-22 20:59:41 +0000551 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
552
553 if (!isPow2) {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000554 if (!caps.fNPOTTextureSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000555 return false;
556 }
557
558 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
559 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000560 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000561 return false;
562 }
563 }
564 return true;
565}
566
567////////////////////////////////////////////////////////////////////////////////
568
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000569const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
570
bsalomon@google.com27847de2011-02-22 20:59:41 +0000571void GrContext::setClip(const GrClip& clip) {
572 fGpu->setClip(clip);
573 fGpu->enableState(GrDrawTarget::kClip_StateBit);
574}
575
576void GrContext::setClip(const GrIRect& rect) {
577 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000578 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000579 fGpu->setClip(clip);
580}
581
582////////////////////////////////////////////////////////////////////////////////
583
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000584void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000585 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000586 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000587}
588
589void GrContext::drawPaint(const GrPaint& paint) {
590 // set rect to be big enough to fill the space, but not super-huge, so we
591 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000592 GrRect r;
593 r.setLTRB(0, 0,
594 GrIntToScalar(getRenderTarget()->width()),
595 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000596 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000597 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000598 SkTLazy<GrPaint> tmpPaint;
599 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000600 // We attempt to map r by the inverse matrix and draw that. mapRect will
601 // map the four corners and bound them with a new rect. This will not
602 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000603 if (!this->getMatrix().hasPerspective()) {
604 if (!fGpu->getViewInverse(&inverse)) {
605 GrPrintf("Could not invert matrix");
606 return;
607 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000608 inverse.mapRect(&r);
609 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000610 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
611 if (!fGpu->getViewInverse(&inverse)) {
612 GrPrintf("Could not invert matrix");
613 return;
614 }
615 tmpPaint.set(paint);
616 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
617 p = tmpPaint.get();
618 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000619 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000620 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000621 // by definition this fills the entire clip, no need for AA
622 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000623 if (!tmpPaint.isValid()) {
624 tmpPaint.set(paint);
625 p = tmpPaint.get();
626 }
627 GrAssert(p == tmpPaint.get());
628 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000629 }
630 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000631}
632
bsalomon@google.com205d4602011-04-25 12:43:45 +0000633////////////////////////////////////////////////////////////////////////////////
634
bsalomon@google.com91958362011-06-13 17:58:13 +0000635struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000636 enum Downsample {
637 k4x4TwoPass_Downsample,
638 k4x4SinglePass_Downsample,
639 kFSAA_Downsample
640 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000641 int fTileSizeX;
642 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000643 int fTileCountX;
644 int fTileCountY;
645 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000646 GrAutoScratchTexture fOffscreen0;
647 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000648 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000649 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000650};
651
bsalomon@google.com471d4712011-08-23 15:45:25 +0000652bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000653 const GrPaint& paint,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000654 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000655#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000656 return false;
657#else
658 if (!paint.fAntiAlias) {
659 return false;
660 }
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000661 // Line primitves are always rasterized as 1 pixel wide.
662 // Super-sampling would make them too thin but MSAA would be OK.
663 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000664 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000665 return false;
666 }
667 if (target->getRenderTarget()->isMultisampled()) {
668 return false;
669 }
670 // we have to be sure that the blend equation is expressible
671 // as simple src / dst coeffecients when the source
672 // is already modulated by the coverage fraction.
673 // We could use dual-source blending to get the correct per-pixel
674 // dst coeffecient for the remaining cases.
675 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
676 kOne_BlendCoeff != paint.fDstBlendCoeff &&
677 kISA_BlendCoeff != paint.fDstBlendCoeff) {
678 return false;
679 }
680 return true;
681#endif
682}
683
bsalomon@google.com91958362011-06-13 17:58:13 +0000684bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000685 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000686 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000687 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000688 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000689
690 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000691
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000692 GrAssert(NULL == record->fOffscreen0.texture());
693 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000694 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000695
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000696 int boundW = boundRect.width();
697 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000698
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000699 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000700
701 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
702 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
703
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000704 if (requireStencil) {
705 desc.fFlags = kRenderTarget_GrTextureFlagBit;
706 } else {
707 desc.fFlags = kRenderTarget_GrTextureFlagBit |
708 kNoStencil_GrTextureFlagBit;
709 }
710
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000711 desc.fFormat = kRGBA_8888_GrPixelConfig;
712
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000713 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000714 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000715 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000716 desc.fAALevel = kMed_GrAALevel;
717 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000718 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000719 OffscreenRecord::k4x4SinglePass_Downsample :
720 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000721 record->fScale = OFFSCREEN_SSAA_SCALE;
722 // both downsample paths assume this
723 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000724 desc.fAALevel = kNone_GrAALevel;
725 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000726
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000727 desc.fWidth *= record->fScale;
728 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000729 record->fOffscreen0.set(this, desc);
730 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000731 return false;
732 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000733 // the approximate lookup might have given us some slop space, might as well
734 // use it when computing the tiles size.
735 // these are scale values, will adjust after considering
736 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000737 record->fTileSizeX = record->fOffscreen0.texture()->width();
738 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000739
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000740 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000741 desc.fWidth /= 2;
742 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000743 record->fOffscreen1.set(this, desc);
744 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000745 return false;
746 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000747 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000748 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000749 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000750 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000752 record->fTileSizeX /= record->fScale;
753 record->fTileSizeY /= record->fScale;
754
755 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
756 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
757
tomhudson@google.com237a4612011-07-19 15:44:00 +0000758 record->fClip = target->getClip();
759
bsalomon@google.com91958362011-06-13 17:58:13 +0000760 target->saveCurrentDrawState(&record->fSavedState);
761 return true;
762}
763
764void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
765 const GrIRect& boundRect,
766 int tileX, int tileY,
767 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000769 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000770 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000771
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000772 GrPaint tempPaint;
773 tempPaint.reset();
774 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000775 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000776
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000777 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000778 int left = boundRect.fLeft + tileX * record->fTileSizeX;
779 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000780 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000781 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000782 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000783 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000784 target->postConcatViewMatrix(scaleM);
785
bsalomon@google.com91958362011-06-13 17:58:13 +0000786 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000787 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000788 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000789 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000790 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
791 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000792 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000793#if 0
794 // visualize tile boundaries by setting edges of offscreen to white
795 // and interior to tranparent. black.
796 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000797
bsalomon@google.com91958362011-06-13 17:58:13 +0000798 static const int gOffset = 2;
799 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
800 record->fScale * w - gOffset,
801 record->fScale * h - gOffset);
802 target->clear(&clear2, 0x0);
803#else
804 target->clear(&clear, 0x0);
805#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806}
807
bsalomon@google.com91958362011-06-13 17:58:13 +0000808void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000809 const GrPaint& paint,
810 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000811 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000812 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000813 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000814 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000815 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000816 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000817 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
818 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000819 tileRect.fRight = (tileX == record->fTileCountX-1) ?
820 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000821 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000822 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
823 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000824 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000825
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000826 GrSamplerState::Filter filter;
827 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
828 filter = GrSamplerState::k4x4Downsample_Filter;
829 } else {
830 filter = GrSamplerState::kBilinear_Filter;
831 }
832
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000833 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000834 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000835 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000836
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000837 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000838 int scale;
839
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000840 enum {
841 kOffscreenStage = GrPaint::kTotalStages,
842 };
843
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000844 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000845 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000846 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000847 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000848
849 // Do 2x2 downsample from first to second
850 target->setTexture(kOffscreenStage, src);
851 target->setRenderTarget(dst);
852 target->setViewMatrix(GrMatrix::I());
853 sampleM.setScale(scale * GR_Scalar1 / src->width(),
854 scale * GR_Scalar1 / src->height());
855 sampler.setMatrix(sampleM);
856 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000857 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
858 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000859 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
860
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000861 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000862 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000863 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000864 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000866 } else {
867 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
868 record->fDownsample);
869 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000870 }
871
bsalomon@google.com91958362011-06-13 17:58:13 +0000872 // setup for draw back to main RT, we use the original
873 // draw state setup by the caller plus an additional coverage
874 // stage to handle the AA resolve. Also, we use an identity
875 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000876 int stageMask = paint.getActiveStageMask();
877
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000878 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000879 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000880
881 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000882 GrMatrix invVM;
883 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000884 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000885 }
886 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000887 // This is important when tiling, otherwise second tile's
888 // pass 1 view matrix will be incorrect.
889 GrDrawTarget::AutoViewMatrixRestore avmr(target);
890
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000891 target->setViewMatrix(GrMatrix::I());
892
893 target->setTexture(kOffscreenStage, src);
894 sampleM.setScale(scale * GR_Scalar1 / src->width(),
895 scale * GR_Scalar1 / src->height());
896 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000897 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000898 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000899 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000900
reed@google.com20efde72011-05-09 17:00:02 +0000901 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000902 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000903 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000904 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000905}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000906
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000907void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
908 GrPathRenderer* pr,
909 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000910 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000911}
912
913////////////////////////////////////////////////////////////////////////////////
914
bsalomon@google.com27847de2011-02-22 20:59:41 +0000915/* create a triangle strip that strokes the specified triangle. There are 8
916 unique vertices, but we repreat the last 2 to close up. Alternatively we
917 could use an indices array, and then only send 8 verts, but not sure that
918 would be faster.
919 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000920static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000921 GrScalar width) {
922 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000923 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000924
925 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
926 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
927 verts[2].set(rect.fRight - rad, rect.fTop + rad);
928 verts[3].set(rect.fRight + rad, rect.fTop - rad);
929 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
930 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
931 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
932 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
933 verts[8] = verts[0];
934 verts[9] = verts[1];
935}
936
bsalomon@google.com205d4602011-04-25 12:43:45 +0000937static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000938 // FIXME: This was copied from SkGpuDevice, seems like
939 // we should have already smeared a in caller if that
940 // is what is desired.
941 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000942 unsigned a = GrColorUnpackA(paint.fColor);
943 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000944 } else {
945 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000946 }
947}
948
949static void setInsetFan(GrPoint* pts, size_t stride,
950 const GrRect& r, GrScalar dx, GrScalar dy) {
951 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
952}
953
954static const uint16_t gFillAARectIdx[] = {
955 0, 1, 5, 5, 4, 0,
956 1, 2, 6, 6, 5, 1,
957 2, 3, 7, 7, 6, 2,
958 3, 0, 4, 4, 7, 3,
959 4, 5, 6, 6, 7, 4,
960};
961
962int GrContext::aaFillRectIndexCount() const {
963 return GR_ARRAY_COUNT(gFillAARectIdx);
964}
965
966GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
967 if (NULL == fAAFillRectIndexBuffer) {
968 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
969 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000970 if (NULL != fAAFillRectIndexBuffer) {
971 #if GR_DEBUG
972 bool updated =
973 #endif
974 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
975 sizeof(gFillAARectIdx));
976 GR_DEBUGASSERT(updated);
977 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000978 }
979 return fAAFillRectIndexBuffer;
980}
981
982static const uint16_t gStrokeAARectIdx[] = {
983 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
984 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
985 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
986 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
987
988 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
989 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
990 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
991 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
992
993 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
994 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
995 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
996 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
997};
998
999int GrContext::aaStrokeRectIndexCount() const {
1000 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1001}
1002
1003GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1004 if (NULL == fAAStrokeRectIndexBuffer) {
1005 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1006 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001007 if (NULL != fAAStrokeRectIndexBuffer) {
1008 #if GR_DEBUG
1009 bool updated =
1010 #endif
1011 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1012 sizeof(gStrokeAARectIdx));
1013 GR_DEBUGASSERT(updated);
1014 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001015 }
1016 return fAAStrokeRectIndexBuffer;
1017}
1018
1019void GrContext::fillAARect(GrDrawTarget* target,
1020 const GrPaint& paint,
1021 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001022 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1023 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001024
1025 size_t vsize = GrDrawTarget::VertexSize(layout);
1026
1027 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001028 if (!geo.succeeded()) {
1029 GrPrintf("Failed to get space for vertices!\n");
1030 return;
1031 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001032 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1033 if (NULL == indexBuffer) {
1034 GrPrintf("Failed to create index buffer!\n");
1035 return;
1036 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001037
1038 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1039
1040 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1041 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1042
1043 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1044 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1045
1046 verts += sizeof(GrPoint);
1047 for (int i = 0; i < 4; ++i) {
1048 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1049 }
1050
1051 GrColor innerColor = getColorForMesh(paint);
1052 verts += 4 * vsize;
1053 for (int i = 0; i < 4; ++i) {
1054 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1055 }
1056
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001057 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001058
1059 target->drawIndexed(kTriangles_PrimitiveType, 0,
1060 0, 8, this->aaFillRectIndexCount());
1061}
1062
1063void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1064 const GrRect& devRect, const GrVec& devStrokeSize) {
1065 const GrScalar& dx = devStrokeSize.fX;
1066 const GrScalar& dy = devStrokeSize.fY;
1067 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1068 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1069
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001070 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1071 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001072
1073 GrScalar spare;
1074 {
1075 GrScalar w = devRect.width() - dx;
1076 GrScalar h = devRect.height() - dy;
1077 spare = GrMin(w, h);
1078 }
1079
1080 if (spare <= 0) {
1081 GrRect r(devRect);
1082 r.inset(-rx, -ry);
1083 fillAARect(target, paint, r);
1084 return;
1085 }
1086
1087 size_t vsize = GrDrawTarget::VertexSize(layout);
1088
1089 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001090 if (!geo.succeeded()) {
1091 GrPrintf("Failed to get space for vertices!\n");
1092 return;
1093 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001094 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1095 if (NULL == indexBuffer) {
1096 GrPrintf("Failed to create index buffer!\n");
1097 return;
1098 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001099
1100 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1101
1102 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1103 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1104 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1105 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1106
1107 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1108 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1109 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1110 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1111
1112 verts += sizeof(GrPoint);
1113 for (int i = 0; i < 4; ++i) {
1114 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1115 }
1116
1117 GrColor innerColor = getColorForMesh(paint);
1118 verts += 4 * vsize;
1119 for (int i = 0; i < 8; ++i) {
1120 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1121 }
1122
1123 verts += 8 * vsize;
1124 for (int i = 0; i < 8; ++i) {
1125 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1126 }
1127
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001128 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001129 target->drawIndexed(kTriangles_PrimitiveType,
1130 0, 0, 16, aaStrokeRectIndexCount());
1131}
1132
reed@google.com20efde72011-05-09 17:00:02 +00001133/**
1134 * Returns true if the rects edges are integer-aligned.
1135 */
1136static bool isIRect(const GrRect& r) {
1137 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1138 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1139}
1140
bsalomon@google.com205d4602011-04-25 12:43:45 +00001141static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001142 const GrPaint& paint,
1143 const GrRect& rect,
1144 GrScalar width,
1145 const GrMatrix* matrix,
1146 GrMatrix* combinedMatrix,
1147 GrRect* devRect) {
1148 // we use a simple alpha ramp to do aa on axis-aligned rects
1149 // do AA with alpha ramp if the caller requested AA, the rect
1150 // will be axis-aligned,the render target is not
1151 // multisampled, and the rect won't land on integer coords.
1152
1153 if (!paint.fAntiAlias) {
1154 return false;
1155 }
1156
1157 if (target->getRenderTarget()->isMultisampled()) {
1158 return false;
1159 }
1160
bsalomon@google.com471d4712011-08-23 15:45:25 +00001161 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001162 return false;
1163 }
1164
1165 if (!target->getViewMatrix().preservesAxisAlignment()) {
1166 return false;
1167 }
1168
1169 if (NULL != matrix &&
1170 !matrix->preservesAxisAlignment()) {
1171 return false;
1172 }
1173
1174 *combinedMatrix = target->getViewMatrix();
1175 if (NULL != matrix) {
1176 combinedMatrix->preConcat(*matrix);
1177 GrAssert(combinedMatrix->preservesAxisAlignment());
1178 }
1179
1180 combinedMatrix->mapRect(devRect, rect);
1181 devRect->sort();
1182
1183 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001184 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001185 } else {
1186 return true;
1187 }
1188}
1189
bsalomon@google.com27847de2011-02-22 20:59:41 +00001190void GrContext::drawRect(const GrPaint& paint,
1191 const GrRect& rect,
1192 GrScalar width,
1193 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001194 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001195
1196 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001197 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198
bsalomon@google.com205d4602011-04-25 12:43:45 +00001199 GrRect devRect = rect;
1200 GrMatrix combinedMatrix;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001201 bool doAA = apply_aa_to_rect(target, paint, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001202 &combinedMatrix, &devRect);
1203
1204 if (doAA) {
1205 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001206 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001207 GrMatrix inv;
1208 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001209 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001210 }
1211 }
1212 target->setViewMatrix(GrMatrix::I());
1213 if (width >= 0) {
1214 GrVec strokeSize;;
1215 if (width > 0) {
1216 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001217 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001218 strokeSize.setAbs(strokeSize);
1219 } else {
1220 strokeSize.set(GR_Scalar1, GR_Scalar1);
1221 }
1222 strokeAARect(target, paint, devRect, strokeSize);
1223 } else {
1224 fillAARect(target, paint, devRect);
1225 }
1226 return;
1227 }
1228
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229 if (width >= 0) {
1230 // TODO: consider making static vertex buffers for these cases.
1231 // Hairline could be done by just adding closing vertex to
1232 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001233 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1234
bsalomon@google.com27847de2011-02-22 20:59:41 +00001235 static const int worstCaseVertCount = 10;
1236 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1237
1238 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001239 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240 return;
1241 }
1242
1243 GrPrimitiveType primType;
1244 int vertCount;
1245 GrPoint* vertex = geo.positions();
1246
1247 if (width > 0) {
1248 vertCount = 10;
1249 primType = kTriangleStrip_PrimitiveType;
1250 setStrokeRectStrip(vertex, rect, width);
1251 } else {
1252 // hairline
1253 vertCount = 5;
1254 primType = kLineStrip_PrimitiveType;
1255 vertex[0].set(rect.fLeft, rect.fTop);
1256 vertex[1].set(rect.fRight, rect.fTop);
1257 vertex[2].set(rect.fRight, rect.fBottom);
1258 vertex[3].set(rect.fLeft, rect.fBottom);
1259 vertex[4].set(rect.fLeft, rect.fTop);
1260 }
1261
1262 GrDrawTarget::AutoViewMatrixRestore avmr;
1263 if (NULL != matrix) {
1264 avmr.set(target);
1265 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001266 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001267 }
1268
1269 target->drawNonIndexed(primType, 0, vertCount);
1270 } else {
1271 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001272 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001273 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1274 if (NULL == sqVB) {
1275 GrPrintf("Failed to create static rect vb.\n");
1276 return;
1277 }
1278 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001279 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1280 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001281 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001282 0, rect.height(), rect.fTop,
1283 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001284
1285 if (NULL != matrix) {
1286 m.postConcat(*matrix);
1287 }
1288
1289 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001290 target->preConcatSamplerMatrices(stageMask, m);
1291
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1293 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001294 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001295 #endif
1296 }
1297}
1298
1299void GrContext::drawRectToRect(const GrPaint& paint,
1300 const GrRect& dstRect,
1301 const GrRect& srcRect,
1302 const GrMatrix* dstMatrix,
1303 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001304 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001305
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001306 // srcRect refers to paint's first texture
1307 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001308 drawRect(paint, dstRect, -1, dstMatrix);
1309 return;
1310 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001311
bsalomon@google.com27847de2011-02-22 20:59:41 +00001312 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1313
1314#if GR_STATIC_RECT_VB
1315 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001316
1317 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001318 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1319
1320 GrMatrix m;
1321
1322 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1323 0, dstRect.height(), dstRect.fTop,
1324 0, 0, GrMatrix::I()[8]);
1325 if (NULL != dstMatrix) {
1326 m.postConcat(*dstMatrix);
1327 }
1328 target->preConcatViewMatrix(m);
1329
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001330 // srcRect refers to first stage
1331 int otherStageMask = paint.getActiveStageMask() &
1332 (~(1 << GrPaint::kFirstTextureStage));
1333 if (otherStageMask) {
1334 target->preConcatSamplerMatrices(otherStageMask, m);
1335 }
1336
bsalomon@google.com27847de2011-02-22 20:59:41 +00001337 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1338 0, srcRect.height(), srcRect.fTop,
1339 0, 0, GrMatrix::I()[8]);
1340 if (NULL != srcMatrix) {
1341 m.postConcat(*srcMatrix);
1342 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001343 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001345 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1346 if (NULL == sqVB) {
1347 GrPrintf("Failed to create static rect vb.\n");
1348 return;
1349 }
1350 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001351 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1352#else
1353
1354 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001355#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001356 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001357#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001358 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1359#endif
1360
1361 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1362 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1363 srcRects[0] = &srcRect;
1364 srcMatrices[0] = srcMatrix;
1365
1366 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1367#endif
1368}
1369
1370void GrContext::drawVertices(const GrPaint& paint,
1371 GrPrimitiveType primitiveType,
1372 int vertexCount,
1373 const GrPoint positions[],
1374 const GrPoint texCoords[],
1375 const GrColor colors[],
1376 const uint16_t indices[],
1377 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001378 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379
1380 GrDrawTarget::AutoReleaseGeometry geo;
1381
1382 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1383
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001384 bool hasTexCoords[GrPaint::kTotalStages] = {
1385 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1386 0 // remaining stages use positions
1387 };
1388
1389 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001390
1391 if (NULL != colors) {
1392 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001393 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001394 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395
1396 if (sizeof(GrPoint) != vertexSize) {
1397 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001398 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001399 return;
1400 }
1401 int texOffsets[GrDrawTarget::kMaxTexCoords];
1402 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001403 int edgeOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001404 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1405 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001406 &colorOffset,
1407 &edgeOffset);
1408 GrAssert(-1 == edgeOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001409 void* curVertex = geo.vertices();
1410
1411 for (int i = 0; i < vertexCount; ++i) {
1412 *((GrPoint*)curVertex) = positions[i];
1413
1414 if (texOffsets[0] > 0) {
1415 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1416 }
1417 if (colorOffset > 0) {
1418 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1419 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001420 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001421 }
1422 } else {
1423 target->setVertexSourceToArray(layout, positions, vertexCount);
1424 }
1425
bsalomon@google.com91958362011-06-13 17:58:13 +00001426 // we don't currently apply offscreen AA to this path. Need improved
1427 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001428
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001429 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001430 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001431 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001432 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001433 target->drawNonIndexed(primitiveType, 0, vertexCount);
1434 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001435}
1436
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001437///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001438
reed@google.com07f3ee12011-05-16 17:21:57 +00001439void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1440 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441
bsalomon@google.com27847de2011-02-22 20:59:41 +00001442 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001443 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1444 if (NULL == pr) {
1445 GrPrintf("Unable to find path renderer compatible with path.\n");
1446 return;
1447 }
1448
bsalomon@google.comee435122011-07-01 14:57:55 +00001449 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1450 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001452 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001453 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001454
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001455 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001456
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001457 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001458 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1459 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001460 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001461 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001462 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001463 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001464 return;
1465 }
1466 }
reed@google.com70c136e2011-06-03 19:51:26 +00001467
reed@google.com07f3ee12011-05-16 17:21:57 +00001468 GrRect pathBounds = path.getBounds();
1469 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001470 if (NULL != translate) {
1471 pathBounds.offset(*translate);
1472 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001473 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001474 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001475 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001476 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001477 return;
1478 }
1479 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001480 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001481 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1482 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001483 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1484 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1485 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001486 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001487 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1488 }
1489 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001490 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001491 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001492 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1493 GrRect rect;
1494 if (clipIBounds.fTop < bound.fTop) {
1495 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1496 clipIBounds.fRight, bound.fTop);
1497 target->drawSimpleRect(rect, NULL, stageMask);
1498 }
1499 if (clipIBounds.fLeft < bound.fLeft) {
1500 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1501 bound.fLeft, bound.fBottom);
1502 target->drawSimpleRect(rect, NULL, stageMask);
1503 }
1504 if (clipIBounds.fRight > bound.fRight) {
1505 rect.setLTRB(bound.fRight, bound.fTop,
1506 clipIBounds.fRight, bound.fBottom);
1507 target->drawSimpleRect(rect, NULL, stageMask);
1508 }
1509 if (clipIBounds.fBottom > bound.fBottom) {
1510 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1511 clipIBounds.fRight, clipIBounds.fBottom);
1512 target->drawSimpleRect(rect, NULL, stageMask);
1513 }
1514 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001515 return;
1516 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001517 }
1518 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001519}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001520
bsalomon@google.com27847de2011-02-22 20:59:41 +00001521////////////////////////////////////////////////////////////////////////////////
1522
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001523bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001524 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001525}
1526
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001527void GrContext::flush(int flagsBitfield) {
1528 if (kDiscard_FlushBit & flagsBitfield) {
1529 fDrawBuffer->reset();
1530 } else {
1531 flushDrawBuffer();
1532 }
1533
1534 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001535 fGpu->forceRenderTargetFlush();
1536 }
1537}
1538
1539void GrContext::flushText() {
1540 if (kText_DrawCategory == fLastDrawCategory) {
1541 flushDrawBuffer();
1542 }
1543}
1544
1545void GrContext::flushDrawBuffer() {
1546#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001547 if (fDrawBuffer) {
1548 fDrawBuffer->playback(fGpu);
1549 fDrawBuffer->reset();
1550 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001551#endif
1552}
1553
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001554bool GrContext::readTexturePixels(GrTexture* texture,
1555 int left, int top, int width, int height,
1556 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001557 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001558
1559 // TODO: code read pixels for textures that aren't rendertargets
1560
1561 this->flush();
1562 GrRenderTarget* target = texture->asRenderTarget();
1563 if (NULL != target) {
1564 return fGpu->readPixels(target,
1565 left, top, width, height,
1566 config, buffer);
1567 } else {
1568 return false;
1569 }
1570}
1571
1572bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1573 int left, int top, int width, int height,
1574 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001575 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001576 uint32_t flushFlags = 0;
1577 if (NULL == target) {
1578 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1579 }
1580
1581 this->flush(flushFlags);
1582 return fGpu->readPixels(target,
1583 left, top, width, height,
1584 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001585}
1586
1587void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001588 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001589 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001590 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001591
1592 // TODO: when underlying api has a direct way to do this we should use it
1593 // (e.g. glDrawPixels on desktop GL).
1594
bsalomon@google.com5c638652011-07-18 19:31:59 +00001595 this->flush(true);
1596
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001597 const GrTextureDesc desc = {
1598 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001599 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001600 GrAutoScratchTexture ast(this, desc);
1601 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001602 if (NULL == texture) {
1603 return;
1604 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001605 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001606
bsalomon@google.com27847de2011-02-22 20:59:41 +00001607 GrDrawTarget::AutoStateRestore asr(fGpu);
1608
1609 GrMatrix matrix;
1610 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1611 fGpu->setViewMatrix(matrix);
1612
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001613 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1615 fGpu->setAlpha(0xFF);
1616 fGpu->setBlendFunc(kOne_BlendCoeff,
1617 kZero_BlendCoeff);
1618 fGpu->setTexture(0, texture);
1619
1620 GrSamplerState sampler;
1621 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001622 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001623 sampler.setMatrix(matrix);
1624 fGpu->setSamplerState(0, sampler);
1625
1626 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1627 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001628 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001629 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1630 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001631 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001632 return;
1633 }
1634 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1635 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1636}
1637////////////////////////////////////////////////////////////////////////////////
1638
1639void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001640
1641 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1642 int s = i + GrPaint::kFirstTextureStage;
1643 target->setTexture(s, paint.getTexture(i));
1644 target->setSamplerState(s, *paint.getTextureSampler(i));
1645 }
1646
1647 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1648
1649 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1650 int s = i + GrPaint::kFirstMaskStage;
1651 target->setTexture(s, paint.getMask(i));
1652 target->setSamplerState(s, *paint.getMaskSampler(i));
1653 }
1654
bsalomon@google.com27847de2011-02-22 20:59:41 +00001655 target->setColor(paint.fColor);
1656
1657 if (paint.fDither) {
1658 target->enableState(GrDrawTarget::kDither_StateBit);
1659 } else {
1660 target->disableState(GrDrawTarget::kDither_StateBit);
1661 }
1662 if (paint.fAntiAlias) {
1663 target->enableState(GrDrawTarget::kAntialias_StateBit);
1664 } else {
1665 target->disableState(GrDrawTarget::kAntialias_StateBit);
1666 }
1667 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001668 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001669}
1670
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001671GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001672 DrawCategory category) {
1673 if (category != fLastDrawCategory) {
1674 flushDrawBuffer();
1675 fLastDrawCategory = category;
1676 }
1677 SetPaint(paint, fGpu);
1678 GrDrawTarget* target = fGpu;
1679 switch (category) {
1680 case kText_DrawCategory:
1681#if DEFER_TEXT_RENDERING
1682 target = fDrawBuffer;
1683 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1684#else
1685 target = fGpu;
1686#endif
1687 break;
1688 case kUnbuffered_DrawCategory:
1689 target = fGpu;
1690 break;
1691 case kBuffered_DrawCategory:
1692 target = fDrawBuffer;
1693 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1694 break;
1695 }
1696 return target;
1697}
1698
bsalomon@google.com30085192011-08-19 15:42:31 +00001699GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1700 const GrPath& path,
1701 GrPathFill fill) {
1702 if (NULL == fPathRendererChain) {
1703 fPathRendererChain =
1704 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1705 }
1706 return fPathRendererChain->getPathRenderer(target, path, fill);
1707}
1708
bsalomon@google.com27847de2011-02-22 20:59:41 +00001709////////////////////////////////////////////////////////////////////////////////
1710
bsalomon@google.com27847de2011-02-22 20:59:41 +00001711void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001712 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001713 fGpu->setRenderTarget(target);
1714}
1715
1716GrRenderTarget* GrContext::getRenderTarget() {
1717 return fGpu->getRenderTarget();
1718}
1719
1720const GrRenderTarget* GrContext::getRenderTarget() const {
1721 return fGpu->getRenderTarget();
1722}
1723
1724const GrMatrix& GrContext::getMatrix() const {
1725 return fGpu->getViewMatrix();
1726}
1727
1728void GrContext::setMatrix(const GrMatrix& m) {
1729 fGpu->setViewMatrix(m);
1730}
1731
1732void GrContext::concatMatrix(const GrMatrix& m) const {
1733 fGpu->preConcatViewMatrix(m);
1734}
1735
1736static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1737 intptr_t mask = 1 << shift;
1738 if (pred) {
1739 bits |= mask;
1740 } else {
1741 bits &= ~mask;
1742 }
1743 return bits;
1744}
1745
1746void GrContext::resetStats() {
1747 fGpu->resetStats();
1748}
1749
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001750const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001751 return fGpu->getStats();
1752}
1753
1754void GrContext::printStats() const {
1755 fGpu->printStats();
1756}
1757
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001758GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001759 fGpu = gpu;
1760 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001761 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001762
bsalomon@google.com30085192011-08-19 15:42:31 +00001763 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001764
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001765 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1766 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001767 fFontCache = new GrFontCache(fGpu);
1768
1769 fLastDrawCategory = kUnbuffered_DrawCategory;
1770
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001771 fDrawBuffer = NULL;
1772 fDrawBufferVBAllocPool = NULL;
1773 fDrawBufferIBAllocPool = NULL;
1774
bsalomon@google.com205d4602011-04-25 12:43:45 +00001775 fAAFillRectIndexBuffer = NULL;
1776 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001777
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001778 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1779 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001780 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1781 }
1782 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001783
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001784 this->setupDrawBuffer();
1785}
1786
1787void GrContext::setupDrawBuffer() {
1788
1789 GrAssert(NULL == fDrawBuffer);
1790 GrAssert(NULL == fDrawBufferVBAllocPool);
1791 GrAssert(NULL == fDrawBufferIBAllocPool);
1792
bsalomon@google.com27847de2011-02-22 20:59:41 +00001793#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001794 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001795 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001796 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1797 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001798 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001799 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001800 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001801 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1802
bsalomon@google.com471d4712011-08-23 15:45:25 +00001803 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1804 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001805 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001806#endif
1807
1808#if BATCH_RECT_TO_RECT
1809 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1810#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001811}
1812
bsalomon@google.com27847de2011-02-22 20:59:41 +00001813GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1814 GrDrawTarget* target;
1815#if DEFER_TEXT_RENDERING
1816 target = prepareToDraw(paint, kText_DrawCategory);
1817#else
1818 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1819#endif
1820 SetPaint(paint, target);
1821 return target;
1822}
1823
1824const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1825 return fGpu->getQuadIndexBuffer();
1826}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001827
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001828void GrContext::convolveInX(GrTexture* texture,
1829 const SkRect& rect,
1830 const float* kernel,
1831 int kernelWidth) {
1832 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1833 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1834}
1835
1836void GrContext::convolveInY(GrTexture* texture,
1837 const SkRect& rect,
1838 const float* kernel,
1839 int kernelWidth) {
1840 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1841 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1842}
1843
1844void GrContext::convolve(GrTexture* texture,
1845 const SkRect& rect,
1846 float imageIncrement[2],
1847 const float* kernel,
1848 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001849 GrDrawTarget::AutoStateRestore asr(fGpu);
1850 GrMatrix sampleM;
1851 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1852 GrSamplerState::kClamp_WrapMode,
1853 GrSamplerState::kConvolution_Filter);
1854 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001855 sampleM.setScale(GR_Scalar1 / texture->width(),
1856 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001857 sampler.setMatrix(sampleM);
1858 fGpu->setSamplerState(0, sampler);
1859 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001860 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001861 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001862 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1863}