blob: a434237bc8b14e4929a03ba147ccee5023cb39fa [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 +00001271namespace {
1272
bsalomon@google.com93c96602012-04-27 13:05:21 +00001273struct CircleVertex {
1274 GrPoint fPos;
1275 GrPoint fCenter;
1276 GrScalar fOuterRadius;
1277 GrScalar fInnerRadius;
1278};
1279
1280/* Returns true if will map a circle to another circle. This can be true
1281 * if the matrix only includes square-scale, rotation, translation.
1282 */
1283inline bool isSimilarityTransformation(const SkMatrix& matrix,
1284 SkScalar tol = SK_ScalarNearlyZero) {
1285 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1286 return true;
1287 }
1288 if (matrix.hasPerspective()) {
1289 return false;
1290 }
1291
1292 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1293 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1294 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1295 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1296
1297 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1298 return false;
1299 }
1300
1301 // it has scales or skews, but it could also be rotation, check it out.
1302 SkVector vec[2];
1303 vec[0].set(mx, sx);
1304 vec[1].set(sy, my);
1305
1306 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1307 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1308 SkScalarSquare(tol));
1309}
1310
1311}
1312
1313// TODO: strokeWidth can't be larger than zero right now.
1314// It will be fixed when drawPath() can handle strokes.
1315void GrContext::drawOval(const GrPaint& paint,
1316 const GrRect& rect,
1317 SkScalar strokeWidth) {
1318 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1319 kUnbuffered_DrawCategory;
1320 GrDrawTarget* target = this->prepareToDraw(paint, category);
1321 GrDrawState* drawState = target->drawState();
1322 GrMatrix vm = drawState->getViewMatrix();
1323
1324 if (!isSimilarityTransformation(vm) ||
1325 !paint.fAntiAlias ||
1326 rect.height() != rect.width()) {
1327 SkPath path;
1328 path.addOval(rect);
1329 GrPathFill fill = (strokeWidth == 0) ?
1330 kHairLine_PathFill : kWinding_PathFill;
1331 this->internalDrawPath(paint, path, fill, NULL);
1332 return;
1333 }
1334
1335 const GrRenderTarget* rt = drawState->getRenderTarget();
1336 if (NULL == rt) {
1337 return;
1338 }
1339
1340 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1341
1342 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1343 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1344 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1345
1346 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1347 GrScalar radius = SkScalarHalf(rect.width());
1348
1349 vm.mapPoints(&center, 1);
1350 radius = vm.mapRadius(radius);
1351
1352 GrScalar outerRadius = radius;
1353 GrScalar innerRadius = 0;
1354 SkScalar halfWidth = 0;
1355 if (strokeWidth == 0) {
1356 halfWidth = SkScalarHalf(SK_Scalar1);
1357
1358 outerRadius += halfWidth;
1359 innerRadius = SkMaxScalar(0, radius - halfWidth);
1360 }
1361
1362 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1363 if (!geo.succeeded()) {
1364 GrPrintf("Failed to get space for vertices!\n");
1365 return;
1366 }
1367
1368 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1369
1370 SkScalar L = center.fX - outerRadius;
1371 SkScalar R = center.fX + outerRadius;
1372 SkScalar T = center.fY - outerRadius;
1373 SkScalar B = center.fY + outerRadius;
1374
1375 verts[0].fPos = SkPoint::Make(L, T);
1376 verts[1].fPos = SkPoint::Make(R, T);
1377 verts[2].fPos = SkPoint::Make(L, B);
1378 verts[3].fPos = SkPoint::Make(R, B);
1379
1380 for (int i = 0; i < 4; ++i) {
1381 // this goes to fragment shader, it should be in y-points-up space.
1382 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1383
1384 verts[i].fOuterRadius = outerRadius;
1385 verts[i].fInnerRadius = innerRadius;
1386 }
1387
1388 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1389 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001390}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001392void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001393 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001394
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001395 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001396 if (GrIsFillInverted(fill)) {
1397 this->drawPaint(paint);
1398 }
1399 return;
1400 }
1401
bsalomon@google.com93c96602012-04-27 13:05:21 +00001402 SkRect ovalRect;
1403 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1404 if (translate) {
1405 ovalRect.offset(*translate);
1406 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001407 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001408 this->drawOval(paint, ovalRect, width);
1409 return;
1410 }
1411
1412 internalDrawPath(paint, path, fill, translate);
1413}
1414
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001415void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001416 GrPathFill fill, const GrPoint* translate) {
1417
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001418 // Note that below we may sw-rasterize the path into a scratch texture.
1419 // Scratch textures can be recycled after they are returned to the texture
1420 // cache. This presents a potential hazard for buffered drawing. However,
1421 // the writePixels that uploads to the scratch will perform a flush so we're
1422 // OK.
1423 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1424 kUnbuffered_DrawCategory;
1425 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001426 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001427
bsalomon@google.com289533a2011-10-27 12:34:25 +00001428 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1429
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001430 // An Assumption here is that path renderer would use some form of tweaking
1431 // the src color (either the input alpha or in the frag shader) to implement
1432 // aa. If we have some future driver-mojo path AA that can do the right
1433 // thing WRT to the blend then we'll need some query on the PR.
1434 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001435#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001436 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001437#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001438 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001439 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001440
robertphillips@google.comed4155d2012-05-01 14:30:24 +00001441 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA);
bsalomon@google.com30085192011-08-19 15:42:31 +00001442 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001443#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001444 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001445#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001446 return;
1447 }
1448
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001449 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001450}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001451
bsalomon@google.com27847de2011-02-22 20:59:41 +00001452////////////////////////////////////////////////////////////////////////////////
1453
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001454void GrContext::flush(int flagsBitfield) {
1455 if (kDiscard_FlushBit & flagsBitfield) {
1456 fDrawBuffer->reset();
1457 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001458 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001459 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001460 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461 fGpu->forceRenderTargetFlush();
1462 }
1463}
1464
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001466 if (fDrawBuffer) {
bsalomon@google.com97805382012-03-13 14:32:07 +00001467 fDrawBuffer->flushTo(fGpu);
junov@google.com53a55842011-06-08 22:55:10 +00001468 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469}
1470
bsalomon@google.com6f379512011-11-16 20:36:03 +00001471void GrContext::internalWriteTexturePixels(GrTexture* texture,
1472 int left, int top,
1473 int width, int height,
1474 GrPixelConfig config,
1475 const void* buffer,
1476 size_t rowBytes,
1477 uint32_t flags) {
1478 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001479 ASSERT_OWNED_RESOURCE(texture);
1480
bsalomon@google.com6f379512011-11-16 20:36:03 +00001481 if (!(kDontFlush_PixelOpsFlag & flags)) {
1482 this->flush();
1483 }
1484 // TODO: use scratch texture to perform conversion
1485 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1486 GrPixelConfigIsUnpremultiplied(config)) {
1487 return;
1488 }
1489
1490 fGpu->writeTexturePixels(texture, left, top, width, height,
1491 config, buffer, rowBytes);
1492}
1493
1494bool GrContext::internalReadTexturePixels(GrTexture* texture,
1495 int left, int top,
1496 int width, int height,
1497 GrPixelConfig config,
1498 void* buffer,
1499 size_t rowBytes,
1500 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001501 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001502 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001503
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001504 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001505 GrRenderTarget* target = texture->asRenderTarget();
1506 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001507 return this->internalReadRenderTargetPixels(target,
1508 left, top, width, height,
1509 config, buffer, rowBytes,
1510 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001511 } else {
1512 return false;
1513 }
1514}
1515
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001516#include "SkConfig8888.h"
1517
1518namespace {
1519/**
1520 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1521 * formats are representable as Config8888 and so the function returns false
1522 * if the GrPixelConfig has no equivalent Config8888.
1523 */
1524bool grconfig_to_config8888(GrPixelConfig config,
1525 SkCanvas::Config8888* config8888) {
1526 switch (config) {
1527 case kRGBA_8888_PM_GrPixelConfig:
1528 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1529 return true;
1530 case kRGBA_8888_UPM_GrPixelConfig:
1531 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1532 return true;
1533 case kBGRA_8888_PM_GrPixelConfig:
1534 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1535 return true;
1536 case kBGRA_8888_UPM_GrPixelConfig:
1537 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1538 return true;
1539 default:
1540 return false;
1541 }
1542}
1543}
1544
bsalomon@google.com6f379512011-11-16 20:36:03 +00001545bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1546 int left, int top,
1547 int width, int height,
1548 GrPixelConfig config,
1549 void* buffer,
1550 size_t rowBytes,
1551 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001552 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001553 ASSERT_OWNED_RESOURCE(target);
1554
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001555 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001556 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001557 if (NULL == target) {
1558 return false;
1559 }
1560 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001561
bsalomon@google.com6f379512011-11-16 20:36:03 +00001562 if (!(kDontFlush_PixelOpsFlag & flags)) {
1563 this->flush();
1564 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001565
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001566 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1567 GrPixelConfigIsUnpremultiplied(config) &&
1568 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1569 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1570 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1571 !grconfig_to_config8888(config, &dstConfig8888)) {
1572 return false;
1573 }
1574 // do read back using target's own config
1575 this->internalReadRenderTargetPixels(target,
1576 left, top,
1577 width, height,
1578 target->config(),
1579 buffer, rowBytes,
1580 kDontFlush_PixelOpsFlag);
1581 // sw convert the pixels to unpremul config
1582 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1583 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1584 pixels, rowBytes, srcConfig8888,
1585 width, height);
1586 return true;
1587 }
1588
bsalomon@google.comc4364992011-11-07 15:54:49 +00001589 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001590 bool swapRAndB = NULL != src &&
1591 fGpu->preferredReadPixelsConfig(config) ==
1592 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001593
1594 bool flipY = NULL != src &&
1595 fGpu->readPixelsWillPayForYFlip(target, left, top,
1596 width, height, config,
1597 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001598 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1599 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001600
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001601 if (NULL == src && alphaConversion) {
1602 // we should fallback to cpu conversion here. This could happen when
1603 // we were given an external render target by the client that is not
1604 // also a texture (e.g. FBO 0 in GL)
1605 return false;
1606 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001607 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001608 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001609 if (flipY || swapRAndB || alphaConversion) {
1610 GrAssert(NULL != src);
1611 if (swapRAndB) {
1612 config = GrPixelConfigSwapRAndB(config);
1613 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001614 }
1615 // Make the scratch a render target because we don't have a robust
1616 // readTexturePixels as of yet (it calls this function).
1617 const GrTextureDesc desc = {
1618 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001619 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001620 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001621 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001622 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001623
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001624 // When a full readback is faster than a partial we could always make
1625 // the scratch exactly match the passed rect. However, if we see many
1626 // different size rectangles we will trash our texture cache and pay the
1627 // cost of creating and destroying many textures. So, we only request
1628 // an exact match when the caller is reading an entire RT.
1629 ScratchTexMatch match = kApprox_ScratchTexMatch;
1630 if (0 == left &&
1631 0 == top &&
1632 target->width() == width &&
1633 target->height() == height &&
1634 fGpu->fullReadPixelsIsFasterThanPartial()) {
1635 match = kExact_ScratchTexMatch;
1636 }
1637 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001638 GrTexture* texture = ast.texture();
1639 if (!texture) {
1640 return false;
1641 }
1642 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001643 GrAssert(NULL != target);
1644
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001645 GrDrawTarget::AutoStateRestore asr(fGpu,
1646 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001647 GrDrawState* drawState = fGpu->drawState();
1648 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001649
bsalomon@google.comc4364992011-11-07 15:54:49 +00001650 GrMatrix matrix;
1651 if (flipY) {
1652 matrix.setTranslate(SK_Scalar1 * left,
1653 SK_Scalar1 * (top + height));
1654 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1655 } else {
1656 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1657 }
1658 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001659 drawState->sampler(0)->reset(matrix);
1660 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001661 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001662 GrRect rect;
1663 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1664 fGpu->drawSimpleRect(rect, NULL, 0x1);
1665 left = 0;
1666 top = 0;
1667 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001668 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001669 left, top, width, height,
1670 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001671}
1672
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001673void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1674 GrAssert(target);
1675 ASSERT_OWNED_RESOURCE(target);
1676 // In the future we may track whether there are any pending draws to this
1677 // target. We don't today so we always perform a flush. We don't promise
1678 // this to our clients, though.
1679 this->flush();
1680 fGpu->resolveRenderTarget(target);
1681}
1682
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001683void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1684 if (NULL == src || NULL == dst) {
1685 return;
1686 }
1687 ASSERT_OWNED_RESOURCE(src);
1688
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001689 // Writes pending to the source texture are not tracked, so a flush
1690 // is required to ensure that the copy captures the most recent contents
1691 // of the source texture. See similar behaviour in
1692 // GrContext::resolveRenderTarget.
1693 this->flush();
1694
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001695 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001696 GrDrawState* drawState = fGpu->drawState();
1697 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001698 GrMatrix sampleM;
1699 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001700 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001701 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001702 SkRect rect = SkRect::MakeXYWH(0, 0,
1703 SK_Scalar1 * src->width(),
1704 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001705 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1706}
1707
bsalomon@google.com6f379512011-11-16 20:36:03 +00001708void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1709 int left, int top,
1710 int width, int height,
1711 GrPixelConfig config,
1712 const void* buffer,
1713 size_t rowBytes,
1714 uint32_t flags) {
1715 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001716 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001717
1718 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001719 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001720 if (NULL == target) {
1721 return;
1722 }
1723 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001724
1725 // TODO: when underlying api has a direct way to do this we should use it
1726 // (e.g. glDrawPixels on desktop GL).
1727
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001728 // If the RT is also a texture and we don't have to do PM/UPM conversion
1729 // then take the texture path, which we expect to be at least as fast or
1730 // faster since it doesn't use an intermediate texture as we do below.
1731
1732#if !GR_MAC_BUILD
1733 // At least some drivers on the Mac get confused when glTexImage2D is called
1734 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1735 // determine what OS versions and/or HW is affected.
1736 if (NULL != target->asTexture() &&
1737 GrPixelConfigIsUnpremultiplied(target->config()) ==
1738 GrPixelConfigIsUnpremultiplied(config)) {
1739
1740 this->internalWriteTexturePixels(target->asTexture(),
1741 left, top, width, height,
1742 config, buffer, rowBytes, flags);
1743 return;
1744 }
1745#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001746 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1747 GrPixelConfigIsUnpremultiplied(config) &&
1748 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1749 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1750 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1751 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1752 return;
1753 }
1754 // allocate a tmp buffer and sw convert the pixels to premul
1755 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1756 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1757 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1758 src, rowBytes, srcConfig8888,
1759 width, height);
1760 // upload the already premul pixels
1761 this->internalWriteRenderTargetPixels(target,
1762 left, top,
1763 width, height,
1764 target->config(),
1765 tmpPixels, 4 * width, flags);
1766 return;
1767 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001768
1769 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1770 GrPixelConfigSwapRAndB(config);
1771 if (swapRAndB) {
1772 config = GrPixelConfigSwapRAndB(config);
1773 }
1774
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001775 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001776 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001777 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001778 GrAutoScratchTexture ast(this, desc);
1779 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001780 if (NULL == texture) {
1781 return;
1782 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001783 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1784 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001785
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001786 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001787 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001788
1789 GrMatrix matrix;
1790 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001791 drawState->setViewMatrix(matrix);
1792 drawState->setRenderTarget(target);
1793 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001794
bsalomon@google.com5c638652011-07-18 19:31:59 +00001795 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001796 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1797 GrSamplerState::kNearest_Filter,
1798 matrix);
1799 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001800
1801 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1802 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001803 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001804 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1805 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001806 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001807 return;
1808 }
1809 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1810 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1811}
1812////////////////////////////////////////////////////////////////////////////////
1813
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001814void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001815
1816 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1817 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001818 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001819 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001820 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001821 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001822 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001823 }
1824
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001825 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001826
1827 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1828 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001829 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001830 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001831 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001832 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001833 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001834 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001835
1836 // disable all stages not accessible via the paint
1837 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001838 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001839 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001840
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001841 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001842
1843 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001844 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001845 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001846 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001847 }
1848 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001849 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001850 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001851 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001852 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001853 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001854 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1855 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001856 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001857 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001858 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001859 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1860 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1861 fDrawState->setCoverage(paint.fCoverage);
bsalomon@google.come79c8152012-03-29 19:07:12 +00001862#if GR_DEBUG
1863 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001864 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001865 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1866 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001867#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868}
1869
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001870GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871 DrawCategory category) {
1872 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001873 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001874 fLastDrawCategory = category;
1875 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001876 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001877 GrDrawTarget* target = fGpu;
1878 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001879 case kUnbuffered_DrawCategory:
1880 target = fGpu;
1881 break;
1882 case kBuffered_DrawCategory:
1883 target = fDrawBuffer;
1884 fDrawBuffer->setClip(fGpu->getClip());
1885 break;
1886 default:
1887 GrCrash("Unexpected DrawCategory.");
1888 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889 }
1890 return target;
1891}
1892
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001893GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001894 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001895 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001896 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001897 if (NULL == fPathRendererChain) {
1898 fPathRendererChain =
1899 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1900 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001901 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001902}
1903
bsalomon@google.com27847de2011-02-22 20:59:41 +00001904////////////////////////////////////////////////////////////////////////////////
1905
bsalomon@google.com27847de2011-02-22 20:59:41 +00001906void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001907 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001908 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001909 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001910 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001911 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001912}
1913
1914GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001915 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001916}
1917
1918const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001919 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001920}
1921
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001922bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1923 return fGpu->isConfigRenderable(config);
1924}
1925
bsalomon@google.com27847de2011-02-22 20:59:41 +00001926const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001927 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001928}
1929
1930void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001931 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001932}
1933
1934void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001935 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001936}
1937
1938static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1939 intptr_t mask = 1 << shift;
1940 if (pred) {
1941 bits |= mask;
1942 } else {
1943 bits &= ~mask;
1944 }
1945 return bits;
1946}
1947
1948void GrContext::resetStats() {
1949 fGpu->resetStats();
1950}
1951
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001952const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001953 return fGpu->getStats();
1954}
1955
1956void GrContext::printStats() const {
1957 fGpu->printStats();
1958}
1959
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001960GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001961 fGpu = gpu;
1962 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001963 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001964
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001965 fDrawState = new GrDrawState();
1966 fGpu->setDrawState(fDrawState);
1967
bsalomon@google.com30085192011-08-19 15:42:31 +00001968 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001969
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001970 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1971 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001972 fFontCache = new GrFontCache(fGpu);
1973
1974 fLastDrawCategory = kUnbuffered_DrawCategory;
1975
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001976 fDrawBuffer = NULL;
1977 fDrawBufferVBAllocPool = NULL;
1978 fDrawBufferIBAllocPool = NULL;
1979
bsalomon@google.com205d4602011-04-25 12:43:45 +00001980 fAAFillRectIndexBuffer = NULL;
1981 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001982
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001983 this->setupDrawBuffer();
1984}
1985
1986void GrContext::setupDrawBuffer() {
1987
1988 GrAssert(NULL == fDrawBuffer);
1989 GrAssert(NULL == fDrawBufferVBAllocPool);
1990 GrAssert(NULL == fDrawBufferIBAllocPool);
1991
bsalomon@google.com92edd312012-04-04 21:40:21 +00001992#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001993 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001994 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001995 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1996 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001997 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001998 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001999 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002000 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2001
bsalomon@google.com471d4712011-08-23 15:45:25 +00002002 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2003 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002004 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002005#endif
2006
2007#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002008 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002009#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002010 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002011 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002012}
2013
bsalomon@google.com27847de2011-02-22 20:59:41 +00002014GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002015#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002016 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002017#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002018 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002019#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002020}
2021
2022const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2023 return fGpu->getQuadIndexBuffer();
2024}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002025
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002026GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2027 GrAutoScratchTexture* temp1,
2028 GrAutoScratchTexture* temp2,
2029 const SkRect& rect,
2030 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002031 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002032 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2033 GrClip oldClip = this->getClip();
2034 GrTexture* origTexture = srcTexture;
2035 GrAutoMatrix avm(this, GrMatrix::I());
2036 SkIRect clearRect;
2037 int scaleFactorX, halfWidthX, kernelWidthX;
2038 int scaleFactorY, halfWidthY, kernelWidthY;
2039 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2040 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002041
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002042 SkRect srcRect(rect);
2043 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2044 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002045 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2046 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002047 this->setClip(srcRect);
2048
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002049 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2050 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2051 kAlpha_8_GrPixelConfig == srcTexture->config());
2052
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002053 const GrTextureDesc desc = {
2054 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002055 SkScalarFloorToInt(srcRect.width()),
2056 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002057 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002058 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002059 };
2060
2061 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002062 if (temp2) {
2063 temp2->set(this, desc);
2064 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002065
2066 GrTexture* dstTexture = temp1->texture();
2067 GrPaint paint;
2068 paint.reset();
2069 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2070
2071 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2072 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2073 srcTexture->height());
2074 this->setRenderTarget(dstTexture->asRenderTarget());
2075 SkRect dstRect(srcRect);
2076 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2077 i < scaleFactorY ? 0.5f : 1.0f);
2078 paint.setTexture(0, srcTexture);
2079 this->drawRectToRect(paint, dstRect, srcRect);
2080 srcRect = dstRect;
2081 SkTSwap(srcTexture, dstTexture);
2082 // If temp2 is non-NULL, don't render back to origTexture
2083 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2084 }
2085
2086 if (sigmaX > 0.0f) {
2087 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2088 float* kernelX = kernelStorageX.get();
2089 build_kernel(sigmaX, kernelX, kernelWidthX);
2090
2091 if (scaleFactorX > 1) {
2092 // Clear out a halfWidth to the right of the srcRect to prevent the
2093 // X convolution from reading garbage.
2094 clearRect = SkIRect::MakeXYWH(
2095 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
2096 this->clear(&clearRect, 0x0);
2097 }
2098
2099 this->setRenderTarget(dstTexture->asRenderTarget());
2100 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2101 GrSamplerState::kX_FilterDirection);
2102 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002103 if (temp2 && dstTexture == origTexture) {
2104 dstTexture = temp2->texture();
2105 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002106 }
2107
2108 if (sigmaY > 0.0f) {
2109 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2110 float* kernelY = kernelStorageY.get();
2111 build_kernel(sigmaY, kernelY, kernelWidthY);
2112
2113 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2114 // Clear out a halfWidth below the srcRect to prevent the Y
2115 // convolution from reading garbage.
2116 clearRect = SkIRect::MakeXYWH(
2117 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
2118 this->clear(&clearRect, 0x0);
2119 }
2120
2121 this->setRenderTarget(dstTexture->asRenderTarget());
2122 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2123 GrSamplerState::kY_FilterDirection);
2124 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002125 if (temp2 && dstTexture == origTexture) {
2126 dstTexture = temp2->texture();
2127 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002128 }
2129
2130 if (scaleFactorX > 1 || scaleFactorY > 1) {
2131 // Clear one pixel to the right and below, to accommodate bilinear
2132 // upsampling.
2133 clearRect = SkIRect::MakeXYWH(
2134 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
2135 this->clear(&clearRect, 0x0);
2136 clearRect = SkIRect::MakeXYWH(
2137 srcRect.fRight, srcRect.fTop, 1, srcRect.height());
2138 this->clear(&clearRect, 0x0);
2139 // FIXME: This should be mitchell, not bilinear.
2140 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2141 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2142 srcTexture->height());
2143 this->setRenderTarget(dstTexture->asRenderTarget());
2144 paint.setTexture(0, srcTexture);
2145 SkRect dstRect(srcRect);
2146 scale_rect(&dstRect, scaleFactorX, scaleFactorY);
2147 this->drawRectToRect(paint, dstRect, srcRect);
2148 srcRect = dstRect;
2149 SkTSwap(srcTexture, dstTexture);
2150 }
2151 this->setRenderTarget(oldRenderTarget);
2152 this->setClip(oldClip);
2153 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002154}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002155
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002156GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2157 const GrRect& rect,
2158 GrTexture* temp1, GrTexture* temp2,
2159 GrSamplerState::Filter filter,
2160 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002161 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002162 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2163 GrAutoMatrix avm(this, GrMatrix::I());
2164 GrClip oldClip = this->getClip();
2165 this->setClip(GrRect::MakeWH(srcTexture->width(), srcTexture->height()));
2166 if (radius.fWidth > 0) {
2167 this->setRenderTarget(temp1->asRenderTarget());
2168 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2169 GrSamplerState::kX_FilterDirection);
2170 SkIRect clearRect = SkIRect::MakeXYWH(rect.fLeft, rect.fBottom,
2171 rect.width(), radius.fHeight);
2172 this->clear(&clearRect, 0x0);
2173 srcTexture = temp1;
2174 }
2175 if (radius.fHeight > 0) {
2176 this->setRenderTarget(temp2->asRenderTarget());
2177 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2178 GrSamplerState::kY_FilterDirection);
2179 srcTexture = temp2;
2180 }
2181 this->setRenderTarget(oldRenderTarget);
2182 this->setClip(oldClip);
2183 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002184}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002185
2186///////////////////////////////////////////////////////////////////////////////