blob: 8d5b88f4b38c2bbecb2106d3d920afd3b9df2b6a [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"
tomhudson@google.comd8f856c2012-05-10 12:13:36 +000014#include "effects/GrConvolutionEffect.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000015#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrIndexBuffer.h"
17#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000018#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000019#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000020#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000021#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000022#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000023#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000024#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000025
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000026#define DEFER_TEXT_RENDERING 1
bsalomon@google.com27847de2011-02-22 20:59:41 +000027
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000028#define DEFER_PATHS 1
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000029
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000030#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
bsalomon@google.com27847de2011-02-22 20:59:41 +000031
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000032#define MAX_BLUR_SIGMA 4.0f
33
bsalomon@google.comd46e2422011-09-23 17:40:07 +000034// When we're using coverage AA but the blend is incompatible (given gpu
35// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000036#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000037
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000038static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
39static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000040
bsalomon@google.com60361492012-03-15 17:47:06 +000041static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000042static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
43
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000044// path rendering is the only thing we defer today that uses non-static indices
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000047
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000073 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com30085192011-08-19 15:42:31 +000086 // a path renderer may be holding onto resources that
87 // are now unusable
88 GrSafeSetNull(fPathRendererChain);
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 delete fDrawBuffer;
91 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000092
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 delete fDrawBufferVBAllocPool;
94 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000095
bsalomon@google.com8fe72472011-03-30 21:26:44 +000096 delete fDrawBufferIBAllocPool;
97 fDrawBufferIBAllocPool = NULL;
98
bsalomon@google.com205d4602011-04-25 12:43:45 +000099 GrSafeSetNull(fAAFillRectIndexBuffer);
100 GrSafeSetNull(fAAStrokeRectIndexBuffer);
101
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102 fTextureCache->removeAll();
103 fFontCache->freeAll();
104 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105}
106
107void GrContext::resetContext() {
108 fGpu->markContextDirty();
109}
110
111void GrContext::freeGpuResources() {
112 this->flush();
113 fTextureCache->removeAll();
114 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000115 // a path renderer may be holding onto resources
116 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000117}
118
twiz@google.com05e70242012-01-27 19:12:00 +0000119size_t GrContext::getGpuTextureCacheBytes() const {
120 return fTextureCache->getCachedResourceBytes();
121}
122
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000123////////////////////////////////////////////////////////////////////////////////
124
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000125int GrContext::PaintStageVertexLayoutBits(
126 const GrPaint& paint,
127 const bool hasTexCoords[GrPaint::kTotalStages]) {
128 int stageMask = paint.getActiveStageMask();
129 int layout = 0;
130 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
131 if ((1 << i) & stageMask) {
132 if (NULL != hasTexCoords && hasTexCoords[i]) {
133 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
134 } else {
135 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
136 }
137 }
138 }
139 return layout;
140}
141
142
143////////////////////////////////////////////////////////////////////////////////
144
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000145enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000146 // flags for textures
147 kNPOTBit = 0x1,
148 kFilterBit = 0x2,
149 kScratchBit = 0x4,
150
151 // resource type
152 kTextureBit = 0x8,
153 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000154};
155
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000156GrTexture* GrContext::TextureCacheEntry::texture() const {
157 if (NULL == fEntry) {
158 return NULL;
159 } else {
160 return (GrTexture*) fEntry->resource();
161 }
162}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000163
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000164namespace {
165// returns true if this is a "special" texture because of gpu NPOT limitations
166bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000167 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000168 GrContext::TextureKey clientKey,
169 int width,
170 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000171 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000172 bool scratch,
173 uint32_t v[4]) {
174 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
175 // we assume we only need 16 bits of width and height
176 // assert that texture creation will fail anyway if this assumption
177 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000178 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000179 v[0] = clientKey & 0xffffffffUL;
180 v[1] = (clientKey >> 32) & 0xffffffffUL;
181 v[2] = width | (height << 16);
182
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000183 v[3] = (sampleCnt << 24);
184 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
185
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000186 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000187 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
188
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000189 bool tiled = NULL != sampler &&
190 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
191 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000192
193 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000195 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000197 }
198 }
199 }
200
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000201 if (scratch) {
202 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000203 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000204
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000205 v[3] |= kTextureBit;
206
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000207 return v[3] & kNPOTBit;
208}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000209
210// we should never have more than one stencil buffer with same combo of
211// (width,height,samplecount)
212void gen_stencil_key_values(int width, int height,
213 int sampleCnt, uint32_t v[4]) {
214 v[0] = width;
215 v[1] = height;
216 v[2] = sampleCnt;
217 v[3] = kStencilBufferBit;
218}
219
220void gen_stencil_key_values(const GrStencilBuffer* sb,
221 uint32_t v[4]) {
222 gen_stencil_key_values(sb->width(), sb->height(),
223 sb->numSamples(), v);
224}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000225
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000226void build_kernel(float sigma, float* kernel, int kernelWidth) {
227 int halfWidth = (kernelWidth - 1) / 2;
228 float sum = 0.0f;
229 float denom = 1.0f / (2.0f * sigma * sigma);
230 for (int i = 0; i < kernelWidth; ++i) {
231 float x = static_cast<float>(i - halfWidth);
232 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
233 // is dropped here, since we renormalize the kernel below.
234 kernel[i] = sk_float_exp(- x * x * denom);
235 sum += kernel[i];
236 }
237 // Normalize the kernel
238 float scale = 1.0f / sum;
239 for (int i = 0; i < kernelWidth; ++i)
240 kernel[i] *= scale;
241}
242
243void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000244 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
245 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
246 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
247 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000248}
249
250float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
251 int *kernelWidth) {
252 *scaleFactor = 1;
253 while (sigma > MAX_BLUR_SIGMA) {
254 *scaleFactor *= 2;
255 sigma *= 0.5f;
256 }
257 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
258 *kernelWidth = *halfWidth * 2 + 1;
259 return sigma;
260}
261
262void apply_morphology(GrGpu* gpu,
263 GrTexture* texture,
264 const SkRect& rect,
265 int radius,
266 GrSamplerState::Filter filter,
267 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000268 GrAssert(filter == GrSamplerState::kErode_Filter ||
269 filter == GrSamplerState::kDilate_Filter);
270
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000271 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
272 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000273 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000274 drawState->setRenderTarget(target);
275 GrMatrix sampleM;
276 sampleM.setIDiv(texture->width(), texture->height());
277 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
278 sampleM);
279 drawState->sampler(0)->setMorphologyRadius(radius);
280 drawState->sampler(0)->setFilterDirection(direction);
281 drawState->setTexture(0, texture);
282 gpu->drawSimpleRect(rect, NULL, 1 << 0);
283}
284
285void convolve(GrGpu* gpu,
286 GrTexture* texture,
287 const SkRect& rect,
288 const float* kernel,
289 int kernelWidth,
290 GrSamplerState::FilterDirection direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000291 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
292 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000293 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000294 drawState->setRenderTarget(target);
295 GrMatrix sampleM;
296 sampleM.setIDiv(texture->width(), texture->height());
297 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
298 GrSamplerState::kConvolution_Filter,
299 sampleM);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000300 drawState->sampler(0)->setCustomStage(
301 new GrConvolutionEffect(direction, kernelWidth, kernel));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000302 drawState->setTexture(0, texture);
303 gpu->drawSimpleRect(rect, NULL, 1 << 0);
304}
305
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000306}
307
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000308GrContext::TextureCacheEntry GrContext::findAndLockTexture(
309 TextureKey key,
310 int width,
311 int height,
312 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000313 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000314 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000315 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000316 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
317 GrResourceCache::kNested_LockType));
318}
319
bsalomon@google.comfb309512011-11-30 14:13:48 +0000320bool GrContext::isTextureInCache(TextureKey key,
321 int width,
322 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000323 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000324 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000325 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000326 GrResourceKey resourceKey(v);
327 return fTextureCache->hasKey(resourceKey);
328}
329
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000330GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000331 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000332 uint32_t v[4];
333 gen_stencil_key_values(sb, v);
334 GrResourceKey resourceKey(v);
335 return fTextureCache->createAndLock(resourceKey, sb);
336}
337
338GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
339 int sampleCnt) {
340 uint32_t v[4];
341 gen_stencil_key_values(width, height, sampleCnt, v);
342 GrResourceKey resourceKey(v);
343 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
344 GrResourceCache::kSingle_LockType);
345 if (NULL != entry) {
346 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
347 return sb;
348 } else {
349 return NULL;
350 }
351}
352
353void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000354 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000355 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000356}
357
358static void stretchImage(void* dst,
359 int dstW,
360 int dstH,
361 void* src,
362 int srcW,
363 int srcH,
364 int bpp) {
365 GrFixed dx = (srcW << 16) / dstW;
366 GrFixed dy = (srcH << 16) / dstH;
367
368 GrFixed y = dy >> 1;
369
370 int dstXLimit = dstW*bpp;
371 for (int j = 0; j < dstH; ++j) {
372 GrFixed x = dx >> 1;
373 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
374 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
375 for (int i = 0; i < dstXLimit; i += bpp) {
376 memcpy((uint8_t*) dstRow + i,
377 (uint8_t*) srcRow + (x>>16)*bpp,
378 bpp);
379 x += dx;
380 }
381 y += dy;
382 }
383}
384
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000385GrContext::TextureCacheEntry GrContext::createAndLockTexture(
386 TextureKey key,
387 const GrSamplerState* sampler,
388 const GrTextureDesc& desc,
389 void* srcData,
390 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000391 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000392
393#if GR_DUMP_TEXTURE_UPLOAD
394 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
395#endif
396
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000397 TextureCacheEntry entry;
398 uint32_t v[4];
399 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000400 desc.fWidth, desc.fHeight,
401 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000402 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000403
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000404 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000405 GrAssert(NULL != sampler);
406 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
407 desc.fWidth,
408 desc.fHeight,
409 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000410
411 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000412 clampEntry = this->createAndLockTexture(key, NULL, desc,
413 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 GrAssert(NULL != clampEntry.texture());
415 if (NULL == clampEntry.texture()) {
416 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000417 }
418 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000419 GrTextureDesc rtDesc = desc;
420 rtDesc.fFlags = rtDesc.fFlags |
421 kRenderTarget_GrTextureFlagBit |
422 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000423 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
424 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000425
426 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
427
428 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000429 GrDrawTarget::AutoStateRestore asr(fGpu,
430 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000431 GrDrawState* drawState = fGpu->drawState();
432 drawState->setRenderTarget(texture->asRenderTarget());
433 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000434
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000435 GrSamplerState::Filter filter;
436 // if filtering is not desired then we want to ensure all
437 // texels in the resampled image are copies of texels from
438 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000439 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000440 filter = GrSamplerState::kNearest_Filter;
441 } else {
442 filter = GrSamplerState::kBilinear_Filter;
443 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000444 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
445 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000446
447 static const GrVertexLayout layout =
448 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
449 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
450
451 if (arg.succeeded()) {
452 GrPoint* verts = (GrPoint*) arg.vertices();
453 verts[0].setIRectFan(0, 0,
454 texture->width(),
455 texture->height(),
456 2*sizeof(GrPoint));
457 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
458 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
459 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000460 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000461 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000462 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000463 } else {
464 // TODO: Our CPU stretch doesn't filter. But we create separate
465 // stretched textures when the sampler state is either filtered or
466 // not. Either implement filtered stretch blit on CPU or just create
467 // one when FBO case fails.
468
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000469 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000470 // no longer need to clamp at min RT size.
471 rtDesc.fWidth = GrNextPow2(desc.fWidth);
472 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000473 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000474 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000475 rtDesc.fWidth *
476 rtDesc.fHeight);
477 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
478 srcData, desc.fWidth, desc.fHeight, bpp);
479
480 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
481
482 GrTexture* texture = fGpu->createTexture(rtDesc,
483 stretchedPixels.get(),
484 stretchedRowBytes);
485 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000486 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000487 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000488 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000489
490 } else {
491 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
492 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000493 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000494 }
495 }
496 return entry;
497}
498
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000499namespace {
500inline void gen_scratch_tex_key_values(const GrGpu* gpu,
501 const GrTextureDesc& desc,
502 uint32_t v[4]) {
503 // Instead of a client-provided key of the texture contents
504 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000505 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000506 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000507 // this code path isn't friendly to tiling with NPOT restricitons
508 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000509 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000510 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000511}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000512}
513
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000514GrContext::TextureCacheEntry GrContext::lockScratchTexture(
515 const GrTextureDesc& inDesc,
516 ScratchTexMatch match) {
517
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000518 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000519 if (kExact_ScratchTexMatch != match) {
520 // bin by pow2 with a reasonable min
521 static const int MIN_SIZE = 256;
522 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
523 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
524 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000525
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000526 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000527 int origWidth = desc.fWidth;
528 int origHeight = desc.fHeight;
529 bool doubledW = false;
530 bool doubledH = false;
531
532 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000533 uint32_t v[4];
534 gen_scratch_tex_key_values(fGpu, desc, v);
535 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000536 entry = fTextureCache->findAndLock(key,
537 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000538 // if we miss, relax the fit of the flags...
539 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000540 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000541 break;
542 }
543 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
544 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
545 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
546 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
547 } else if (!doubledW) {
548 desc.fFlags = inDesc.fFlags;
549 desc.fWidth *= 2;
550 doubledW = true;
551 } else if (!doubledH) {
552 desc.fFlags = inDesc.fFlags;
553 desc.fWidth = origWidth;
554 desc.fHeight *= 2;
555 doubledH = true;
556 } else {
557 break;
558 }
559
560 } while (true);
561
562 if (NULL == entry) {
563 desc.fFlags = inDesc.fFlags;
564 desc.fWidth = origWidth;
565 desc.fHeight = origHeight;
566 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
567 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000568 uint32_t v[4];
569 gen_scratch_tex_key_values(fGpu, desc, v);
570 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000571 entry = fTextureCache->createAndLock(key, texture);
572 }
573 }
574
575 // If the caller gives us the same desc/sampler twice we don't want
576 // to return the same texture the second time (unless it was previously
577 // released). So we detach the entry from the cache and reattach at release.
578 if (NULL != entry) {
579 fTextureCache->detach(entry);
580 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000581 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000582}
583
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000584void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000585 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000586 // If this is a scratch texture we detached it from the cache
587 // while it was locked (to avoid two callers simultaneously getting
588 // the same texture).
589 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
590 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000591 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000592 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000593 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000594}
595
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000596GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000597 void* srcData,
598 size_t rowBytes) {
599 return fGpu->createTexture(desc, srcData, rowBytes);
600}
601
602void GrContext::getTextureCacheLimits(int* maxTextures,
603 size_t* maxTextureBytes) const {
604 fTextureCache->getLimits(maxTextures, maxTextureBytes);
605}
606
607void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
608 fTextureCache->setLimits(maxTextures, maxTextureBytes);
609}
610
bsalomon@google.com91958362011-06-13 17:58:13 +0000611int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000612 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000613}
614
615int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000616 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000617}
618
619///////////////////////////////////////////////////////////////////////////////
620
bsalomon@google.come269f212011-11-07 13:29:52 +0000621GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
622 return fGpu->createPlatformTexture(desc);
623}
624
625GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
626 return fGpu->createPlatformRenderTarget(desc);
627}
628
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000629///////////////////////////////////////////////////////////////////////////////
630
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000631bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000632 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000633 const GrDrawTarget::Caps& caps = fGpu->getCaps();
634 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000635 return false;
636 }
637
bsalomon@google.com27847de2011-02-22 20:59:41 +0000638 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
639
640 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000641 bool tiled = NULL != sampler &&
642 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
643 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000644 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000645 return false;
646 }
647 }
648 return true;
649}
650
651////////////////////////////////////////////////////////////////////////////////
652
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000653const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
654
bsalomon@google.com27847de2011-02-22 20:59:41 +0000655void GrContext::setClip(const GrClip& clip) {
656 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000657 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000658}
659
660void GrContext::setClip(const GrIRect& rect) {
661 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000662 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000663 fGpu->setClip(clip);
664}
665
666////////////////////////////////////////////////////////////////////////////////
667
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000668void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000669 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000670 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000671}
672
673void GrContext::drawPaint(const GrPaint& paint) {
674 // set rect to be big enough to fill the space, but not super-huge, so we
675 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000676 GrRect r;
677 r.setLTRB(0, 0,
678 GrIntToScalar(getRenderTarget()->width()),
679 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000680 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000681 SkTLazy<GrPaint> tmpPaint;
682 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000683 GrAutoMatrix am;
684
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000685 // We attempt to map r by the inverse matrix and draw that. mapRect will
686 // map the four corners and bound them with a new rect. This will not
687 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000688 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000689 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000690 GrPrintf("Could not invert matrix");
691 return;
692 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000693 inverse.mapRect(&r);
694 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000695 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000696 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000697 GrPrintf("Could not invert matrix");
698 return;
699 }
700 tmpPaint.set(paint);
701 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
702 p = tmpPaint.get();
703 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000704 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000705 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000706 // by definition this fills the entire clip, no need for AA
707 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000708 if (!tmpPaint.isValid()) {
709 tmpPaint.set(paint);
710 p = tmpPaint.get();
711 }
712 GrAssert(p == tmpPaint.get());
713 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000714 }
715 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000716}
717
bsalomon@google.com205d4602011-04-25 12:43:45 +0000718////////////////////////////////////////////////////////////////////////////////
719
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000720namespace {
721inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
722 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
723}
724}
725
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000726////////////////////////////////////////////////////////////////////////////////
727
bsalomon@google.com27847de2011-02-22 20:59:41 +0000728/* create a triangle strip that strokes the specified triangle. There are 8
729 unique vertices, but we repreat the last 2 to close up. Alternatively we
730 could use an indices array, and then only send 8 verts, but not sure that
731 would be faster.
732 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000733static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000734 GrScalar width) {
735 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000736 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000737
738 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
739 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
740 verts[2].set(rect.fRight - rad, rect.fTop + rad);
741 verts[3].set(rect.fRight + rad, rect.fTop - rad);
742 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
743 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
744 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
745 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
746 verts[8] = verts[0];
747 verts[9] = verts[1];
748}
749
bsalomon@google.com205d4602011-04-25 12:43:45 +0000750static void setInsetFan(GrPoint* pts, size_t stride,
751 const GrRect& r, GrScalar dx, GrScalar dy) {
752 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
753}
754
755static const uint16_t gFillAARectIdx[] = {
756 0, 1, 5, 5, 4, 0,
757 1, 2, 6, 6, 5, 1,
758 2, 3, 7, 7, 6, 2,
759 3, 0, 4, 4, 7, 3,
760 4, 5, 6, 6, 7, 4,
761};
762
763int GrContext::aaFillRectIndexCount() const {
764 return GR_ARRAY_COUNT(gFillAARectIdx);
765}
766
767GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
768 if (NULL == fAAFillRectIndexBuffer) {
769 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
770 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000771 if (NULL != fAAFillRectIndexBuffer) {
772 #if GR_DEBUG
773 bool updated =
774 #endif
775 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
776 sizeof(gFillAARectIdx));
777 GR_DEBUGASSERT(updated);
778 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000779 }
780 return fAAFillRectIndexBuffer;
781}
782
783static const uint16_t gStrokeAARectIdx[] = {
784 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
785 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
786 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
787 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
788
789 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
790 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
791 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
792 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
793
794 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
795 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
796 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
797 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
798};
799
800int GrContext::aaStrokeRectIndexCount() const {
801 return GR_ARRAY_COUNT(gStrokeAARectIdx);
802}
803
804GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
805 if (NULL == fAAStrokeRectIndexBuffer) {
806 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
807 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000808 if (NULL != fAAStrokeRectIndexBuffer) {
809 #if GR_DEBUG
810 bool updated =
811 #endif
812 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
813 sizeof(gStrokeAARectIdx));
814 GR_DEBUGASSERT(updated);
815 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000816 }
817 return fAAStrokeRectIndexBuffer;
818}
819
bsalomon@google.coma3108262011-10-10 14:08:47 +0000820static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
821 bool useCoverage) {
822 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000823 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000824 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000825 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
826 }
827 }
828 if (useCoverage) {
829 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
830 } else {
831 layout |= GrDrawTarget::kColor_VertexLayoutBit;
832 }
833 return layout;
834}
835
bsalomon@google.com205d4602011-04-25 12:43:45 +0000836void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000837 const GrRect& devRect,
838 bool useVertexCoverage) {
839 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000840
841 size_t vsize = GrDrawTarget::VertexSize(layout);
842
843 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000844 if (!geo.succeeded()) {
845 GrPrintf("Failed to get space for vertices!\n");
846 return;
847 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000848 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
849 if (NULL == indexBuffer) {
850 GrPrintf("Failed to create index buffer!\n");
851 return;
852 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000853
854 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
855
856 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
857 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
858
859 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
860 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
861
862 verts += sizeof(GrPoint);
863 for (int i = 0; i < 4; ++i) {
864 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
865 }
866
bsalomon@google.coma3108262011-10-10 14:08:47 +0000867 GrColor innerColor;
868 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000869 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000870 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000871 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000872 }
873
bsalomon@google.com205d4602011-04-25 12:43:45 +0000874 verts += 4 * vsize;
875 for (int i = 0; i < 4; ++i) {
876 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
877 }
878
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000879 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000880
881 target->drawIndexed(kTriangles_PrimitiveType, 0,
882 0, 8, this->aaFillRectIndexCount());
883}
884
bsalomon@google.coma3108262011-10-10 14:08:47 +0000885void GrContext::strokeAARect(GrDrawTarget* target,
886 const GrRect& devRect,
887 const GrVec& devStrokeSize,
888 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000889 const GrScalar& dx = devStrokeSize.fX;
890 const GrScalar& dy = devStrokeSize.fY;
891 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
892 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
893
bsalomon@google.com205d4602011-04-25 12:43:45 +0000894 GrScalar spare;
895 {
896 GrScalar w = devRect.width() - dx;
897 GrScalar h = devRect.height() - dy;
898 spare = GrMin(w, h);
899 }
900
901 if (spare <= 0) {
902 GrRect r(devRect);
903 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000904 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000905 return;
906 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000907 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 size_t vsize = GrDrawTarget::VertexSize(layout);
909
910 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000911 if (!geo.succeeded()) {
912 GrPrintf("Failed to get space for vertices!\n");
913 return;
914 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000915 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
916 if (NULL == indexBuffer) {
917 GrPrintf("Failed to create index buffer!\n");
918 return;
919 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000920
921 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
922
923 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
924 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
925 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
926 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
927
928 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
929 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
930 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
931 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
932
933 verts += sizeof(GrPoint);
934 for (int i = 0; i < 4; ++i) {
935 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
936 }
937
bsalomon@google.coma3108262011-10-10 14:08:47 +0000938 GrColor innerColor;
939 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000940 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000941 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000942 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000943 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000944 verts += 4 * vsize;
945 for (int i = 0; i < 8; ++i) {
946 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
947 }
948
949 verts += 8 * vsize;
950 for (int i = 0; i < 8; ++i) {
951 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
952 }
953
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000954 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000955 target->drawIndexed(kTriangles_PrimitiveType,
956 0, 0, 16, aaStrokeRectIndexCount());
957}
958
reed@google.com20efde72011-05-09 17:00:02 +0000959/**
960 * Returns true if the rects edges are integer-aligned.
961 */
962static bool isIRect(const GrRect& r) {
963 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
964 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
965}
966
bsalomon@google.com205d4602011-04-25 12:43:45 +0000967static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000968 const GrRect& rect,
969 GrScalar width,
970 const GrMatrix* matrix,
971 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000972 GrRect* devRect,
973 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000974 // we use a simple coverage ramp to do aa on axis-aligned rects
975 // we check if the rect will be axis-aligned, and the rect won't land on
976 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000977
bsalomon@google.coma3108262011-10-10 14:08:47 +0000978 // we are keeping around the "tweak the alpha" trick because
979 // it is our only hope for the fixed-pipe implementation.
980 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000981 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000982 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000983 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000984 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000985#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000986 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000987#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000988 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000989 } else {
990 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000991 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000992 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000993 const GrDrawState& drawState = target->getDrawState();
994 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000995 return false;
996 }
997
bsalomon@google.com471d4712011-08-23 15:45:25 +0000998 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000999 return false;
1000 }
1001
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001002 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001003 return false;
1004 }
1005
1006 if (NULL != matrix &&
1007 !matrix->preservesAxisAlignment()) {
1008 return false;
1009 }
1010
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001011 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001012 if (NULL != matrix) {
1013 combinedMatrix->preConcat(*matrix);
1014 GrAssert(combinedMatrix->preservesAxisAlignment());
1015 }
1016
1017 combinedMatrix->mapRect(devRect, rect);
1018 devRect->sort();
1019
1020 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001021 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022 } else {
1023 return true;
1024 }
1025}
1026
bsalomon@google.com27847de2011-02-22 20:59:41 +00001027void GrContext::drawRect(const GrPaint& paint,
1028 const GrRect& rect,
1029 GrScalar width,
1030 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001031 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001032
1033 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001034 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001035
bsalomon@google.com205d4602011-04-25 12:43:45 +00001036 GrRect devRect = rect;
1037 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001038 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001039 bool needAA = paint.fAntiAlias &&
1040 !this->getRenderTarget()->isMultisampled();
1041 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1042 &combinedMatrix, &devRect,
1043 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001044
1045 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001046 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001047 if (width >= 0) {
1048 GrVec strokeSize;;
1049 if (width > 0) {
1050 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001051 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001052 strokeSize.setAbs(strokeSize);
1053 } else {
1054 strokeSize.set(GR_Scalar1, GR_Scalar1);
1055 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001056 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001057 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059 }
1060 return;
1061 }
1062
bsalomon@google.com27847de2011-02-22 20:59:41 +00001063 if (width >= 0) {
1064 // TODO: consider making static vertex buffers for these cases.
1065 // Hairline could be done by just adding closing vertex to
1066 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001067 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1068
bsalomon@google.com27847de2011-02-22 20:59:41 +00001069 static const int worstCaseVertCount = 10;
1070 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1071
1072 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001073 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001074 return;
1075 }
1076
1077 GrPrimitiveType primType;
1078 int vertCount;
1079 GrPoint* vertex = geo.positions();
1080
1081 if (width > 0) {
1082 vertCount = 10;
1083 primType = kTriangleStrip_PrimitiveType;
1084 setStrokeRectStrip(vertex, rect, width);
1085 } else {
1086 // hairline
1087 vertCount = 5;
1088 primType = kLineStrip_PrimitiveType;
1089 vertex[0].set(rect.fLeft, rect.fTop);
1090 vertex[1].set(rect.fRight, rect.fTop);
1091 vertex[2].set(rect.fRight, rect.fBottom);
1092 vertex[3].set(rect.fLeft, rect.fBottom);
1093 vertex[4].set(rect.fLeft, rect.fTop);
1094 }
1095
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001096 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001097 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001098 GrDrawState* drawState = target->drawState();
1099 avmr.set(drawState);
1100 drawState->preConcatViewMatrix(*matrix);
1101 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001102 }
1103
1104 target->drawNonIndexed(primType, 0, vertCount);
1105 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001106#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001107 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001108 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1109 if (NULL == sqVB) {
1110 GrPrintf("Failed to create static rect vb.\n");
1111 return;
1112 }
1113 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001114 GrDrawState* drawState = target->drawState();
1115 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001116 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001117 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001118 0, rect.height(), rect.fTop,
1119 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001120
1121 if (NULL != matrix) {
1122 m.postConcat(*matrix);
1123 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001124 drawState->preConcatViewMatrix(m);
1125 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001126
bsalomon@google.com27847de2011-02-22 20:59:41 +00001127 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001128#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001129 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001130#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001131 }
1132}
1133
1134void GrContext::drawRectToRect(const GrPaint& paint,
1135 const GrRect& dstRect,
1136 const GrRect& srcRect,
1137 const GrMatrix* dstMatrix,
1138 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001139 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001140
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001141 // srcRect refers to paint's first texture
1142 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001143 drawRect(paint, dstRect, -1, dstMatrix);
1144 return;
1145 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001146
bsalomon@google.com27847de2011-02-22 20:59:41 +00001147 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1148
1149#if GR_STATIC_RECT_VB
1150 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001151 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001152 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001153 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001154
1155 GrMatrix m;
1156
1157 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1158 0, dstRect.height(), dstRect.fTop,
1159 0, 0, GrMatrix::I()[8]);
1160 if (NULL != dstMatrix) {
1161 m.postConcat(*dstMatrix);
1162 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001163 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001164
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001165 // srcRect refers to first stage
1166 int otherStageMask = paint.getActiveStageMask() &
1167 (~(1 << GrPaint::kFirstTextureStage));
1168 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001169 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001170 }
1171
bsalomon@google.com27847de2011-02-22 20:59:41 +00001172 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1173 0, srcRect.height(), srcRect.fTop,
1174 0, 0, GrMatrix::I()[8]);
1175 if (NULL != srcMatrix) {
1176 m.postConcat(*srcMatrix);
1177 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001178 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001179
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001180 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1181 if (NULL == sqVB) {
1182 GrPrintf("Failed to create static rect vb.\n");
1183 return;
1184 }
1185 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001186 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1187#else
1188
1189 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001190#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001191 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001192#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1194#endif
1195
tomhudson@google.com93813632011-10-27 20:21:16 +00001196 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1197 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198 srcRects[0] = &srcRect;
1199 srcMatrices[0] = srcMatrix;
1200
1201 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1202#endif
1203}
1204
1205void GrContext::drawVertices(const GrPaint& paint,
1206 GrPrimitiveType primitiveType,
1207 int vertexCount,
1208 const GrPoint positions[],
1209 const GrPoint texCoords[],
1210 const GrColor colors[],
1211 const uint16_t indices[],
1212 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001213 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001214
1215 GrDrawTarget::AutoReleaseGeometry geo;
1216
1217 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1218
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001219 bool hasTexCoords[GrPaint::kTotalStages] = {
1220 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1221 0 // remaining stages use positions
1222 };
1223
1224 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001225
1226 if (NULL != colors) {
1227 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001228 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001229 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001230
1231 if (sizeof(GrPoint) != vertexSize) {
1232 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001233 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234 return;
1235 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001236 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001237 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001238 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1239 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001240 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001241 NULL,
1242 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001243 void* curVertex = geo.vertices();
1244
1245 for (int i = 0; i < vertexCount; ++i) {
1246 *((GrPoint*)curVertex) = positions[i];
1247
1248 if (texOffsets[0] > 0) {
1249 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1250 }
1251 if (colorOffset > 0) {
1252 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1253 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001254 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255 }
1256 } else {
1257 target->setVertexSourceToArray(layout, positions, vertexCount);
1258 }
1259
bsalomon@google.com91958362011-06-13 17:58:13 +00001260 // we don't currently apply offscreen AA to this path. Need improved
1261 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001262
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001263 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001264 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001265 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001266 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001267 target->drawNonIndexed(primitiveType, 0, vertexCount);
1268 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269}
1270
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001271///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001272namespace {
1273
bsalomon@google.com93c96602012-04-27 13:05:21 +00001274struct CircleVertex {
1275 GrPoint fPos;
1276 GrPoint fCenter;
1277 GrScalar fOuterRadius;
1278 GrScalar fInnerRadius;
1279};
1280
1281/* Returns true if will map a circle to another circle. This can be true
1282 * if the matrix only includes square-scale, rotation, translation.
1283 */
1284inline bool isSimilarityTransformation(const SkMatrix& matrix,
1285 SkScalar tol = SK_ScalarNearlyZero) {
1286 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1287 return true;
1288 }
1289 if (matrix.hasPerspective()) {
1290 return false;
1291 }
1292
1293 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1294 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1295 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1296 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1297
1298 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1299 return false;
1300 }
1301
1302 // it has scales or skews, but it could also be rotation, check it out.
1303 SkVector vec[2];
1304 vec[0].set(mx, sx);
1305 vec[1].set(sy, my);
1306
1307 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1308 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1309 SkScalarSquare(tol));
1310}
1311
1312}
1313
1314// TODO: strokeWidth can't be larger than zero right now.
1315// It will be fixed when drawPath() can handle strokes.
1316void GrContext::drawOval(const GrPaint& paint,
1317 const GrRect& rect,
1318 SkScalar strokeWidth) {
1319 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1320 kUnbuffered_DrawCategory;
1321 GrDrawTarget* target = this->prepareToDraw(paint, category);
1322 GrDrawState* drawState = target->drawState();
1323 GrMatrix vm = drawState->getViewMatrix();
1324
1325 if (!isSimilarityTransformation(vm) ||
1326 !paint.fAntiAlias ||
1327 rect.height() != rect.width()) {
1328 SkPath path;
1329 path.addOval(rect);
1330 GrPathFill fill = (strokeWidth == 0) ?
1331 kHairLine_PathFill : kWinding_PathFill;
1332 this->internalDrawPath(paint, path, fill, NULL);
1333 return;
1334 }
1335
1336 const GrRenderTarget* rt = drawState->getRenderTarget();
1337 if (NULL == rt) {
1338 return;
1339 }
1340
1341 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1342
1343 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1344 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1345 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1346
1347 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1348 GrScalar radius = SkScalarHalf(rect.width());
1349
1350 vm.mapPoints(&center, 1);
1351 radius = vm.mapRadius(radius);
1352
1353 GrScalar outerRadius = radius;
1354 GrScalar innerRadius = 0;
1355 SkScalar halfWidth = 0;
1356 if (strokeWidth == 0) {
1357 halfWidth = SkScalarHalf(SK_Scalar1);
1358
1359 outerRadius += halfWidth;
1360 innerRadius = SkMaxScalar(0, radius - halfWidth);
1361 }
1362
1363 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1364 if (!geo.succeeded()) {
1365 GrPrintf("Failed to get space for vertices!\n");
1366 return;
1367 }
1368
1369 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1370
1371 SkScalar L = center.fX - outerRadius;
1372 SkScalar R = center.fX + outerRadius;
1373 SkScalar T = center.fY - outerRadius;
1374 SkScalar B = center.fY + outerRadius;
1375
1376 verts[0].fPos = SkPoint::Make(L, T);
1377 verts[1].fPos = SkPoint::Make(R, T);
1378 verts[2].fPos = SkPoint::Make(L, B);
1379 verts[3].fPos = SkPoint::Make(R, B);
1380
1381 for (int i = 0; i < 4; ++i) {
1382 // this goes to fragment shader, it should be in y-points-up space.
1383 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1384
1385 verts[i].fOuterRadius = outerRadius;
1386 verts[i].fInnerRadius = innerRadius;
1387 }
1388
1389 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1390 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001391}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001392
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001393void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001394 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001396 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001397 if (GrIsFillInverted(fill)) {
1398 this->drawPaint(paint);
1399 }
1400 return;
1401 }
1402
bsalomon@google.com93c96602012-04-27 13:05:21 +00001403 SkRect ovalRect;
1404 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1405 if (translate) {
1406 ovalRect.offset(*translate);
1407 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001408 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001409 this->drawOval(paint, ovalRect, width);
1410 return;
1411 }
1412
1413 internalDrawPath(paint, path, fill, translate);
1414}
1415
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001416void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001417 GrPathFill fill, const GrPoint* translate) {
1418
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001419 // Note that below we may sw-rasterize the path into a scratch texture.
1420 // Scratch textures can be recycled after they are returned to the texture
1421 // cache. This presents a potential hazard for buffered drawing. However,
1422 // the writePixels that uploads to the scratch will perform a flush so we're
1423 // OK.
1424 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1425 kUnbuffered_DrawCategory;
1426 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001427 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001428
bsalomon@google.com289533a2011-10-27 12:34:25 +00001429 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1430
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001431 // An Assumption here is that path renderer would use some form of tweaking
1432 // the src color (either the input alpha or in the frag shader) to implement
1433 // aa. If we have some future driver-mojo path AA that can do the right
1434 // thing WRT to the blend then we'll need some query on the PR.
1435 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001436#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001437 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001438#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001439 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001440 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001441
robertphillips@google.comed4155d2012-05-01 14:30:24 +00001442 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA);
bsalomon@google.com30085192011-08-19 15:42:31 +00001443 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001444#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001445 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001446#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001447 return;
1448 }
1449
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001450 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001452
bsalomon@google.com27847de2011-02-22 20:59:41 +00001453////////////////////////////////////////////////////////////////////////////////
1454
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001455void GrContext::flush(int flagsBitfield) {
1456 if (kDiscard_FlushBit & flagsBitfield) {
1457 fDrawBuffer->reset();
1458 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001459 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001460 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001461 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001462 fGpu->forceRenderTargetFlush();
1463 }
1464}
1465
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001467 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001468 // With addition of the AA clip path, flushing the draw buffer can
1469 // result in the generation of an AA clip mask. During this
1470 // process the SW path renderer may be invoked which recusively
1471 // calls this method (via internalWriteTexturePixels) creating
1472 // infinite recursion
1473 GrInOrderDrawBuffer* temp = fDrawBuffer;
1474 fDrawBuffer = NULL;
1475
1476 temp->flushTo(fGpu);
1477
1478 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001479 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001480}
1481
bsalomon@google.com6f379512011-11-16 20:36:03 +00001482void GrContext::internalWriteTexturePixels(GrTexture* texture,
1483 int left, int top,
1484 int width, int height,
1485 GrPixelConfig config,
1486 const void* buffer,
1487 size_t rowBytes,
1488 uint32_t flags) {
1489 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001490 ASSERT_OWNED_RESOURCE(texture);
1491
bsalomon@google.com6f379512011-11-16 20:36:03 +00001492 if (!(kDontFlush_PixelOpsFlag & flags)) {
1493 this->flush();
1494 }
1495 // TODO: use scratch texture to perform conversion
1496 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1497 GrPixelConfigIsUnpremultiplied(config)) {
1498 return;
1499 }
1500
1501 fGpu->writeTexturePixels(texture, left, top, width, height,
1502 config, buffer, rowBytes);
1503}
1504
1505bool GrContext::internalReadTexturePixels(GrTexture* texture,
1506 int left, int top,
1507 int width, int height,
1508 GrPixelConfig config,
1509 void* buffer,
1510 size_t rowBytes,
1511 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001512 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001513 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001514
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001515 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001516 GrRenderTarget* target = texture->asRenderTarget();
1517 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001518 return this->internalReadRenderTargetPixels(target,
1519 left, top, width, height,
1520 config, buffer, rowBytes,
1521 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001522 } else {
1523 return false;
1524 }
1525}
1526
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001527#include "SkConfig8888.h"
1528
1529namespace {
1530/**
1531 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1532 * formats are representable as Config8888 and so the function returns false
1533 * if the GrPixelConfig has no equivalent Config8888.
1534 */
1535bool grconfig_to_config8888(GrPixelConfig config,
1536 SkCanvas::Config8888* config8888) {
1537 switch (config) {
1538 case kRGBA_8888_PM_GrPixelConfig:
1539 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1540 return true;
1541 case kRGBA_8888_UPM_GrPixelConfig:
1542 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1543 return true;
1544 case kBGRA_8888_PM_GrPixelConfig:
1545 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1546 return true;
1547 case kBGRA_8888_UPM_GrPixelConfig:
1548 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1549 return true;
1550 default:
1551 return false;
1552 }
1553}
1554}
1555
bsalomon@google.com6f379512011-11-16 20:36:03 +00001556bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1557 int left, int top,
1558 int width, int height,
1559 GrPixelConfig config,
1560 void* buffer,
1561 size_t rowBytes,
1562 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001563 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001564 ASSERT_OWNED_RESOURCE(target);
1565
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001566 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001567 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001568 if (NULL == target) {
1569 return false;
1570 }
1571 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001572
bsalomon@google.com6f379512011-11-16 20:36:03 +00001573 if (!(kDontFlush_PixelOpsFlag & flags)) {
1574 this->flush();
1575 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001576
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001577 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1578 GrPixelConfigIsUnpremultiplied(config) &&
1579 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1580 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1581 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1582 !grconfig_to_config8888(config, &dstConfig8888)) {
1583 return false;
1584 }
1585 // do read back using target's own config
1586 this->internalReadRenderTargetPixels(target,
1587 left, top,
1588 width, height,
1589 target->config(),
1590 buffer, rowBytes,
1591 kDontFlush_PixelOpsFlag);
1592 // sw convert the pixels to unpremul config
1593 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1594 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1595 pixels, rowBytes, srcConfig8888,
1596 width, height);
1597 return true;
1598 }
1599
bsalomon@google.comc4364992011-11-07 15:54:49 +00001600 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001601 bool swapRAndB = NULL != src &&
1602 fGpu->preferredReadPixelsConfig(config) ==
1603 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001604
1605 bool flipY = NULL != src &&
1606 fGpu->readPixelsWillPayForYFlip(target, left, top,
1607 width, height, config,
1608 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001609 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1610 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001611
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001612 if (NULL == src && alphaConversion) {
1613 // we should fallback to cpu conversion here. This could happen when
1614 // we were given an external render target by the client that is not
1615 // also a texture (e.g. FBO 0 in GL)
1616 return false;
1617 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001618 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001619 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001620 if (flipY || swapRAndB || alphaConversion) {
1621 GrAssert(NULL != src);
1622 if (swapRAndB) {
1623 config = GrPixelConfigSwapRAndB(config);
1624 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001625 }
1626 // Make the scratch a render target because we don't have a robust
1627 // readTexturePixels as of yet (it calls this function).
1628 const GrTextureDesc desc = {
1629 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001630 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001631 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001632 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001633 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001634
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001635 // When a full readback is faster than a partial we could always make
1636 // the scratch exactly match the passed rect. However, if we see many
1637 // different size rectangles we will trash our texture cache and pay the
1638 // cost of creating and destroying many textures. So, we only request
1639 // an exact match when the caller is reading an entire RT.
1640 ScratchTexMatch match = kApprox_ScratchTexMatch;
1641 if (0 == left &&
1642 0 == top &&
1643 target->width() == width &&
1644 target->height() == height &&
1645 fGpu->fullReadPixelsIsFasterThanPartial()) {
1646 match = kExact_ScratchTexMatch;
1647 }
1648 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001649 GrTexture* texture = ast.texture();
1650 if (!texture) {
1651 return false;
1652 }
1653 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001654 GrAssert(NULL != target);
1655
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001656 GrDrawTarget::AutoStateRestore asr(fGpu,
1657 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001658 GrDrawState* drawState = fGpu->drawState();
1659 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001660
bsalomon@google.comc4364992011-11-07 15:54:49 +00001661 GrMatrix matrix;
1662 if (flipY) {
1663 matrix.setTranslate(SK_Scalar1 * left,
1664 SK_Scalar1 * (top + height));
1665 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1666 } else {
1667 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1668 }
1669 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001670 drawState->sampler(0)->reset(matrix);
1671 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001672 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001673 GrRect rect;
1674 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1675 fGpu->drawSimpleRect(rect, NULL, 0x1);
1676 left = 0;
1677 top = 0;
1678 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001679 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001680 left, top, width, height,
1681 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001682}
1683
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001684void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1685 GrAssert(target);
1686 ASSERT_OWNED_RESOURCE(target);
1687 // In the future we may track whether there are any pending draws to this
1688 // target. We don't today so we always perform a flush. We don't promise
1689 // this to our clients, though.
1690 this->flush();
1691 fGpu->resolveRenderTarget(target);
1692}
1693
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001694void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1695 if (NULL == src || NULL == dst) {
1696 return;
1697 }
1698 ASSERT_OWNED_RESOURCE(src);
1699
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001700 // Writes pending to the source texture are not tracked, so a flush
1701 // is required to ensure that the copy captures the most recent contents
1702 // of the source texture. See similar behaviour in
1703 // GrContext::resolveRenderTarget.
1704 this->flush();
1705
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001706 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001707 GrDrawState* drawState = fGpu->drawState();
1708 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001709 GrMatrix sampleM;
1710 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001711 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001712 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001713 SkRect rect = SkRect::MakeXYWH(0, 0,
1714 SK_Scalar1 * src->width(),
1715 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001716 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1717}
1718
bsalomon@google.com6f379512011-11-16 20:36:03 +00001719void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1720 int left, int top,
1721 int width, int height,
1722 GrPixelConfig config,
1723 const void* buffer,
1724 size_t rowBytes,
1725 uint32_t flags) {
1726 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001727 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001728
1729 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001730 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001731 if (NULL == target) {
1732 return;
1733 }
1734 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001735
1736 // TODO: when underlying api has a direct way to do this we should use it
1737 // (e.g. glDrawPixels on desktop GL).
1738
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001739 // If the RT is also a texture and we don't have to do PM/UPM conversion
1740 // then take the texture path, which we expect to be at least as fast or
1741 // faster since it doesn't use an intermediate texture as we do below.
1742
1743#if !GR_MAC_BUILD
1744 // At least some drivers on the Mac get confused when glTexImage2D is called
1745 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1746 // determine what OS versions and/or HW is affected.
1747 if (NULL != target->asTexture() &&
1748 GrPixelConfigIsUnpremultiplied(target->config()) ==
1749 GrPixelConfigIsUnpremultiplied(config)) {
1750
1751 this->internalWriteTexturePixels(target->asTexture(),
1752 left, top, width, height,
1753 config, buffer, rowBytes, flags);
1754 return;
1755 }
1756#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001757 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1758 GrPixelConfigIsUnpremultiplied(config) &&
1759 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1760 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1761 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1762 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1763 return;
1764 }
1765 // allocate a tmp buffer and sw convert the pixels to premul
1766 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1767 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1768 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1769 src, rowBytes, srcConfig8888,
1770 width, height);
1771 // upload the already premul pixels
1772 this->internalWriteRenderTargetPixels(target,
1773 left, top,
1774 width, height,
1775 target->config(),
1776 tmpPixels, 4 * width, flags);
1777 return;
1778 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001779
1780 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1781 GrPixelConfigSwapRAndB(config);
1782 if (swapRAndB) {
1783 config = GrPixelConfigSwapRAndB(config);
1784 }
1785
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001786 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001787 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001788 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001789 GrAutoScratchTexture ast(this, desc);
1790 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001791 if (NULL == texture) {
1792 return;
1793 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001794 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1795 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001796
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001797 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001798 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001799
1800 GrMatrix matrix;
1801 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001802 drawState->setViewMatrix(matrix);
1803 drawState->setRenderTarget(target);
1804 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001805
bsalomon@google.com5c638652011-07-18 19:31:59 +00001806 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001807 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1808 GrSamplerState::kNearest_Filter,
1809 matrix);
1810 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001811
1812 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1813 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001814 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001815 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1816 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001817 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001818 return;
1819 }
1820 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1821 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1822}
1823////////////////////////////////////////////////////////////////////////////////
1824
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001825void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001826
1827 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1828 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001829 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001830 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001831 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001832 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001833 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001834 }
1835
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001836 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001837
1838 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1839 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001840 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001841 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001842 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001843 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001844 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001845 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001846
1847 // disable all stages not accessible via the paint
1848 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001849 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001850 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001851
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001852 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001853
1854 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001855 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001856 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001857 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001858 }
1859 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001860 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001861 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001862 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001863 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001864 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001865 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1866 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001867 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001868 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001869 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001870 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1871 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1872 fDrawState->setCoverage(paint.fCoverage);
bsalomon@google.come79c8152012-03-29 19:07:12 +00001873#if GR_DEBUG
1874 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001875 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001876 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1877 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001878#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001879}
1880
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001881GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001882 DrawCategory category) {
1883 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001884 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885 fLastDrawCategory = category;
1886 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001887 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001888 GrDrawTarget* target = fGpu;
1889 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001890 case kUnbuffered_DrawCategory:
1891 target = fGpu;
1892 break;
1893 case kBuffered_DrawCategory:
1894 target = fDrawBuffer;
1895 fDrawBuffer->setClip(fGpu->getClip());
1896 break;
1897 default:
1898 GrCrash("Unexpected DrawCategory.");
1899 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001900 }
1901 return target;
1902}
1903
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001904GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001905 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001906 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001907 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001908 if (NULL == fPathRendererChain) {
1909 fPathRendererChain =
1910 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1911 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001912 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001913}
1914
bsalomon@google.com27847de2011-02-22 20:59:41 +00001915////////////////////////////////////////////////////////////////////////////////
1916
bsalomon@google.com27847de2011-02-22 20:59:41 +00001917void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001918 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001919 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001920 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001921 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001922 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001923}
1924
1925GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001926 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001927}
1928
1929const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001930 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001931}
1932
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001933bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1934 return fGpu->isConfigRenderable(config);
1935}
1936
bsalomon@google.com27847de2011-02-22 20:59:41 +00001937const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001938 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001939}
1940
1941void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001942 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001943}
1944
1945void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001946 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001947}
1948
1949static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1950 intptr_t mask = 1 << shift;
1951 if (pred) {
1952 bits |= mask;
1953 } else {
1954 bits &= ~mask;
1955 }
1956 return bits;
1957}
1958
1959void GrContext::resetStats() {
1960 fGpu->resetStats();
1961}
1962
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001963const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001964 return fGpu->getStats();
1965}
1966
1967void GrContext::printStats() const {
1968 fGpu->printStats();
1969}
1970
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001971GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001972 fGpu = gpu;
1973 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001974 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001975
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001976 fDrawState = new GrDrawState();
1977 fGpu->setDrawState(fDrawState);
1978
bsalomon@google.com30085192011-08-19 15:42:31 +00001979 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001980
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001981 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1982 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001983 fFontCache = new GrFontCache(fGpu);
1984
1985 fLastDrawCategory = kUnbuffered_DrawCategory;
1986
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001987 fDrawBuffer = NULL;
1988 fDrawBufferVBAllocPool = NULL;
1989 fDrawBufferIBAllocPool = NULL;
1990
bsalomon@google.com205d4602011-04-25 12:43:45 +00001991 fAAFillRectIndexBuffer = NULL;
1992 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001993
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001994 this->setupDrawBuffer();
1995}
1996
1997void GrContext::setupDrawBuffer() {
1998
1999 GrAssert(NULL == fDrawBuffer);
2000 GrAssert(NULL == fDrawBufferVBAllocPool);
2001 GrAssert(NULL == fDrawBufferIBAllocPool);
2002
bsalomon@google.com92edd312012-04-04 21:40:21 +00002003#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002004 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002005 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002006 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2007 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002008 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002009 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002010 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002011 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2012
bsalomon@google.com471d4712011-08-23 15:45:25 +00002013 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2014 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002015 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002016#endif
2017
2018#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002019 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002020#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002021 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002022 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002023}
2024
bsalomon@google.com27847de2011-02-22 20:59:41 +00002025GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002026#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002027 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002028#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002029 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002030#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002031}
2032
2033const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2034 return fGpu->getQuadIndexBuffer();
2035}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002036
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002037GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2038 GrAutoScratchTexture* temp1,
2039 GrAutoScratchTexture* temp2,
2040 const SkRect& rect,
2041 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002042 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002043 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2044 GrClip oldClip = this->getClip();
2045 GrTexture* origTexture = srcTexture;
2046 GrAutoMatrix avm(this, GrMatrix::I());
2047 SkIRect clearRect;
2048 int scaleFactorX, halfWidthX, kernelWidthX;
2049 int scaleFactorY, halfWidthY, kernelWidthY;
2050 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2051 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002052
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002053 SkRect srcRect(rect);
2054 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2055 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002056 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2057 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002058 this->setClip(srcRect);
2059
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002060 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2061 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2062 kAlpha_8_GrPixelConfig == srcTexture->config());
2063
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002064 const GrTextureDesc desc = {
2065 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002066 SkScalarFloorToInt(srcRect.width()),
2067 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002068 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002069 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002070 };
2071
2072 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002073 if (temp2) {
2074 temp2->set(this, desc);
2075 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002076
2077 GrTexture* dstTexture = temp1->texture();
2078 GrPaint paint;
2079 paint.reset();
2080 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2081
2082 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2083 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2084 srcTexture->height());
2085 this->setRenderTarget(dstTexture->asRenderTarget());
2086 SkRect dstRect(srcRect);
2087 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2088 i < scaleFactorY ? 0.5f : 1.0f);
2089 paint.setTexture(0, srcTexture);
2090 this->drawRectToRect(paint, dstRect, srcRect);
2091 srcRect = dstRect;
2092 SkTSwap(srcTexture, dstTexture);
2093 // If temp2 is non-NULL, don't render back to origTexture
2094 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2095 }
2096
robertphillips@google.com7a396332012-05-10 15:11:27 +00002097 SkIRect srcIRect;
2098 srcRect.roundOut(&srcIRect);
2099
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002100 if (sigmaX > 0.0f) {
2101 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2102 float* kernelX = kernelStorageX.get();
2103 build_kernel(sigmaX, kernelX, kernelWidthX);
2104
2105 if (scaleFactorX > 1) {
2106 // Clear out a halfWidth to the right of the srcRect to prevent the
2107 // X convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002108 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2109 halfWidthX, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002110 this->clear(&clearRect, 0x0);
2111 }
2112
2113 this->setRenderTarget(dstTexture->asRenderTarget());
2114 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2115 GrSamplerState::kX_FilterDirection);
2116 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002117 if (temp2 && dstTexture == origTexture) {
2118 dstTexture = temp2->texture();
2119 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002120 }
2121
2122 if (sigmaY > 0.0f) {
2123 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2124 float* kernelY = kernelStorageY.get();
2125 build_kernel(sigmaY, kernelY, kernelWidthY);
2126
2127 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2128 // Clear out a halfWidth below the srcRect to prevent the Y
2129 // convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002130 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2131 srcIRect.width(), halfWidthY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002132 this->clear(&clearRect, 0x0);
2133 }
2134
2135 this->setRenderTarget(dstTexture->asRenderTarget());
2136 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2137 GrSamplerState::kY_FilterDirection);
2138 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002139 if (temp2 && dstTexture == origTexture) {
2140 dstTexture = temp2->texture();
2141 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002142 }
2143
2144 if (scaleFactorX > 1 || scaleFactorY > 1) {
2145 // Clear one pixel to the right and below, to accommodate bilinear
2146 // upsampling.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002147 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2148 srcIRect.width() + 1, 1);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002149 this->clear(&clearRect, 0x0);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002150 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2151 1, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002152 this->clear(&clearRect, 0x0);
2153 // FIXME: This should be mitchell, not bilinear.
2154 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2155 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2156 srcTexture->height());
2157 this->setRenderTarget(dstTexture->asRenderTarget());
2158 paint.setTexture(0, srcTexture);
2159 SkRect dstRect(srcRect);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002160 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002161 this->drawRectToRect(paint, dstRect, srcRect);
2162 srcRect = dstRect;
2163 SkTSwap(srcTexture, dstTexture);
2164 }
2165 this->setRenderTarget(oldRenderTarget);
2166 this->setClip(oldClip);
2167 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002168}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002169
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002170GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2171 const GrRect& rect,
2172 GrTexture* temp1, GrTexture* temp2,
2173 GrSamplerState::Filter filter,
2174 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002175 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002176 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2177 GrAutoMatrix avm(this, GrMatrix::I());
2178 GrClip oldClip = this->getClip();
robertphillips@google.com7a396332012-05-10 15:11:27 +00002179 this->setClip(GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
2180 SkIntToScalar(srcTexture->height())));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002181 if (radius.fWidth > 0) {
2182 this->setRenderTarget(temp1->asRenderTarget());
2183 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2184 GrSamplerState::kX_FilterDirection);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002185 SkIRect clearRect = SkIRect::MakeXYWH(
2186 SkScalarFloorToInt(rect.fLeft),
2187 SkScalarFloorToInt(rect.fBottom),
2188 SkScalarFloorToInt(rect.width()),
2189 radius.fHeight);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002190 this->clear(&clearRect, 0x0);
2191 srcTexture = temp1;
2192 }
2193 if (radius.fHeight > 0) {
2194 this->setRenderTarget(temp2->asRenderTarget());
2195 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2196 GrSamplerState::kY_FilterDirection);
2197 srcTexture = temp2;
2198 }
2199 this->setRenderTarget(oldRenderTarget);
2200 this->setClip(oldClip);
2201 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002202}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002203
2204///////////////////////////////////////////////////////////////////////////////