blob: 7ee2b71746193b62a20b7cc58e647f51542226c5 [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
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000025#define DEFER_TEXT_RENDERING 1
bsalomon@google.com27847de2011-02-22 20:59:41 +000026
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000027#define DEFER_PATHS 1
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000028
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000029#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
bsalomon@google.com27847de2011-02-22 20:59:41 +000030
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000031#define MAX_BLUR_SIGMA 4.0f
32
bsalomon@google.comd46e2422011-09-23 17:40:07 +000033// When we're using coverage AA but the blend is incompatible (given gpu
34// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000035#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000036
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000037static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000039
bsalomon@google.com60361492012-03-15 17:47:06 +000040static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000041static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000043// path rendering is the only thing we defer today that uses non-static indices
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000046
bsalomon@google.combc4b6542011-11-19 13:56:11 +000047#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
48
bsalomon@google.com05ef5102011-05-02 21:14:59 +000049GrContext* GrContext::Create(GrEngine engine,
50 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000051 GrContext* ctx = NULL;
52 GrGpu* fGpu = GrGpu::Create(engine, context3D);
53 if (NULL != fGpu) {
54 ctx = new GrContext(fGpu);
55 fGpu->unref();
56 }
57 return ctx;
58}
59
bsalomon@google.com27847de2011-02-22 20:59:41 +000060GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000061 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 delete fTextureCache;
63 delete fFontCache;
64 delete fDrawBuffer;
65 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000066 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000067
bsalomon@google.com205d4602011-04-25 12:43:45 +000068 GrSafeUnref(fAAFillRectIndexBuffer);
69 GrSafeUnref(fAAStrokeRectIndexBuffer);
70 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000071 GrSafeUnref(fPathRendererChain);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000072 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com30085192011-08-19 15:42:31 +000085 // a path renderer may be holding onto resources that
86 // are now unusable
87 GrSafeSetNull(fPathRendererChain);
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBuffer;
90 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferVBAllocPool;
93 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000094
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 delete fDrawBufferIBAllocPool;
96 fDrawBufferIBAllocPool = NULL;
97
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 GrSafeSetNull(fAAFillRectIndexBuffer);
99 GrSafeSetNull(fAAStrokeRectIndexBuffer);
100
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101 fTextureCache->removeAll();
102 fFontCache->freeAll();
103 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000104}
105
106void GrContext::resetContext() {
107 fGpu->markContextDirty();
108}
109
110void GrContext::freeGpuResources() {
111 this->flush();
112 fTextureCache->removeAll();
113 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000114 // a path renderer may be holding onto resources
115 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000116}
117
twiz@google.com05e70242012-01-27 19:12:00 +0000118size_t GrContext::getGpuTextureCacheBytes() const {
119 return fTextureCache->getCachedResourceBytes();
120}
121
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000122////////////////////////////////////////////////////////////////////////////////
123
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000124int GrContext::PaintStageVertexLayoutBits(
125 const GrPaint& paint,
126 const bool hasTexCoords[GrPaint::kTotalStages]) {
127 int stageMask = paint.getActiveStageMask();
128 int layout = 0;
129 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
130 if ((1 << i) & stageMask) {
131 if (NULL != hasTexCoords && hasTexCoords[i]) {
132 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
133 } else {
134 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
135 }
136 }
137 }
138 return layout;
139}
140
141
142////////////////////////////////////////////////////////////////////////////////
143
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000144enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000145 // flags for textures
146 kNPOTBit = 0x1,
147 kFilterBit = 0x2,
148 kScratchBit = 0x4,
149
150 // resource type
151 kTextureBit = 0x8,
152 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000153};
154
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000155GrTexture* GrContext::TextureCacheEntry::texture() const {
156 if (NULL == fEntry) {
157 return NULL;
158 } else {
159 return (GrTexture*) fEntry->resource();
160 }
161}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000162
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163namespace {
164// returns true if this is a "special" texture because of gpu NPOT limitations
165bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000166 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000167 GrContext::TextureKey clientKey,
168 int width,
169 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000170 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000171 bool scratch,
172 uint32_t v[4]) {
173 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
174 // we assume we only need 16 bits of width and height
175 // assert that texture creation will fail anyway if this assumption
176 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000177 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000178 v[0] = clientKey & 0xffffffffUL;
179 v[1] = (clientKey >> 32) & 0xffffffffUL;
180 v[2] = width | (height << 16);
181
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000182 v[3] = (sampleCnt << 24);
183 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
184
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000185 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000186 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
187
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000188 bool tiled = NULL != sampler &&
189 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
190 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000191
192 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000194 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000195 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000196 }
197 }
198 }
199
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000200 if (scratch) {
201 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000202 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000203
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000204 v[3] |= kTextureBit;
205
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000206 return v[3] & kNPOTBit;
207}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000208
209// we should never have more than one stencil buffer with same combo of
210// (width,height,samplecount)
211void gen_stencil_key_values(int width, int height,
212 int sampleCnt, uint32_t v[4]) {
213 v[0] = width;
214 v[1] = height;
215 v[2] = sampleCnt;
216 v[3] = kStencilBufferBit;
217}
218
219void gen_stencil_key_values(const GrStencilBuffer* sb,
220 uint32_t v[4]) {
221 gen_stencil_key_values(sb->width(), sb->height(),
222 sb->numSamples(), v);
223}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000224
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000225void build_kernel(float sigma, float* kernel, int kernelWidth) {
226 int halfWidth = (kernelWidth - 1) / 2;
227 float sum = 0.0f;
228 float denom = 1.0f / (2.0f * sigma * sigma);
229 for (int i = 0; i < kernelWidth; ++i) {
230 float x = static_cast<float>(i - halfWidth);
231 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
232 // is dropped here, since we renormalize the kernel below.
233 kernel[i] = sk_float_exp(- x * x * denom);
234 sum += kernel[i];
235 }
236 // Normalize the kernel
237 float scale = 1.0f / sum;
238 for (int i = 0; i < kernelWidth; ++i)
239 kernel[i] *= scale;
240}
241
242void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000243 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
244 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
245 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
246 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000247}
248
249float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
250 int *kernelWidth) {
251 *scaleFactor = 1;
252 while (sigma > MAX_BLUR_SIGMA) {
253 *scaleFactor *= 2;
254 sigma *= 0.5f;
255 }
256 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
257 *kernelWidth = *halfWidth * 2 + 1;
258 return sigma;
259}
260
261void apply_morphology(GrGpu* gpu,
262 GrTexture* texture,
263 const SkRect& rect,
264 int radius,
265 GrSamplerState::Filter filter,
266 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000267 GrAssert(filter == GrSamplerState::kErode_Filter ||
268 filter == GrSamplerState::kDilate_Filter);
269
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000270 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
271 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000272 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000273 drawState->setRenderTarget(target);
274 GrMatrix sampleM;
275 sampleM.setIDiv(texture->width(), texture->height());
276 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
277 sampleM);
278 drawState->sampler(0)->setMorphologyRadius(radius);
279 drawState->sampler(0)->setFilterDirection(direction);
280 drawState->setTexture(0, texture);
281 gpu->drawSimpleRect(rect, NULL, 1 << 0);
282}
283
284void convolve(GrGpu* gpu,
285 GrTexture* texture,
286 const SkRect& rect,
287 const float* kernel,
288 int kernelWidth,
289 GrSamplerState::FilterDirection direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000290 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
291 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000292 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000293 drawState->setRenderTarget(target);
294 GrMatrix sampleM;
295 sampleM.setIDiv(texture->width(), texture->height());
296 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
297 GrSamplerState::kConvolution_Filter,
298 sampleM);
299 drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel);
300 drawState->sampler(0)->setFilterDirection(direction);
301 drawState->setTexture(0, texture);
302 gpu->drawSimpleRect(rect, NULL, 1 << 0);
303}
304
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000305}
306
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000307GrContext::TextureCacheEntry GrContext::findAndLockTexture(
308 TextureKey key,
309 int width,
310 int height,
311 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000312 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000313 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000314 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000315 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
316 GrResourceCache::kNested_LockType));
317}
318
bsalomon@google.comfb309512011-11-30 14:13:48 +0000319bool GrContext::isTextureInCache(TextureKey key,
320 int width,
321 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000322 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000323 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000324 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000325 GrResourceKey resourceKey(v);
326 return fTextureCache->hasKey(resourceKey);
327}
328
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000329GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000330 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000331 uint32_t v[4];
332 gen_stencil_key_values(sb, v);
333 GrResourceKey resourceKey(v);
334 return fTextureCache->createAndLock(resourceKey, sb);
335}
336
337GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
338 int sampleCnt) {
339 uint32_t v[4];
340 gen_stencil_key_values(width, height, sampleCnt, v);
341 GrResourceKey resourceKey(v);
342 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
343 GrResourceCache::kSingle_LockType);
344 if (NULL != entry) {
345 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
346 return sb;
347 } else {
348 return NULL;
349 }
350}
351
352void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000353 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000354 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000355}
356
357static void stretchImage(void* dst,
358 int dstW,
359 int dstH,
360 void* src,
361 int srcW,
362 int srcH,
363 int bpp) {
364 GrFixed dx = (srcW << 16) / dstW;
365 GrFixed dy = (srcH << 16) / dstH;
366
367 GrFixed y = dy >> 1;
368
369 int dstXLimit = dstW*bpp;
370 for (int j = 0; j < dstH; ++j) {
371 GrFixed x = dx >> 1;
372 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
373 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
374 for (int i = 0; i < dstXLimit; i += bpp) {
375 memcpy((uint8_t*) dstRow + i,
376 (uint8_t*) srcRow + (x>>16)*bpp,
377 bpp);
378 x += dx;
379 }
380 y += dy;
381 }
382}
383
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000384GrContext::TextureCacheEntry GrContext::createAndLockTexture(
385 TextureKey key,
386 const GrSamplerState* sampler,
387 const GrTextureDesc& desc,
388 void* srcData,
389 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000390 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391
392#if GR_DUMP_TEXTURE_UPLOAD
393 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
394#endif
395
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000396 TextureCacheEntry entry;
397 uint32_t v[4];
398 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000399 desc.fWidth, desc.fHeight,
400 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000401 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000404 GrAssert(NULL != sampler);
405 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
406 desc.fWidth,
407 desc.fHeight,
408 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000409
410 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000411 clampEntry = this->createAndLockTexture(key, NULL, desc,
412 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000413 GrAssert(NULL != clampEntry.texture());
414 if (NULL == clampEntry.texture()) {
415 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000416 }
417 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000418 GrTextureDesc rtDesc = desc;
419 rtDesc.fFlags = rtDesc.fFlags |
420 kRenderTarget_GrTextureFlagBit |
421 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000422 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
423 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000424
425 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
426
427 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000428 GrDrawTarget::AutoStateRestore asr(fGpu,
429 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000430 GrDrawState* drawState = fGpu->drawState();
431 drawState->setRenderTarget(texture->asRenderTarget());
432 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000433
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000434 GrSamplerState::Filter filter;
435 // if filtering is not desired then we want to ensure all
436 // texels in the resampled image are copies of texels from
437 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000438 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000439 filter = GrSamplerState::kNearest_Filter;
440 } else {
441 filter = GrSamplerState::kBilinear_Filter;
442 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000443 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
444 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000445
446 static const GrVertexLayout layout =
447 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
448 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
449
450 if (arg.succeeded()) {
451 GrPoint* verts = (GrPoint*) arg.vertices();
452 verts[0].setIRectFan(0, 0,
453 texture->width(),
454 texture->height(),
455 2*sizeof(GrPoint));
456 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
457 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
458 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000459 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000460 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000461 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000462 } else {
463 // TODO: Our CPU stretch doesn't filter. But we create separate
464 // stretched textures when the sampler state is either filtered or
465 // not. Either implement filtered stretch blit on CPU or just create
466 // one when FBO case fails.
467
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000468 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000469 // no longer need to clamp at min RT size.
470 rtDesc.fWidth = GrNextPow2(desc.fWidth);
471 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000472 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000473 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000474 rtDesc.fWidth *
475 rtDesc.fHeight);
476 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
477 srcData, desc.fWidth, desc.fHeight, bpp);
478
479 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
480
481 GrTexture* texture = fGpu->createTexture(rtDesc,
482 stretchedPixels.get(),
483 stretchedRowBytes);
484 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000486 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000487 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000488
489 } else {
490 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
491 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000493 }
494 }
495 return entry;
496}
497
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000498namespace {
499inline void gen_scratch_tex_key_values(const GrGpu* gpu,
500 const GrTextureDesc& desc,
501 uint32_t v[4]) {
502 // Instead of a client-provided key of the texture contents
503 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000504 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000505 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000506 // this code path isn't friendly to tiling with NPOT restricitons
507 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000508 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000509 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000510}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000511}
512
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513GrContext::TextureCacheEntry GrContext::lockScratchTexture(
514 const GrTextureDesc& inDesc,
515 ScratchTexMatch match) {
516
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000517 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 if (kExact_ScratchTexMatch != match) {
519 // bin by pow2 with a reasonable min
520 static const int MIN_SIZE = 256;
521 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
522 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
523 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000524
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000525 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000526 int origWidth = desc.fWidth;
527 int origHeight = desc.fHeight;
528 bool doubledW = false;
529 bool doubledH = false;
530
531 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000532 uint32_t v[4];
533 gen_scratch_tex_key_values(fGpu, desc, v);
534 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000535 entry = fTextureCache->findAndLock(key,
536 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000537 // if we miss, relax the fit of the flags...
538 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000539 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000540 break;
541 }
542 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
543 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
544 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
545 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
546 } else if (!doubledW) {
547 desc.fFlags = inDesc.fFlags;
548 desc.fWidth *= 2;
549 doubledW = true;
550 } else if (!doubledH) {
551 desc.fFlags = inDesc.fFlags;
552 desc.fWidth = origWidth;
553 desc.fHeight *= 2;
554 doubledH = true;
555 } else {
556 break;
557 }
558
559 } while (true);
560
561 if (NULL == entry) {
562 desc.fFlags = inDesc.fFlags;
563 desc.fWidth = origWidth;
564 desc.fHeight = origHeight;
565 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
566 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000567 uint32_t v[4];
568 gen_scratch_tex_key_values(fGpu, desc, v);
569 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000570 entry = fTextureCache->createAndLock(key, texture);
571 }
572 }
573
574 // If the caller gives us the same desc/sampler twice we don't want
575 // to return the same texture the second time (unless it was previously
576 // released). So we detach the entry from the cache and reattach at release.
577 if (NULL != entry) {
578 fTextureCache->detach(entry);
579 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000580 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000581}
582
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000583void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000584 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000585 // If this is a scratch texture we detached it from the cache
586 // while it was locked (to avoid two callers simultaneously getting
587 // the same texture).
588 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
589 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000590 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000591 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000592 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000593}
594
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000595GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596 void* srcData,
597 size_t rowBytes) {
598 return fGpu->createTexture(desc, srcData, rowBytes);
599}
600
601void GrContext::getTextureCacheLimits(int* maxTextures,
602 size_t* maxTextureBytes) const {
603 fTextureCache->getLimits(maxTextures, maxTextureBytes);
604}
605
606void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
607 fTextureCache->setLimits(maxTextures, maxTextureBytes);
608}
609
bsalomon@google.com91958362011-06-13 17:58:13 +0000610int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000611 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000612}
613
614int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000615 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000616}
617
618///////////////////////////////////////////////////////////////////////////////
619
bsalomon@google.come269f212011-11-07 13:29:52 +0000620GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
621 return fGpu->createPlatformTexture(desc);
622}
623
624GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
625 return fGpu->createPlatformRenderTarget(desc);
626}
627
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000628///////////////////////////////////////////////////////////////////////////////
629
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000630bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000631 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000632 const GrDrawTarget::Caps& caps = fGpu->getCaps();
633 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000634 return false;
635 }
636
bsalomon@google.com27847de2011-02-22 20:59:41 +0000637 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
638
639 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000640 bool tiled = NULL != sampler &&
641 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
642 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000643 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644 return false;
645 }
646 }
647 return true;
648}
649
650////////////////////////////////////////////////////////////////////////////////
651
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000652const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
653
bsalomon@google.com27847de2011-02-22 20:59:41 +0000654void GrContext::setClip(const GrClip& clip) {
655 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000656 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000657}
658
659void GrContext::setClip(const GrIRect& rect) {
660 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000661 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000662 fGpu->setClip(clip);
663}
664
665////////////////////////////////////////////////////////////////////////////////
666
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000667void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000668 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000669 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000670}
671
672void GrContext::drawPaint(const GrPaint& paint) {
673 // set rect to be big enough to fill the space, but not super-huge, so we
674 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000675 GrRect r;
676 r.setLTRB(0, 0,
677 GrIntToScalar(getRenderTarget()->width()),
678 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000679 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000680 SkTLazy<GrPaint> tmpPaint;
681 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000682 GrAutoMatrix am;
683
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000684 // We attempt to map r by the inverse matrix and draw that. mapRect will
685 // map the four corners and bound them with a new rect. This will not
686 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000687 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000688 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000689 GrPrintf("Could not invert matrix");
690 return;
691 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000692 inverse.mapRect(&r);
693 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000694 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000695 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000696 GrPrintf("Could not invert matrix");
697 return;
698 }
699 tmpPaint.set(paint);
700 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
701 p = tmpPaint.get();
702 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000703 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000704 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000705 // by definition this fills the entire clip, no need for AA
706 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000707 if (!tmpPaint.isValid()) {
708 tmpPaint.set(paint);
709 p = tmpPaint.get();
710 }
711 GrAssert(p == tmpPaint.get());
712 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000713 }
714 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000715}
716
bsalomon@google.com205d4602011-04-25 12:43:45 +0000717////////////////////////////////////////////////////////////////////////////////
718
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000719namespace {
720inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
721 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
722}
723}
724
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000725////////////////////////////////////////////////////////////////////////////////
726
bsalomon@google.com27847de2011-02-22 20:59:41 +0000727/* create a triangle strip that strokes the specified triangle. There are 8
728 unique vertices, but we repreat the last 2 to close up. Alternatively we
729 could use an indices array, and then only send 8 verts, but not sure that
730 would be faster.
731 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000732static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000733 GrScalar width) {
734 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000735 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000736
737 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
738 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
739 verts[2].set(rect.fRight - rad, rect.fTop + rad);
740 verts[3].set(rect.fRight + rad, rect.fTop - rad);
741 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
742 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
743 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
744 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
745 verts[8] = verts[0];
746 verts[9] = verts[1];
747}
748
bsalomon@google.com205d4602011-04-25 12:43:45 +0000749static void setInsetFan(GrPoint* pts, size_t stride,
750 const GrRect& r, GrScalar dx, GrScalar dy) {
751 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
752}
753
754static const uint16_t gFillAARectIdx[] = {
755 0, 1, 5, 5, 4, 0,
756 1, 2, 6, 6, 5, 1,
757 2, 3, 7, 7, 6, 2,
758 3, 0, 4, 4, 7, 3,
759 4, 5, 6, 6, 7, 4,
760};
761
762int GrContext::aaFillRectIndexCount() const {
763 return GR_ARRAY_COUNT(gFillAARectIdx);
764}
765
766GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
767 if (NULL == fAAFillRectIndexBuffer) {
768 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
769 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000770 if (NULL != fAAFillRectIndexBuffer) {
771 #if GR_DEBUG
772 bool updated =
773 #endif
774 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
775 sizeof(gFillAARectIdx));
776 GR_DEBUGASSERT(updated);
777 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000778 }
779 return fAAFillRectIndexBuffer;
780}
781
782static const uint16_t gStrokeAARectIdx[] = {
783 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
784 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
785 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
786 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
787
788 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
789 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
790 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
791 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
792
793 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
794 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
795 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
796 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
797};
798
799int GrContext::aaStrokeRectIndexCount() const {
800 return GR_ARRAY_COUNT(gStrokeAARectIdx);
801}
802
803GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
804 if (NULL == fAAStrokeRectIndexBuffer) {
805 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
806 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000807 if (NULL != fAAStrokeRectIndexBuffer) {
808 #if GR_DEBUG
809 bool updated =
810 #endif
811 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
812 sizeof(gStrokeAARectIdx));
813 GR_DEBUGASSERT(updated);
814 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000815 }
816 return fAAStrokeRectIndexBuffer;
817}
818
bsalomon@google.coma3108262011-10-10 14:08:47 +0000819static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
820 bool useCoverage) {
821 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000822 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000823 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000824 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
825 }
826 }
827 if (useCoverage) {
828 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
829 } else {
830 layout |= GrDrawTarget::kColor_VertexLayoutBit;
831 }
832 return layout;
833}
834
bsalomon@google.com205d4602011-04-25 12:43:45 +0000835void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000836 const GrRect& devRect,
837 bool useVertexCoverage) {
838 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000839
840 size_t vsize = GrDrawTarget::VertexSize(layout);
841
842 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000843 if (!geo.succeeded()) {
844 GrPrintf("Failed to get space for vertices!\n");
845 return;
846 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000847 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
848 if (NULL == indexBuffer) {
849 GrPrintf("Failed to create index buffer!\n");
850 return;
851 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000852
853 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
854
855 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
856 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
857
858 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
859 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
860
861 verts += sizeof(GrPoint);
862 for (int i = 0; i < 4; ++i) {
863 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
864 }
865
bsalomon@google.coma3108262011-10-10 14:08:47 +0000866 GrColor innerColor;
867 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000868 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000869 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000870 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000871 }
872
bsalomon@google.com205d4602011-04-25 12:43:45 +0000873 verts += 4 * vsize;
874 for (int i = 0; i < 4; ++i) {
875 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
876 }
877
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000878 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000879
880 target->drawIndexed(kTriangles_PrimitiveType, 0,
881 0, 8, this->aaFillRectIndexCount());
882}
883
bsalomon@google.coma3108262011-10-10 14:08:47 +0000884void GrContext::strokeAARect(GrDrawTarget* target,
885 const GrRect& devRect,
886 const GrVec& devStrokeSize,
887 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000888 const GrScalar& dx = devStrokeSize.fX;
889 const GrScalar& dy = devStrokeSize.fY;
890 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
891 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
892
bsalomon@google.com205d4602011-04-25 12:43:45 +0000893 GrScalar spare;
894 {
895 GrScalar w = devRect.width() - dx;
896 GrScalar h = devRect.height() - dy;
897 spare = GrMin(w, h);
898 }
899
900 if (spare <= 0) {
901 GrRect r(devRect);
902 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000903 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000904 return;
905 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000906 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000907 size_t vsize = GrDrawTarget::VertexSize(layout);
908
909 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000910 if (!geo.succeeded()) {
911 GrPrintf("Failed to get space for vertices!\n");
912 return;
913 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000914 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
915 if (NULL == indexBuffer) {
916 GrPrintf("Failed to create index buffer!\n");
917 return;
918 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000919
920 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
921
922 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
923 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
924 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
925 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
926
927 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
928 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
929 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
930 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
931
932 verts += sizeof(GrPoint);
933 for (int i = 0; i < 4; ++i) {
934 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
935 }
936
bsalomon@google.coma3108262011-10-10 14:08:47 +0000937 GrColor innerColor;
938 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000939 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000940 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000941 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000942 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000943 verts += 4 * vsize;
944 for (int i = 0; i < 8; ++i) {
945 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
946 }
947
948 verts += 8 * vsize;
949 for (int i = 0; i < 8; ++i) {
950 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
951 }
952
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000953 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000954 target->drawIndexed(kTriangles_PrimitiveType,
955 0, 0, 16, aaStrokeRectIndexCount());
956}
957
reed@google.com20efde72011-05-09 17:00:02 +0000958/**
959 * Returns true if the rects edges are integer-aligned.
960 */
961static bool isIRect(const GrRect& r) {
962 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
963 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
964}
965
bsalomon@google.com205d4602011-04-25 12:43:45 +0000966static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000967 const GrRect& rect,
968 GrScalar width,
969 const GrMatrix* matrix,
970 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000971 GrRect* devRect,
972 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000973 // we use a simple coverage ramp to do aa on axis-aligned rects
974 // we check if the rect will be axis-aligned, and the rect won't land on
975 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000976
bsalomon@google.coma3108262011-10-10 14:08:47 +0000977 // we are keeping around the "tweak the alpha" trick because
978 // it is our only hope for the fixed-pipe implementation.
979 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000980 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000981 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000982 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000983 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000984#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000985 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000986#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000987 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000988 } else {
989 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000990 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000991 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000992 const GrDrawState& drawState = target->getDrawState();
993 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000994 return false;
995 }
996
bsalomon@google.com471d4712011-08-23 15:45:25 +0000997 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000998 return false;
999 }
1000
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001001 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002 return false;
1003 }
1004
1005 if (NULL != matrix &&
1006 !matrix->preservesAxisAlignment()) {
1007 return false;
1008 }
1009
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001010 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001011 if (NULL != matrix) {
1012 combinedMatrix->preConcat(*matrix);
1013 GrAssert(combinedMatrix->preservesAxisAlignment());
1014 }
1015
1016 combinedMatrix->mapRect(devRect, rect);
1017 devRect->sort();
1018
1019 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001020 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001021 } else {
1022 return true;
1023 }
1024}
1025
bsalomon@google.com27847de2011-02-22 20:59:41 +00001026void GrContext::drawRect(const GrPaint& paint,
1027 const GrRect& rect,
1028 GrScalar width,
1029 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001030 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001031
1032 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001033 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001034
bsalomon@google.com205d4602011-04-25 12:43:45 +00001035 GrRect devRect = rect;
1036 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001037 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001038 bool needAA = paint.fAntiAlias &&
1039 !this->getRenderTarget()->isMultisampled();
1040 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1041 &combinedMatrix, &devRect,
1042 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001043
1044 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001045 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001046 if (width >= 0) {
1047 GrVec strokeSize;;
1048 if (width > 0) {
1049 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001050 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001051 strokeSize.setAbs(strokeSize);
1052 } else {
1053 strokeSize.set(GR_Scalar1, GR_Scalar1);
1054 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001055 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001056 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001057 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001058 }
1059 return;
1060 }
1061
bsalomon@google.com27847de2011-02-22 20:59:41 +00001062 if (width >= 0) {
1063 // TODO: consider making static vertex buffers for these cases.
1064 // Hairline could be done by just adding closing vertex to
1065 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001066 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1067
bsalomon@google.com27847de2011-02-22 20:59:41 +00001068 static const int worstCaseVertCount = 10;
1069 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1070
1071 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001072 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001073 return;
1074 }
1075
1076 GrPrimitiveType primType;
1077 int vertCount;
1078 GrPoint* vertex = geo.positions();
1079
1080 if (width > 0) {
1081 vertCount = 10;
1082 primType = kTriangleStrip_PrimitiveType;
1083 setStrokeRectStrip(vertex, rect, width);
1084 } else {
1085 // hairline
1086 vertCount = 5;
1087 primType = kLineStrip_PrimitiveType;
1088 vertex[0].set(rect.fLeft, rect.fTop);
1089 vertex[1].set(rect.fRight, rect.fTop);
1090 vertex[2].set(rect.fRight, rect.fBottom);
1091 vertex[3].set(rect.fLeft, rect.fBottom);
1092 vertex[4].set(rect.fLeft, rect.fTop);
1093 }
1094
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001095 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001096 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001097 GrDrawState* drawState = target->drawState();
1098 avmr.set(drawState);
1099 drawState->preConcatViewMatrix(*matrix);
1100 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001101 }
1102
1103 target->drawNonIndexed(primType, 0, vertCount);
1104 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001105#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001106 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001107 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1108 if (NULL == sqVB) {
1109 GrPrintf("Failed to create static rect vb.\n");
1110 return;
1111 }
1112 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001113 GrDrawState* drawState = target->drawState();
1114 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001115 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001116 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001117 0, rect.height(), rect.fTop,
1118 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119
1120 if (NULL != matrix) {
1121 m.postConcat(*matrix);
1122 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001123 drawState->preConcatViewMatrix(m);
1124 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001125
bsalomon@google.com27847de2011-02-22 20:59:41 +00001126 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001127#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001128 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001129#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130 }
1131}
1132
1133void GrContext::drawRectToRect(const GrPaint& paint,
1134 const GrRect& dstRect,
1135 const GrRect& srcRect,
1136 const GrMatrix* dstMatrix,
1137 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001138 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001139
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001140 // srcRect refers to paint's first texture
1141 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001142 drawRect(paint, dstRect, -1, dstMatrix);
1143 return;
1144 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001145
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1147
1148#if GR_STATIC_RECT_VB
1149 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001150 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001151 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001152 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001153
1154 GrMatrix m;
1155
1156 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1157 0, dstRect.height(), dstRect.fTop,
1158 0, 0, GrMatrix::I()[8]);
1159 if (NULL != dstMatrix) {
1160 m.postConcat(*dstMatrix);
1161 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001162 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001163
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001164 // srcRect refers to first stage
1165 int otherStageMask = paint.getActiveStageMask() &
1166 (~(1 << GrPaint::kFirstTextureStage));
1167 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001168 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001169 }
1170
bsalomon@google.com27847de2011-02-22 20:59:41 +00001171 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1172 0, srcRect.height(), srcRect.fTop,
1173 0, 0, GrMatrix::I()[8]);
1174 if (NULL != srcMatrix) {
1175 m.postConcat(*srcMatrix);
1176 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001177 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001178
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001179 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1180 if (NULL == sqVB) {
1181 GrPrintf("Failed to create static rect vb.\n");
1182 return;
1183 }
1184 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001185 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1186#else
1187
1188 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001189#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001190 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001191#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001192 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1193#endif
1194
tomhudson@google.com93813632011-10-27 20:21:16 +00001195 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1196 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001197 srcRects[0] = &srcRect;
1198 srcMatrices[0] = srcMatrix;
1199
1200 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1201#endif
1202}
1203
1204void GrContext::drawVertices(const GrPaint& paint,
1205 GrPrimitiveType primitiveType,
1206 int vertexCount,
1207 const GrPoint positions[],
1208 const GrPoint texCoords[],
1209 const GrColor colors[],
1210 const uint16_t indices[],
1211 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001212 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001213
1214 GrDrawTarget::AutoReleaseGeometry geo;
1215
1216 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1217
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001218 bool hasTexCoords[GrPaint::kTotalStages] = {
1219 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1220 0 // remaining stages use positions
1221 };
1222
1223 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001224
1225 if (NULL != colors) {
1226 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001228 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229
1230 if (sizeof(GrPoint) != vertexSize) {
1231 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001232 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233 return;
1234 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001235 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001236 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001237 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1238 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001239 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001240 NULL,
1241 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001242 void* curVertex = geo.vertices();
1243
1244 for (int i = 0; i < vertexCount; ++i) {
1245 *((GrPoint*)curVertex) = positions[i];
1246
1247 if (texOffsets[0] > 0) {
1248 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1249 }
1250 if (colorOffset > 0) {
1251 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1252 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001254 }
1255 } else {
1256 target->setVertexSourceToArray(layout, positions, vertexCount);
1257 }
1258
bsalomon@google.com91958362011-06-13 17:58:13 +00001259 // we don't currently apply offscreen AA to this path. Need improved
1260 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001261
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001262 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001263 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001264 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001266 target->drawNonIndexed(primitiveType, 0, vertexCount);
1267 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001268}
1269
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001270///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001271#include "SkDraw.h"
1272#include "SkRasterClip.h"
1273
1274namespace {
1275
1276SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1277 switch (fill) {
1278 case kWinding_PathFill:
1279 return SkPath::kWinding_FillType;
1280 case kEvenOdd_PathFill:
1281 return SkPath::kEvenOdd_FillType;
1282 case kInverseWinding_PathFill:
1283 return SkPath::kInverseWinding_FillType;
1284 case kInverseEvenOdd_PathFill:
1285 return SkPath::kInverseEvenOdd_FillType;
1286 default:
1287 GrCrash("Unexpected fill.");
1288 return SkPath::kWinding_FillType;
1289 }
1290}
1291
1292// gets device coord bounds of path (not considering the fill) and clip. The
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001293// path bounds will be a subset of the clip bounds. returns false if
1294// path bounds would be empty.
bsalomon@google.com150d2842012-01-12 20:19:56 +00001295bool get_path_and_clip_bounds(const GrDrawTarget* target,
1296 const GrPath& path,
1297 const GrVec* translate,
1298 GrIRect* pathBounds,
1299 GrIRect* clipBounds) {
1300 // compute bounds as intersection of rt size, clip, and path
1301 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1302 if (NULL == rt) {
1303 return false;
1304 }
1305 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1306 const GrClip& clip = target->getClip();
1307 if (clip.hasConservativeBounds()) {
1308 clip.getConservativeBounds().roundOut(clipBounds);
1309 if (!pathBounds->intersect(*clipBounds)) {
1310 return false;
1311 }
1312 } else {
1313 // pathBounds is currently the rt extent, set clip bounds to that rect.
1314 *clipBounds = *pathBounds;
1315 }
1316 GrRect pathSBounds = path.getBounds();
1317 if (!pathSBounds.isEmpty()) {
1318 if (NULL != translate) {
1319 pathSBounds.offset(*translate);
1320 }
1321 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1322 pathSBounds);
1323 GrIRect pathIBounds;
1324 pathSBounds.roundOut(&pathIBounds);
1325 if (!pathBounds->intersect(pathIBounds)) {
1326 return false;
1327 }
1328 } else {
1329 return false;
1330 }
1331 return true;
1332}
1333
1334/**
1335 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1336 * scratch texture.
1337 */
1338
1339bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1340 const GrIRect& pathDevBounds,
1341 GrPathFill fill,
1342 GrContext* context,
1343 const GrPoint* translate,
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001344 GrAutoScratchTexture* tex,
1345 bool antiAlias) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001346 SkPaint paint;
1347 SkPath tmpPath;
1348 const SkPath* pathToDraw = &clientPath;
1349 if (kHairLine_PathFill == fill) {
1350 paint.setStyle(SkPaint::kStroke_Style);
1351 paint.setStrokeWidth(SK_Scalar1);
1352 } else {
1353 paint.setStyle(SkPaint::kFill_Style);
1354 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1355 if (skfill != pathToDraw->getFillType()) {
1356 tmpPath = *pathToDraw;
1357 tmpPath.setFillType(skfill);
1358 pathToDraw = &tmpPath;
1359 }
1360 }
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001361 paint.setAntiAlias(antiAlias);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001362 paint.setColor(SK_ColorWHITE);
1363
1364 GrMatrix matrix = context->getMatrix();
1365 if (NULL != translate) {
1366 matrix.postTranslate(translate->fX, translate->fY);
1367 }
1368
1369 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1370 -pathDevBounds.fTop * SK_Scalar1);
1371 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1372 pathDevBounds.height());
1373
1374 SkBitmap bm;
1375 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1376 if (!bm.allocPixels()) {
1377 return false;
1378 }
1379 sk_bzero(bm.getPixels(), bm.getSafeSize());
1380
1381 SkDraw draw;
1382 sk_bzero(&draw, sizeof(draw));
1383 SkRasterClip rc(bounds);
1384 draw.fRC = &rc;
1385 draw.fClip = &rc.bwRgn();
1386 draw.fMatrix = &matrix;
1387 draw.fBitmap = &bm;
1388 draw.drawPath(*pathToDraw, paint);
1389
1390 const GrTextureDesc desc = {
1391 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001392 bounds.fRight,
1393 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001394 kAlpha_8_GrPixelConfig,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001395 0 // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001396 };
1397
1398 tex->set(context, desc);
1399 GrTexture* texture = tex->texture();
1400
1401 if (NULL == texture) {
1402 return false;
1403 }
1404 SkAutoLockPixels alp(bm);
1405 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1406 bm.getPixels(), bm.rowBytes());
1407 return true;
1408}
1409
1410void draw_around_inv_path(GrDrawTarget* target,
1411 GrDrawState::StageMask stageMask,
1412 const GrIRect& clipBounds,
1413 const GrIRect& pathBounds) {
1414 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1415 GrRect rect;
1416 if (clipBounds.fTop < pathBounds.fTop) {
1417 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1418 clipBounds.fRight, pathBounds.fTop);
1419 target->drawSimpleRect(rect, NULL, stageMask);
1420 }
1421 if (clipBounds.fLeft < pathBounds.fLeft) {
1422 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1423 pathBounds.fLeft, pathBounds.fBottom);
1424 target->drawSimpleRect(rect, NULL, stageMask);
1425 }
1426 if (clipBounds.fRight > pathBounds.fRight) {
1427 rect.iset(pathBounds.fRight, pathBounds.fTop,
1428 clipBounds.fRight, pathBounds.fBottom);
1429 target->drawSimpleRect(rect, NULL, stageMask);
1430 }
1431 if (clipBounds.fBottom > pathBounds.fBottom) {
1432 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1433 clipBounds.fRight, clipBounds.fBottom);
1434 target->drawSimpleRect(rect, NULL, stageMask);
1435 }
1436}
1437
bsalomon@google.com93c96602012-04-27 13:05:21 +00001438struct CircleVertex {
1439 GrPoint fPos;
1440 GrPoint fCenter;
1441 GrScalar fOuterRadius;
1442 GrScalar fInnerRadius;
1443};
1444
1445/* Returns true if will map a circle to another circle. This can be true
1446 * if the matrix only includes square-scale, rotation, translation.
1447 */
1448inline bool isSimilarityTransformation(const SkMatrix& matrix,
1449 SkScalar tol = SK_ScalarNearlyZero) {
1450 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1451 return true;
1452 }
1453 if (matrix.hasPerspective()) {
1454 return false;
1455 }
1456
1457 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1458 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1459 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1460 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1461
1462 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1463 return false;
1464 }
1465
1466 // it has scales or skews, but it could also be rotation, check it out.
1467 SkVector vec[2];
1468 vec[0].set(mx, sx);
1469 vec[1].set(sy, my);
1470
1471 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1472 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1473 SkScalarSquare(tol));
1474}
1475
1476}
1477
1478// TODO: strokeWidth can't be larger than zero right now.
1479// It will be fixed when drawPath() can handle strokes.
1480void GrContext::drawOval(const GrPaint& paint,
1481 const GrRect& rect,
1482 SkScalar strokeWidth) {
1483 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1484 kUnbuffered_DrawCategory;
1485 GrDrawTarget* target = this->prepareToDraw(paint, category);
1486 GrDrawState* drawState = target->drawState();
1487 GrMatrix vm = drawState->getViewMatrix();
1488
1489 if (!isSimilarityTransformation(vm) ||
1490 !paint.fAntiAlias ||
1491 rect.height() != rect.width()) {
1492 SkPath path;
1493 path.addOval(rect);
1494 GrPathFill fill = (strokeWidth == 0) ?
1495 kHairLine_PathFill : kWinding_PathFill;
1496 this->internalDrawPath(paint, path, fill, NULL);
1497 return;
1498 }
1499
1500 const GrRenderTarget* rt = drawState->getRenderTarget();
1501 if (NULL == rt) {
1502 return;
1503 }
1504
1505 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1506
1507 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1508 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1509 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1510
1511 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1512 GrScalar radius = SkScalarHalf(rect.width());
1513
1514 vm.mapPoints(&center, 1);
1515 radius = vm.mapRadius(radius);
1516
1517 GrScalar outerRadius = radius;
1518 GrScalar innerRadius = 0;
1519 SkScalar halfWidth = 0;
1520 if (strokeWidth == 0) {
1521 halfWidth = SkScalarHalf(SK_Scalar1);
1522
1523 outerRadius += halfWidth;
1524 innerRadius = SkMaxScalar(0, radius - halfWidth);
1525 }
1526
1527 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1528 if (!geo.succeeded()) {
1529 GrPrintf("Failed to get space for vertices!\n");
1530 return;
1531 }
1532
1533 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1534
1535 SkScalar L = center.fX - outerRadius;
1536 SkScalar R = center.fX + outerRadius;
1537 SkScalar T = center.fY - outerRadius;
1538 SkScalar B = center.fY + outerRadius;
1539
1540 verts[0].fPos = SkPoint::Make(L, T);
1541 verts[1].fPos = SkPoint::Make(R, T);
1542 verts[2].fPos = SkPoint::Make(L, B);
1543 verts[3].fPos = SkPoint::Make(R, B);
1544
1545 for (int i = 0; i < 4; ++i) {
1546 // this goes to fragment shader, it should be in y-points-up space.
1547 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1548
1549 verts[i].fOuterRadius = outerRadius;
1550 verts[i].fInnerRadius = innerRadius;
1551 }
1552
1553 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1554 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001555}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001556
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001557
1558
1559// return true on success; false on failure
1560bool onDrawPath(const SkPath& path,
1561 GrPathFill fill,
1562 const GrVec* translate,
1563 GrDrawTarget* target,
1564 GrDrawState::StageMask stageMask,
1565 bool antiAlias,
1566 GrContext* context) {
1567
1568 GrAutoScratchTexture ast;
1569 GrIRect pathBounds, clipBounds;
1570 if (!get_path_and_clip_bounds(target, path, translate,
1571 &pathBounds, &clipBounds)) {
1572 return true; // path is empty so there is nothing to do
1573 }
1574 if (sw_draw_path_to_mask_texture(path, pathBounds,
1575 fill, context,
1576 translate, &ast, antiAlias)) {
1577 GrTexture* texture = ast.texture();
1578 GrAssert(NULL != texture);
1579 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1580 enum {
1581 kPathMaskStage = GrPaint::kTotalStages,
1582 };
1583 target->drawState()->setTexture(kPathMaskStage, texture);
1584 target->drawState()->sampler(kPathMaskStage)->reset();
1585 GrScalar w = GrIntToScalar(pathBounds.width());
1586 GrScalar h = GrIntToScalar(pathBounds.height());
1587 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1588 h / texture->height());
1589 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1590 srcRects[kPathMaskStage] = &maskRect;
1591 stageMask |= 1 << kPathMaskStage;
1592 GrRect dstRect = GrRect::MakeLTRB(
1593 SK_Scalar1* pathBounds.fLeft,
1594 SK_Scalar1* pathBounds.fTop,
1595 SK_Scalar1* pathBounds.fRight,
1596 SK_Scalar1* pathBounds.fBottom);
1597 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1598 target->drawState()->setTexture(kPathMaskStage, NULL);
1599 if (GrIsFillInverted(fill)) {
1600 draw_around_inv_path(target, stageMask,
1601 clipBounds, pathBounds);
1602 }
1603 return true;
1604 }
1605
1606 return false;
1607}
1608
reed@google.com07f3ee12011-05-16 17:21:57 +00001609void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1610 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001611
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001612 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001613 if (GrIsFillInverted(fill)) {
1614 this->drawPaint(paint);
1615 }
1616 return;
1617 }
1618
bsalomon@google.com93c96602012-04-27 13:05:21 +00001619 SkRect ovalRect;
1620 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1621 if (translate) {
1622 ovalRect.offset(*translate);
1623 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001624 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001625 this->drawOval(paint, ovalRect, width);
1626 return;
1627 }
1628
1629 internalDrawPath(paint, path, fill, translate);
1630}
1631
1632void GrContext::internalDrawPath(const GrPaint& paint, const GrPath& path,
1633 GrPathFill fill, const GrPoint* translate) {
1634
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001635 // Note that below we may sw-rasterize the path into a scratch texture.
1636 // Scratch textures can be recycled after they are returned to the texture
1637 // cache. This presents a potential hazard for buffered drawing. However,
1638 // the writePixels that uploads to the scratch will perform a flush so we're
1639 // OK.
1640 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1641 kUnbuffered_DrawCategory;
1642 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001643 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001644
bsalomon@google.com289533a2011-10-27 12:34:25 +00001645 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1646
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001647 // An Assumption here is that path renderer would use some form of tweaking
1648 // the src color (either the input alpha or in the frag shader) to implement
1649 // aa. If we have some future driver-mojo path AA that can do the right
1650 // thing WRT to the blend then we'll need some query on the PR.
1651 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001652#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001653 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001654#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001655 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001656 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001657
bsalomon@google.com289533a2011-10-27 12:34:25 +00001658 GrPathRenderer* pr = NULL;
1659 if (prAA) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001660 pr = this->getPathRenderer(path, fill, target, true);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001661 if (NULL == pr) {
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001662 if (onDrawPath(path, fill, translate,
1663 target, stageMask, prAA, this)) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001664 return;
1665 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001666 }
1667 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001668 pr = this->getPathRenderer(path, fill, target, false);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001669 }
1670
bsalomon@google.com30085192011-08-19 15:42:31 +00001671 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001672#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001673 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001674#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001675 return;
1676 }
1677
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001678 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001679}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001680
bsalomon@google.com27847de2011-02-22 20:59:41 +00001681////////////////////////////////////////////////////////////////////////////////
1682
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001683void GrContext::flush(int flagsBitfield) {
1684 if (kDiscard_FlushBit & flagsBitfield) {
1685 fDrawBuffer->reset();
1686 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001687 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001688 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001689 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001690 fGpu->forceRenderTargetFlush();
1691 }
1692}
1693
bsalomon@google.com27847de2011-02-22 20:59:41 +00001694void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001695 if (fDrawBuffer) {
bsalomon@google.com97805382012-03-13 14:32:07 +00001696 fDrawBuffer->flushTo(fGpu);
junov@google.com53a55842011-06-08 22:55:10 +00001697 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001698}
1699
bsalomon@google.com6f379512011-11-16 20:36:03 +00001700void GrContext::internalWriteTexturePixels(GrTexture* texture,
1701 int left, int top,
1702 int width, int height,
1703 GrPixelConfig config,
1704 const void* buffer,
1705 size_t rowBytes,
1706 uint32_t flags) {
1707 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001708 ASSERT_OWNED_RESOURCE(texture);
1709
bsalomon@google.com6f379512011-11-16 20:36:03 +00001710 if (!(kDontFlush_PixelOpsFlag & flags)) {
1711 this->flush();
1712 }
1713 // TODO: use scratch texture to perform conversion
1714 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1715 GrPixelConfigIsUnpremultiplied(config)) {
1716 return;
1717 }
1718
1719 fGpu->writeTexturePixels(texture, left, top, width, height,
1720 config, buffer, rowBytes);
1721}
1722
1723bool GrContext::internalReadTexturePixels(GrTexture* texture,
1724 int left, int top,
1725 int width, int height,
1726 GrPixelConfig config,
1727 void* buffer,
1728 size_t rowBytes,
1729 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001730 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001731 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001732
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001733 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001734 GrRenderTarget* target = texture->asRenderTarget();
1735 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001736 return this->internalReadRenderTargetPixels(target,
1737 left, top, width, height,
1738 config, buffer, rowBytes,
1739 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001740 } else {
1741 return false;
1742 }
1743}
1744
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001745#include "SkConfig8888.h"
1746
1747namespace {
1748/**
1749 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1750 * formats are representable as Config8888 and so the function returns false
1751 * if the GrPixelConfig has no equivalent Config8888.
1752 */
1753bool grconfig_to_config8888(GrPixelConfig config,
1754 SkCanvas::Config8888* config8888) {
1755 switch (config) {
1756 case kRGBA_8888_PM_GrPixelConfig:
1757 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1758 return true;
1759 case kRGBA_8888_UPM_GrPixelConfig:
1760 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1761 return true;
1762 case kBGRA_8888_PM_GrPixelConfig:
1763 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1764 return true;
1765 case kBGRA_8888_UPM_GrPixelConfig:
1766 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1767 return true;
1768 default:
1769 return false;
1770 }
1771}
1772}
1773
bsalomon@google.com6f379512011-11-16 20:36:03 +00001774bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1775 int left, int top,
1776 int width, int height,
1777 GrPixelConfig config,
1778 void* buffer,
1779 size_t rowBytes,
1780 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001781 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001782 ASSERT_OWNED_RESOURCE(target);
1783
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001784 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001785 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001786 if (NULL == target) {
1787 return false;
1788 }
1789 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001790
bsalomon@google.com6f379512011-11-16 20:36:03 +00001791 if (!(kDontFlush_PixelOpsFlag & flags)) {
1792 this->flush();
1793 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001794
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001795 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1796 GrPixelConfigIsUnpremultiplied(config) &&
1797 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1798 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1799 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1800 !grconfig_to_config8888(config, &dstConfig8888)) {
1801 return false;
1802 }
1803 // do read back using target's own config
1804 this->internalReadRenderTargetPixels(target,
1805 left, top,
1806 width, height,
1807 target->config(),
1808 buffer, rowBytes,
1809 kDontFlush_PixelOpsFlag);
1810 // sw convert the pixels to unpremul config
1811 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1812 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1813 pixels, rowBytes, srcConfig8888,
1814 width, height);
1815 return true;
1816 }
1817
bsalomon@google.comc4364992011-11-07 15:54:49 +00001818 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001819 bool swapRAndB = NULL != src &&
1820 fGpu->preferredReadPixelsConfig(config) ==
1821 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001822
1823 bool flipY = NULL != src &&
1824 fGpu->readPixelsWillPayForYFlip(target, left, top,
1825 width, height, config,
1826 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001827 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1828 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001829
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001830 if (NULL == src && alphaConversion) {
1831 // we should fallback to cpu conversion here. This could happen when
1832 // we were given an external render target by the client that is not
1833 // also a texture (e.g. FBO 0 in GL)
1834 return false;
1835 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001836 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001837 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001838 if (flipY || swapRAndB || alphaConversion) {
1839 GrAssert(NULL != src);
1840 if (swapRAndB) {
1841 config = GrPixelConfigSwapRAndB(config);
1842 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001843 }
1844 // Make the scratch a render target because we don't have a robust
1845 // readTexturePixels as of yet (it calls this function).
1846 const GrTextureDesc desc = {
1847 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001848 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001849 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001850 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001851 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001852
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001853 // When a full readback is faster than a partial we could always make
1854 // the scratch exactly match the passed rect. However, if we see many
1855 // different size rectangles we will trash our texture cache and pay the
1856 // cost of creating and destroying many textures. So, we only request
1857 // an exact match when the caller is reading an entire RT.
1858 ScratchTexMatch match = kApprox_ScratchTexMatch;
1859 if (0 == left &&
1860 0 == top &&
1861 target->width() == width &&
1862 target->height() == height &&
1863 fGpu->fullReadPixelsIsFasterThanPartial()) {
1864 match = kExact_ScratchTexMatch;
1865 }
1866 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001867 GrTexture* texture = ast.texture();
1868 if (!texture) {
1869 return false;
1870 }
1871 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001872 GrAssert(NULL != target);
1873
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001874 GrDrawTarget::AutoStateRestore asr(fGpu,
1875 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001876 GrDrawState* drawState = fGpu->drawState();
1877 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001878
bsalomon@google.comc4364992011-11-07 15:54:49 +00001879 GrMatrix matrix;
1880 if (flipY) {
1881 matrix.setTranslate(SK_Scalar1 * left,
1882 SK_Scalar1 * (top + height));
1883 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1884 } else {
1885 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1886 }
1887 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001888 drawState->sampler(0)->reset(matrix);
1889 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001890 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001891 GrRect rect;
1892 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1893 fGpu->drawSimpleRect(rect, NULL, 0x1);
1894 left = 0;
1895 top = 0;
1896 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001897 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001898 left, top, width, height,
1899 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001900}
1901
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001902void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1903 GrAssert(target);
1904 ASSERT_OWNED_RESOURCE(target);
1905 // In the future we may track whether there are any pending draws to this
1906 // target. We don't today so we always perform a flush. We don't promise
1907 // this to our clients, though.
1908 this->flush();
1909 fGpu->resolveRenderTarget(target);
1910}
1911
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001912void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1913 if (NULL == src || NULL == dst) {
1914 return;
1915 }
1916 ASSERT_OWNED_RESOURCE(src);
1917
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001918 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001919 GrDrawState* drawState = fGpu->drawState();
1920 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001921 GrMatrix sampleM;
1922 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001923 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001924 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001925 SkRect rect = SkRect::MakeXYWH(0, 0,
1926 SK_Scalar1 * src->width(),
1927 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001928 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1929}
1930
bsalomon@google.com6f379512011-11-16 20:36:03 +00001931void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1932 int left, int top,
1933 int width, int height,
1934 GrPixelConfig config,
1935 const void* buffer,
1936 size_t rowBytes,
1937 uint32_t flags) {
1938 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001939 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001940
1941 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001942 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001943 if (NULL == target) {
1944 return;
1945 }
1946 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001947
1948 // TODO: when underlying api has a direct way to do this we should use it
1949 // (e.g. glDrawPixels on desktop GL).
1950
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001951 // If the RT is also a texture and we don't have to do PM/UPM conversion
1952 // then take the texture path, which we expect to be at least as fast or
1953 // faster since it doesn't use an intermediate texture as we do below.
1954
1955#if !GR_MAC_BUILD
1956 // At least some drivers on the Mac get confused when glTexImage2D is called
1957 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1958 // determine what OS versions and/or HW is affected.
1959 if (NULL != target->asTexture() &&
1960 GrPixelConfigIsUnpremultiplied(target->config()) ==
1961 GrPixelConfigIsUnpremultiplied(config)) {
1962
1963 this->internalWriteTexturePixels(target->asTexture(),
1964 left, top, width, height,
1965 config, buffer, rowBytes, flags);
1966 return;
1967 }
1968#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001969 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1970 GrPixelConfigIsUnpremultiplied(config) &&
1971 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1972 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1973 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1974 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1975 return;
1976 }
1977 // allocate a tmp buffer and sw convert the pixels to premul
1978 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1979 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1980 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1981 src, rowBytes, srcConfig8888,
1982 width, height);
1983 // upload the already premul pixels
1984 this->internalWriteRenderTargetPixels(target,
1985 left, top,
1986 width, height,
1987 target->config(),
1988 tmpPixels, 4 * width, flags);
1989 return;
1990 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001991
1992 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1993 GrPixelConfigSwapRAndB(config);
1994 if (swapRAndB) {
1995 config = GrPixelConfigSwapRAndB(config);
1996 }
1997
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001998 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001999 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00002000 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002001 GrAutoScratchTexture ast(this, desc);
2002 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002003 if (NULL == texture) {
2004 return;
2005 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00002006 this->internalWriteTexturePixels(texture, 0, 0, width, height,
2007 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002008
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00002009 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002010 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002011
2012 GrMatrix matrix;
2013 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002014 drawState->setViewMatrix(matrix);
2015 drawState->setRenderTarget(target);
2016 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002017
bsalomon@google.com5c638652011-07-18 19:31:59 +00002018 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002019 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2020 GrSamplerState::kNearest_Filter,
2021 matrix);
2022 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002023
2024 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
2025 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002026 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00002027 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
2028 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002029 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00002030 return;
2031 }
2032 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
2033 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
2034}
2035////////////////////////////////////////////////////////////////////////////////
2036
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002037void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002038
2039 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2040 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002041 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002042 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002043 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002044 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002045 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002046 }
2047
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002048 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002049
2050 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2051 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002052 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002053 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002054 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002055 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002056 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002057 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00002058
2059 // disable all stages not accessible via the paint
2060 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002061 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00002062 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002063
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002064 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002065
2066 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002067 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002068 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002069 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002070 }
2071 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002072 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002073 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002074 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002075 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002076 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002077 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
2078 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002079 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002080 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002081 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002082 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
2083 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
2084 fDrawState->setCoverage(paint.fCoverage);
bsalomon@google.come79c8152012-03-29 19:07:12 +00002085#if GR_DEBUG
2086 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002087 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002088 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2089 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00002090#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002091}
2092
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002093GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002094 DrawCategory category) {
2095 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002096 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002097 fLastDrawCategory = category;
2098 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002099 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002100 GrDrawTarget* target = fGpu;
2101 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00002102 case kUnbuffered_DrawCategory:
2103 target = fGpu;
2104 break;
2105 case kBuffered_DrawCategory:
2106 target = fDrawBuffer;
2107 fDrawBuffer->setClip(fGpu->getClip());
2108 break;
2109 default:
2110 GrCrash("Unexpected DrawCategory.");
2111 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00002112 }
2113 return target;
2114}
2115
bsalomon@google.com289533a2011-10-27 12:34:25 +00002116GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2117 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00002118 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00002119 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002120 if (NULL == fPathRendererChain) {
2121 fPathRendererChain =
2122 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2123 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00002124 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002125}
2126
bsalomon@google.com27847de2011-02-22 20:59:41 +00002127////////////////////////////////////////////////////////////////////////////////
2128
bsalomon@google.com27847de2011-02-22 20:59:41 +00002129void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002130 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002131 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002132 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002133 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002134 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002135}
2136
2137GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002138 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002139}
2140
2141const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002142 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002143}
2144
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002145bool GrContext::isConfigRenderable(GrPixelConfig config) const {
2146 return fGpu->isConfigRenderable(config);
2147}
2148
bsalomon@google.com27847de2011-02-22 20:59:41 +00002149const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002150 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002151}
2152
2153void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002154 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002155}
2156
2157void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002158 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002159}
2160
2161static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2162 intptr_t mask = 1 << shift;
2163 if (pred) {
2164 bits |= mask;
2165 } else {
2166 bits &= ~mask;
2167 }
2168 return bits;
2169}
2170
2171void GrContext::resetStats() {
2172 fGpu->resetStats();
2173}
2174
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002175const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002176 return fGpu->getStats();
2177}
2178
2179void GrContext::printStats() const {
2180 fGpu->printStats();
2181}
2182
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002183GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002184 fGpu = gpu;
2185 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002186 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002187
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002188 fDrawState = new GrDrawState();
2189 fGpu->setDrawState(fDrawState);
2190
bsalomon@google.com30085192011-08-19 15:42:31 +00002191 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002192
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002193 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2194 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002195 fFontCache = new GrFontCache(fGpu);
2196
2197 fLastDrawCategory = kUnbuffered_DrawCategory;
2198
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002199 fDrawBuffer = NULL;
2200 fDrawBufferVBAllocPool = NULL;
2201 fDrawBufferIBAllocPool = NULL;
2202
bsalomon@google.com205d4602011-04-25 12:43:45 +00002203 fAAFillRectIndexBuffer = NULL;
2204 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002205
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002206 this->setupDrawBuffer();
2207}
2208
2209void GrContext::setupDrawBuffer() {
2210
2211 GrAssert(NULL == fDrawBuffer);
2212 GrAssert(NULL == fDrawBufferVBAllocPool);
2213 GrAssert(NULL == fDrawBufferIBAllocPool);
2214
bsalomon@google.com92edd312012-04-04 21:40:21 +00002215#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002216 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002217 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002218 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2219 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002220 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002221 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002222 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002223 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2224
bsalomon@google.com471d4712011-08-23 15:45:25 +00002225 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2226 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002227 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002228#endif
2229
2230#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002231 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002232#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002233 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002234 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002235}
2236
bsalomon@google.com27847de2011-02-22 20:59:41 +00002237GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002238#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002239 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002240#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002241 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002242#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002243}
2244
2245const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2246 return fGpu->getQuadIndexBuffer();
2247}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002248
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002249GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2250 GrAutoScratchTexture* temp1,
2251 GrAutoScratchTexture* temp2,
2252 const SkRect& rect,
2253 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002254 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002255 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2256 GrClip oldClip = this->getClip();
2257 GrTexture* origTexture = srcTexture;
2258 GrAutoMatrix avm(this, GrMatrix::I());
2259 SkIRect clearRect;
2260 int scaleFactorX, halfWidthX, kernelWidthX;
2261 int scaleFactorY, halfWidthY, kernelWidthY;
2262 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2263 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002264
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002265 SkRect srcRect(rect);
2266 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2267 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002268 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2269 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002270 this->setClip(srcRect);
2271
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002272 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2273 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2274 kAlpha_8_GrPixelConfig == srcTexture->config());
2275
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002276 const GrTextureDesc desc = {
2277 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002278 SkScalarFloorToInt(srcRect.width()),
2279 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002280 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002281 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002282 };
2283
2284 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002285 if (temp2) {
2286 temp2->set(this, desc);
2287 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002288
2289 GrTexture* dstTexture = temp1->texture();
2290 GrPaint paint;
2291 paint.reset();
2292 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2293
2294 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2295 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2296 srcTexture->height());
2297 this->setRenderTarget(dstTexture->asRenderTarget());
2298 SkRect dstRect(srcRect);
2299 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2300 i < scaleFactorY ? 0.5f : 1.0f);
2301 paint.setTexture(0, srcTexture);
2302 this->drawRectToRect(paint, dstRect, srcRect);
2303 srcRect = dstRect;
2304 SkTSwap(srcTexture, dstTexture);
2305 // If temp2 is non-NULL, don't render back to origTexture
2306 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2307 }
2308
2309 if (sigmaX > 0.0f) {
2310 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2311 float* kernelX = kernelStorageX.get();
2312 build_kernel(sigmaX, kernelX, kernelWidthX);
2313
2314 if (scaleFactorX > 1) {
2315 // Clear out a halfWidth to the right of the srcRect to prevent the
2316 // X convolution from reading garbage.
2317 clearRect = SkIRect::MakeXYWH(
2318 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2319 this->clear(&clearRect, 0x0);
2320 }
2321
2322 this->setRenderTarget(dstTexture->asRenderTarget());
2323 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2324 GrSamplerState::kX_FilterDirection);
2325 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002326 if (temp2 && dstTexture == origTexture) {
2327 dstTexture = temp2->texture();
2328 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002329 }
2330
2331 if (sigmaY > 0.0f) {
2332 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2333 float* kernelY = kernelStorageY.get();
2334 build_kernel(sigmaY, kernelY, kernelWidthY);
2335
2336 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2337 // Clear out a halfWidth below the srcRect to prevent the Y
2338 // convolution from reading garbage.
2339 clearRect = SkIRect::MakeXYWH(
2340 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2341 this->clear(&clearRect, 0x0);
2342 }
2343
2344 this->setRenderTarget(dstTexture->asRenderTarget());
2345 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2346 GrSamplerState::kY_FilterDirection);
2347 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002348 if (temp2 && dstTexture == origTexture) {
2349 dstTexture = temp2->texture();
2350 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002351 }
2352
2353 if (scaleFactorX > 1 || scaleFactorY > 1) {
2354 // Clear one pixel to the right and below, to accommodate bilinear
2355 // upsampling.
2356 clearRect = SkIRect::MakeXYWH(
2357 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2358 this->clear(&clearRect, 0x0);
2359 clearRect = SkIRect::MakeXYWH(
2360 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2361 this->clear(&clearRect, 0x0);
2362 // FIXME: This should be mitchell, not bilinear.
2363 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2364 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2365 srcTexture->height());
2366 this->setRenderTarget(dstTexture->asRenderTarget());
2367 paint.setTexture(0, srcTexture);
2368 SkRect dstRect(srcRect);
2369 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2370 this->drawRectToRect(paint, dstRect, srcRect);
2371 srcRect = dstRect;
2372 SkTSwap(srcTexture, dstTexture);
2373 }
2374 this->setRenderTarget(oldRenderTarget);
2375 this->setClip(oldClip);
2376 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002377}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002378
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002379GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2380 const GrRect& rect,
2381 GrTexture* temp1, GrTexture* temp2,
2382 GrSamplerState::Filter filter,
2383 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002384 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002385 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2386 GrAutoMatrix avm(this, GrMatrix::I());
2387 GrClip oldClip = this->getClip();
2388 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2389 if (radius.fWidth > 0) {
2390 this->setRenderTarget(temp1->asRenderTarget());
2391 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2392 GrSamplerState::kX_FilterDirection);
2393 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2394 rect.width(), radius.fHeight);
2395 this->clear(&clearRect, 0x0);
2396 srcTexture = temp1;
2397 }
2398 if (radius.fHeight > 0) {
2399 this->setRenderTarget(temp2->asRenderTarget());
2400 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2401 GrSamplerState::kY_FilterDirection);
2402 srcTexture = temp2;
2403 }
2404 this->setRenderTarget(oldRenderTarget);
2405 this->setClip(oldClip);
2406 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002407}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002408
2409///////////////////////////////////////////////////////////////////////////////