blob: 5ec6511b9f845147750c5a6b488e0e56ce8380c0 [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
reed@google.com4b2d3f32012-05-15 18:05:50 +000038#if GR_DEBUG
39 // change this to a 1 to see notifications when partial coverage fails
40 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
41#else
42 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
43#endif
44
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000045static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
46static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000047
bsalomon@google.com60361492012-03-15 17:47:06 +000048static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000049static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
50
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000051// path rendering is the only thing we defer today that uses non-static indices
52static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
53static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000054
bsalomon@google.combc4b6542011-11-19 13:56:11 +000055#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
56
bsalomon@google.com05ef5102011-05-02 21:14:59 +000057GrContext* GrContext::Create(GrEngine engine,
58 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000059 GrContext* ctx = NULL;
60 GrGpu* fGpu = GrGpu::Create(engine, context3D);
61 if (NULL != fGpu) {
62 ctx = new GrContext(fGpu);
63 fGpu->unref();
64 }
65 return ctx;
66}
67
bsalomon@google.com27847de2011-02-22 20:59:41 +000068GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000069 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000070 delete fTextureCache;
71 delete fFontCache;
72 delete fDrawBuffer;
73 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000074 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000075
bsalomon@google.com205d4602011-04-25 12:43:45 +000076 GrSafeUnref(fAAFillRectIndexBuffer);
77 GrSafeUnref(fAAStrokeRectIndexBuffer);
78 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000079 GrSafeUnref(fPathRendererChain);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000080 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000081}
82
bsalomon@google.com8fe72472011-03-30 21:26:44 +000083void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000084 contextDestroyed();
85 this->setupDrawBuffer();
86}
87
88void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000089 // abandon first to so destructors
90 // don't try to free the resources in the API.
91 fGpu->abandonResources();
92
bsalomon@google.com30085192011-08-19 15:42:31 +000093 // a path renderer may be holding onto resources that
94 // are now unusable
95 GrSafeSetNull(fPathRendererChain);
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 delete fDrawBuffer;
98 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000099
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100 delete fDrawBufferVBAllocPool;
101 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000102
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000103 delete fDrawBufferIBAllocPool;
104 fDrawBufferIBAllocPool = NULL;
105
bsalomon@google.com205d4602011-04-25 12:43:45 +0000106 GrSafeSetNull(fAAFillRectIndexBuffer);
107 GrSafeSetNull(fAAStrokeRectIndexBuffer);
108
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000109 fTextureCache->removeAll();
110 fFontCache->freeAll();
111 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000112}
113
114void GrContext::resetContext() {
115 fGpu->markContextDirty();
116}
117
118void GrContext::freeGpuResources() {
119 this->flush();
robertphillips@google.comff175842012-05-14 19:31:39 +0000120
121 fGpu->purgeResources();
122
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000123 fTextureCache->removeAll();
124 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000125 // a path renderer may be holding onto resources
126 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000127}
128
twiz@google.com05e70242012-01-27 19:12:00 +0000129size_t GrContext::getGpuTextureCacheBytes() const {
130 return fTextureCache->getCachedResourceBytes();
131}
132
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000133////////////////////////////////////////////////////////////////////////////////
134
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000135int GrContext::PaintStageVertexLayoutBits(
136 const GrPaint& paint,
137 const bool hasTexCoords[GrPaint::kTotalStages]) {
138 int stageMask = paint.getActiveStageMask();
139 int layout = 0;
140 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
141 if ((1 << i) & stageMask) {
142 if (NULL != hasTexCoords && hasTexCoords[i]) {
143 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
144 } else {
145 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
146 }
147 }
148 }
149 return layout;
150}
151
152
153////////////////////////////////////////////////////////////////////////////////
154
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000155enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000156 // flags for textures
157 kNPOTBit = 0x1,
158 kFilterBit = 0x2,
159 kScratchBit = 0x4,
160
161 // resource type
162 kTextureBit = 0x8,
163 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000164};
165
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000166GrTexture* GrContext::TextureCacheEntry::texture() const {
167 if (NULL == fEntry) {
168 return NULL;
169 } else {
170 return (GrTexture*) fEntry->resource();
171 }
172}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000173
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000174namespace {
175// returns true if this is a "special" texture because of gpu NPOT limitations
176bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000177 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000178 GrContext::TextureKey clientKey,
179 int width,
180 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000181 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000182 bool scratch,
183 uint32_t v[4]) {
184 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
185 // we assume we only need 16 bits of width and height
186 // assert that texture creation will fail anyway if this assumption
187 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000188 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000189 v[0] = clientKey & 0xffffffffUL;
190 v[1] = (clientKey >> 32) & 0xffffffffUL;
191 v[2] = width | (height << 16);
192
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000193 v[3] = (sampleCnt << 24);
194 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
195
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000196 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000197 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
198
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000199 bool tiled = NULL != sampler &&
200 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
201 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000202
203 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000204 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000205 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000206 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000207 }
208 }
209 }
210
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000211 if (scratch) {
212 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000213 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000214
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000215 v[3] |= kTextureBit;
216
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000217 return v[3] & kNPOTBit;
218}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000219
220// we should never have more than one stencil buffer with same combo of
221// (width,height,samplecount)
222void gen_stencil_key_values(int width, int height,
223 int sampleCnt, uint32_t v[4]) {
224 v[0] = width;
225 v[1] = height;
226 v[2] = sampleCnt;
227 v[3] = kStencilBufferBit;
228}
229
230void gen_stencil_key_values(const GrStencilBuffer* sb,
231 uint32_t v[4]) {
232 gen_stencil_key_values(sb->width(), sb->height(),
233 sb->numSamples(), v);
234}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000235
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000236void build_kernel(float sigma, float* kernel, int kernelWidth) {
237 int halfWidth = (kernelWidth - 1) / 2;
238 float sum = 0.0f;
239 float denom = 1.0f / (2.0f * sigma * sigma);
240 for (int i = 0; i < kernelWidth; ++i) {
241 float x = static_cast<float>(i - halfWidth);
242 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
243 // is dropped here, since we renormalize the kernel below.
244 kernel[i] = sk_float_exp(- x * x * denom);
245 sum += kernel[i];
246 }
247 // Normalize the kernel
248 float scale = 1.0f / sum;
249 for (int i = 0; i < kernelWidth; ++i)
250 kernel[i] *= scale;
251}
252
253void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000254 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
255 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
256 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
257 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000258}
259
260float adjust_sigma(float sigma, int *scaleFactor, int *halfWidth,
261 int *kernelWidth) {
262 *scaleFactor = 1;
263 while (sigma > MAX_BLUR_SIGMA) {
264 *scaleFactor *= 2;
265 sigma *= 0.5f;
266 }
267 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
268 *kernelWidth = *halfWidth * 2 + 1;
269 return sigma;
270}
271
272void apply_morphology(GrGpu* gpu,
273 GrTexture* texture,
274 const SkRect& rect,
275 int radius,
276 GrSamplerState::Filter filter,
277 GrSamplerState::FilterDirection direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000278 GrAssert(filter == GrSamplerState::kErode_Filter ||
279 filter == GrSamplerState::kDilate_Filter);
280
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000281 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
282 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000283 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000284 drawState->setRenderTarget(target);
285 GrMatrix sampleM;
286 sampleM.setIDiv(texture->width(), texture->height());
287 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, filter,
288 sampleM);
289 drawState->sampler(0)->setMorphologyRadius(radius);
290 drawState->sampler(0)->setFilterDirection(direction);
291 drawState->setTexture(0, texture);
292 gpu->drawSimpleRect(rect, NULL, 1 << 0);
293}
294
295void convolve(GrGpu* gpu,
296 GrTexture* texture,
297 const SkRect& rect,
298 const float* kernel,
299 int kernelWidth,
300 GrSamplerState::FilterDirection direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000301 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
302 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000303 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000304 drawState->setRenderTarget(target);
305 GrMatrix sampleM;
306 sampleM.setIDiv(texture->width(), texture->height());
307 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
308 GrSamplerState::kConvolution_Filter,
309 sampleM);
tomhudson@google.comd8f856c2012-05-10 12:13:36 +0000310 drawState->sampler(0)->setCustomStage(
311 new GrConvolutionEffect(direction, kernelWidth, kernel));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000312 drawState->setTexture(0, texture);
313 gpu->drawSimpleRect(rect, NULL, 1 << 0);
314}
315
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000316}
317
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000318GrContext::TextureCacheEntry GrContext::findAndLockTexture(
319 TextureKey key,
320 int width,
321 int height,
322 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000323 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000324 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000325 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000326 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
327 GrResourceCache::kNested_LockType));
328}
329
bsalomon@google.comfb309512011-11-30 14:13:48 +0000330bool GrContext::isTextureInCache(TextureKey key,
331 int width,
332 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000333 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000334 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000335 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000336 GrResourceKey resourceKey(v);
337 return fTextureCache->hasKey(resourceKey);
338}
339
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000340GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000341 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000342 uint32_t v[4];
343 gen_stencil_key_values(sb, v);
344 GrResourceKey resourceKey(v);
345 return fTextureCache->createAndLock(resourceKey, sb);
346}
347
348GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
349 int sampleCnt) {
350 uint32_t v[4];
351 gen_stencil_key_values(width, height, sampleCnt, v);
352 GrResourceKey resourceKey(v);
353 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
354 GrResourceCache::kSingle_LockType);
355 if (NULL != entry) {
356 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
357 return sb;
358 } else {
359 return NULL;
360 }
361}
362
363void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000364 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000365 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000366}
367
368static void stretchImage(void* dst,
369 int dstW,
370 int dstH,
371 void* src,
372 int srcW,
373 int srcH,
374 int bpp) {
375 GrFixed dx = (srcW << 16) / dstW;
376 GrFixed dy = (srcH << 16) / dstH;
377
378 GrFixed y = dy >> 1;
379
380 int dstXLimit = dstW*bpp;
381 for (int j = 0; j < dstH; ++j) {
382 GrFixed x = dx >> 1;
383 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
384 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
385 for (int i = 0; i < dstXLimit; i += bpp) {
386 memcpy((uint8_t*) dstRow + i,
387 (uint8_t*) srcRow + (x>>16)*bpp,
388 bpp);
389 x += dx;
390 }
391 y += dy;
392 }
393}
394
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000395GrContext::TextureCacheEntry GrContext::createAndLockTexture(
396 TextureKey key,
397 const GrSamplerState* sampler,
398 const GrTextureDesc& desc,
399 void* srcData,
400 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000401 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402
403#if GR_DUMP_TEXTURE_UPLOAD
404 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
405#endif
406
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000407 TextureCacheEntry entry;
408 uint32_t v[4];
409 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000410 desc.fWidth, desc.fHeight,
411 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000413
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000415 GrAssert(NULL != sampler);
416 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
417 desc.fWidth,
418 desc.fHeight,
419 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000420
421 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000422 clampEntry = this->createAndLockTexture(key, NULL, desc,
423 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000424 GrAssert(NULL != clampEntry.texture());
425 if (NULL == clampEntry.texture()) {
426 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000427 }
428 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000429 GrTextureDesc rtDesc = desc;
430 rtDesc.fFlags = rtDesc.fFlags |
431 kRenderTarget_GrTextureFlagBit |
432 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000433 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
434 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000435
436 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
437
438 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000439 GrDrawTarget::AutoStateRestore asr(fGpu,
440 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000441 GrDrawState* drawState = fGpu->drawState();
442 drawState->setRenderTarget(texture->asRenderTarget());
443 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000444
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000445 GrSamplerState::Filter filter;
446 // if filtering is not desired then we want to ensure all
447 // texels in the resampled image are copies of texels from
448 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000449 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000450 filter = GrSamplerState::kNearest_Filter;
451 } else {
452 filter = GrSamplerState::kBilinear_Filter;
453 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000454 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
455 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000456
457 static const GrVertexLayout layout =
458 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
459 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
460
461 if (arg.succeeded()) {
462 GrPoint* verts = (GrPoint*) arg.vertices();
463 verts[0].setIRectFan(0, 0,
464 texture->width(),
465 texture->height(),
466 2*sizeof(GrPoint));
467 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
468 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
469 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000470 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000471 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000472 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000473 } else {
474 // TODO: Our CPU stretch doesn't filter. But we create separate
475 // stretched textures when the sampler state is either filtered or
476 // not. Either implement filtered stretch blit on CPU or just create
477 // one when FBO case fails.
478
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000479 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000480 // no longer need to clamp at min RT size.
481 rtDesc.fWidth = GrNextPow2(desc.fWidth);
482 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000483 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000484 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000485 rtDesc.fWidth *
486 rtDesc.fHeight);
487 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
488 srcData, desc.fWidth, desc.fHeight, bpp);
489
490 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
491
492 GrTexture* texture = fGpu->createTexture(rtDesc,
493 stretchedPixels.get(),
494 stretchedRowBytes);
495 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000496 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000497 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000498 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000499
500 } else {
501 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
502 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000503 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000504 }
505 }
506 return entry;
507}
508
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000509namespace {
510inline void gen_scratch_tex_key_values(const GrGpu* gpu,
511 const GrTextureDesc& desc,
512 uint32_t v[4]) {
513 // Instead of a client-provided key of the texture contents
514 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000515 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000516 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000517 // this code path isn't friendly to tiling with NPOT restricitons
518 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000519 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000520 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000521}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000522}
523
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000524GrContext::TextureCacheEntry GrContext::lockScratchTexture(
525 const GrTextureDesc& inDesc,
526 ScratchTexMatch match) {
527
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000528 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000529 if (kExact_ScratchTexMatch != match) {
530 // bin by pow2 with a reasonable min
531 static const int MIN_SIZE = 256;
532 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
533 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
534 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000535
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000536 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000537 int origWidth = desc.fWidth;
538 int origHeight = desc.fHeight;
539 bool doubledW = false;
540 bool doubledH = false;
541
542 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000543 uint32_t v[4];
544 gen_scratch_tex_key_values(fGpu, desc, v);
545 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000546 entry = fTextureCache->findAndLock(key,
547 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000548 // if we miss, relax the fit of the flags...
549 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000550 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000551 break;
552 }
553 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
554 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
555 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
556 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
557 } else if (!doubledW) {
558 desc.fFlags = inDesc.fFlags;
559 desc.fWidth *= 2;
560 doubledW = true;
561 } else if (!doubledH) {
562 desc.fFlags = inDesc.fFlags;
563 desc.fWidth = origWidth;
564 desc.fHeight *= 2;
565 doubledH = true;
566 } else {
567 break;
568 }
569
570 } while (true);
571
572 if (NULL == entry) {
573 desc.fFlags = inDesc.fFlags;
574 desc.fWidth = origWidth;
575 desc.fHeight = origHeight;
576 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
577 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000578 uint32_t v[4];
579 gen_scratch_tex_key_values(fGpu, desc, v);
580 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000581 entry = fTextureCache->createAndLock(key, texture);
582 }
583 }
584
585 // If the caller gives us the same desc/sampler twice we don't want
586 // to return the same texture the second time (unless it was previously
587 // released). So we detach the entry from the cache and reattach at release.
588 if (NULL != entry) {
589 fTextureCache->detach(entry);
590 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000591 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000592}
593
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000594void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000595 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000596 // If this is a scratch texture we detached it from the cache
597 // while it was locked (to avoid two callers simultaneously getting
598 // the same texture).
599 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
600 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000601 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000602 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000603 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000604}
605
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000606GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000607 void* srcData,
608 size_t rowBytes) {
609 return fGpu->createTexture(desc, srcData, rowBytes);
610}
611
612void GrContext::getTextureCacheLimits(int* maxTextures,
613 size_t* maxTextureBytes) const {
614 fTextureCache->getLimits(maxTextures, maxTextureBytes);
615}
616
617void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
618 fTextureCache->setLimits(maxTextures, maxTextureBytes);
619}
620
bsalomon@google.com91958362011-06-13 17:58:13 +0000621int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000622 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000623}
624
625int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000626 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000627}
628
629///////////////////////////////////////////////////////////////////////////////
630
bsalomon@google.come269f212011-11-07 13:29:52 +0000631GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
632 return fGpu->createPlatformTexture(desc);
633}
634
635GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
636 return fGpu->createPlatformRenderTarget(desc);
637}
638
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000639///////////////////////////////////////////////////////////////////////////////
640
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000641bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000642 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000643 const GrDrawTarget::Caps& caps = fGpu->getCaps();
644 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000645 return false;
646 }
647
bsalomon@google.com27847de2011-02-22 20:59:41 +0000648 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
649
650 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000651 bool tiled = NULL != sampler &&
652 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
653 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000654 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000655 return false;
656 }
657 }
658 return true;
659}
660
661////////////////////////////////////////////////////////////////////////////////
662
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000663const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
664
bsalomon@google.com27847de2011-02-22 20:59:41 +0000665void GrContext::setClip(const GrClip& clip) {
666 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000667 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000668}
669
670void GrContext::setClip(const GrIRect& rect) {
671 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000672 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000673 fGpu->setClip(clip);
674}
675
676////////////////////////////////////////////////////////////////////////////////
677
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000678void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000679 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000680 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000681}
682
683void GrContext::drawPaint(const GrPaint& paint) {
684 // set rect to be big enough to fill the space, but not super-huge, so we
685 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000686 GrRect r;
687 r.setLTRB(0, 0,
688 GrIntToScalar(getRenderTarget()->width()),
689 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000690 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000691 SkTLazy<GrPaint> tmpPaint;
692 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000693 GrAutoMatrix am;
694
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000695 // We attempt to map r by the inverse matrix and draw that. mapRect will
696 // map the four corners and bound them with a new rect. This will not
697 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000698 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000699 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000700 GrPrintf("Could not invert matrix");
701 return;
702 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000703 inverse.mapRect(&r);
704 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000705 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000706 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000707 GrPrintf("Could not invert matrix");
708 return;
709 }
710 tmpPaint.set(paint);
711 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
712 p = tmpPaint.get();
713 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000714 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000715 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000716 // by definition this fills the entire clip, no need for AA
717 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000718 if (!tmpPaint.isValid()) {
719 tmpPaint.set(paint);
720 p = tmpPaint.get();
721 }
722 GrAssert(p == tmpPaint.get());
723 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000724 }
725 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000726}
727
bsalomon@google.com205d4602011-04-25 12:43:45 +0000728////////////////////////////////////////////////////////////////////////////////
729
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000730namespace {
731inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
732 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
733}
734}
735
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000736////////////////////////////////////////////////////////////////////////////////
737
bsalomon@google.com27847de2011-02-22 20:59:41 +0000738/* create a triangle strip that strokes the specified triangle. There are 8
739 unique vertices, but we repreat the last 2 to close up. Alternatively we
740 could use an indices array, and then only send 8 verts, but not sure that
741 would be faster.
742 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000743static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000744 GrScalar width) {
745 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000746 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000747
748 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
749 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
750 verts[2].set(rect.fRight - rad, rect.fTop + rad);
751 verts[3].set(rect.fRight + rad, rect.fTop - rad);
752 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
753 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
754 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
755 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
756 verts[8] = verts[0];
757 verts[9] = verts[1];
758}
759
bsalomon@google.com205d4602011-04-25 12:43:45 +0000760static void setInsetFan(GrPoint* pts, size_t stride,
761 const GrRect& r, GrScalar dx, GrScalar dy) {
762 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
763}
764
765static const uint16_t gFillAARectIdx[] = {
766 0, 1, 5, 5, 4, 0,
767 1, 2, 6, 6, 5, 1,
768 2, 3, 7, 7, 6, 2,
769 3, 0, 4, 4, 7, 3,
770 4, 5, 6, 6, 7, 4,
771};
772
773int GrContext::aaFillRectIndexCount() const {
774 return GR_ARRAY_COUNT(gFillAARectIdx);
775}
776
777GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
778 if (NULL == fAAFillRectIndexBuffer) {
779 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
780 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000781 if (NULL != fAAFillRectIndexBuffer) {
782 #if GR_DEBUG
783 bool updated =
784 #endif
785 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
786 sizeof(gFillAARectIdx));
787 GR_DEBUGASSERT(updated);
788 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000789 }
790 return fAAFillRectIndexBuffer;
791}
792
793static const uint16_t gStrokeAARectIdx[] = {
794 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
795 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
796 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
797 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
798
799 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
800 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
801 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
802 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
803
804 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
805 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
806 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
807 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
808};
809
810int GrContext::aaStrokeRectIndexCount() const {
811 return GR_ARRAY_COUNT(gStrokeAARectIdx);
812}
813
814GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
815 if (NULL == fAAStrokeRectIndexBuffer) {
816 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
817 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000818 if (NULL != fAAStrokeRectIndexBuffer) {
819 #if GR_DEBUG
820 bool updated =
821 #endif
822 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
823 sizeof(gStrokeAARectIdx));
824 GR_DEBUGASSERT(updated);
825 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000826 }
827 return fAAStrokeRectIndexBuffer;
828}
829
bsalomon@google.coma3108262011-10-10 14:08:47 +0000830static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
831 bool useCoverage) {
832 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000833 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000834 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000835 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
836 }
837 }
838 if (useCoverage) {
839 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
840 } else {
841 layout |= GrDrawTarget::kColor_VertexLayoutBit;
842 }
843 return layout;
844}
845
bsalomon@google.com205d4602011-04-25 12:43:45 +0000846void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000847 const GrRect& devRect,
848 bool useVertexCoverage) {
849 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000850
851 size_t vsize = GrDrawTarget::VertexSize(layout);
852
853 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000854 if (!geo.succeeded()) {
855 GrPrintf("Failed to get space for vertices!\n");
856 return;
857 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000858 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
859 if (NULL == indexBuffer) {
860 GrPrintf("Failed to create index buffer!\n");
861 return;
862 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000863
864 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
865
866 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
867 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
868
869 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
870 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
871
872 verts += sizeof(GrPoint);
873 for (int i = 0; i < 4; ++i) {
874 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
875 }
876
bsalomon@google.coma3108262011-10-10 14:08:47 +0000877 GrColor innerColor;
878 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000879 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000880 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000881 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000882 }
883
bsalomon@google.com205d4602011-04-25 12:43:45 +0000884 verts += 4 * vsize;
885 for (int i = 0; i < 4; ++i) {
886 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
887 }
888
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000889 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000890
891 target->drawIndexed(kTriangles_PrimitiveType, 0,
892 0, 8, this->aaFillRectIndexCount());
893}
894
bsalomon@google.coma3108262011-10-10 14:08:47 +0000895void GrContext::strokeAARect(GrDrawTarget* target,
896 const GrRect& devRect,
897 const GrVec& devStrokeSize,
898 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000899 const GrScalar& dx = devStrokeSize.fX;
900 const GrScalar& dy = devStrokeSize.fY;
901 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
902 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
903
bsalomon@google.com205d4602011-04-25 12:43:45 +0000904 GrScalar spare;
905 {
906 GrScalar w = devRect.width() - dx;
907 GrScalar h = devRect.height() - dy;
908 spare = GrMin(w, h);
909 }
910
911 if (spare <= 0) {
912 GrRect r(devRect);
913 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000914 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000915 return;
916 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000917 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000918 size_t vsize = GrDrawTarget::VertexSize(layout);
919
920 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000921 if (!geo.succeeded()) {
922 GrPrintf("Failed to get space for vertices!\n");
923 return;
924 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000925 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
926 if (NULL == indexBuffer) {
927 GrPrintf("Failed to create index buffer!\n");
928 return;
929 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000930
931 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
932
933 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
934 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
935 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
936 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
937
938 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
939 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
940 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
941 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
942
943 verts += sizeof(GrPoint);
944 for (int i = 0; i < 4; ++i) {
945 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
946 }
947
bsalomon@google.coma3108262011-10-10 14:08:47 +0000948 GrColor innerColor;
949 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000950 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000951 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000952 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000953 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000954 verts += 4 * vsize;
955 for (int i = 0; i < 8; ++i) {
956 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
957 }
958
959 verts += 8 * vsize;
960 for (int i = 0; i < 8; ++i) {
961 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
962 }
963
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000964 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000965 target->drawIndexed(kTriangles_PrimitiveType,
966 0, 0, 16, aaStrokeRectIndexCount());
967}
968
reed@google.com20efde72011-05-09 17:00:02 +0000969/**
970 * Returns true if the rects edges are integer-aligned.
971 */
972static bool isIRect(const GrRect& r) {
973 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
974 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
975}
976
bsalomon@google.com205d4602011-04-25 12:43:45 +0000977static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000978 const GrRect& rect,
979 GrScalar width,
980 const GrMatrix* matrix,
981 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000982 GrRect* devRect,
983 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000984 // we use a simple coverage ramp to do aa on axis-aligned rects
985 // we check if the rect will be axis-aligned, and the rect won't land on
986 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000987
bsalomon@google.coma3108262011-10-10 14:08:47 +0000988 // we are keeping around the "tweak the alpha" trick because
989 // it is our only hope for the fixed-pipe implementation.
990 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000991 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000992 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000993 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000994 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000995#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000996 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000997#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000998 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000999 } else {
1000 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001001 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001003 const GrDrawState& drawState = target->getDrawState();
1004 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001005 return false;
1006 }
1007
bsalomon@google.com471d4712011-08-23 15:45:25 +00001008 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001009 return false;
1010 }
1011
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001012 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001013 return false;
1014 }
1015
1016 if (NULL != matrix &&
1017 !matrix->preservesAxisAlignment()) {
1018 return false;
1019 }
1020
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001021 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022 if (NULL != matrix) {
1023 combinedMatrix->preConcat(*matrix);
1024 GrAssert(combinedMatrix->preservesAxisAlignment());
1025 }
1026
1027 combinedMatrix->mapRect(devRect, rect);
1028 devRect->sort();
1029
1030 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001031 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001032 } else {
1033 return true;
1034 }
1035}
1036
bsalomon@google.com27847de2011-02-22 20:59:41 +00001037void GrContext::drawRect(const GrPaint& paint,
1038 const GrRect& rect,
1039 GrScalar width,
1040 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001041 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001042
1043 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001044 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001045
bsalomon@google.com205d4602011-04-25 12:43:45 +00001046 GrRect devRect = rect;
1047 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001048 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001049 bool needAA = paint.fAntiAlias &&
1050 !this->getRenderTarget()->isMultisampled();
1051 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1052 &combinedMatrix, &devRect,
1053 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054
1055 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001056 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001057 if (width >= 0) {
1058 GrVec strokeSize;;
1059 if (width > 0) {
1060 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001061 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001062 strokeSize.setAbs(strokeSize);
1063 } else {
1064 strokeSize.set(GR_Scalar1, GR_Scalar1);
1065 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001066 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001067 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001068 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001069 }
1070 return;
1071 }
1072
bsalomon@google.com27847de2011-02-22 20:59:41 +00001073 if (width >= 0) {
1074 // TODO: consider making static vertex buffers for these cases.
1075 // Hairline could be done by just adding closing vertex to
1076 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001077 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1078
bsalomon@google.com27847de2011-02-22 20:59:41 +00001079 static const int worstCaseVertCount = 10;
1080 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1081
1082 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001083 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001084 return;
1085 }
1086
1087 GrPrimitiveType primType;
1088 int vertCount;
1089 GrPoint* vertex = geo.positions();
1090
1091 if (width > 0) {
1092 vertCount = 10;
1093 primType = kTriangleStrip_PrimitiveType;
1094 setStrokeRectStrip(vertex, rect, width);
1095 } else {
1096 // hairline
1097 vertCount = 5;
1098 primType = kLineStrip_PrimitiveType;
1099 vertex[0].set(rect.fLeft, rect.fTop);
1100 vertex[1].set(rect.fRight, rect.fTop);
1101 vertex[2].set(rect.fRight, rect.fBottom);
1102 vertex[3].set(rect.fLeft, rect.fBottom);
1103 vertex[4].set(rect.fLeft, rect.fTop);
1104 }
1105
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001106 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001107 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001108 GrDrawState* drawState = target->drawState();
1109 avmr.set(drawState);
1110 drawState->preConcatViewMatrix(*matrix);
1111 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001112 }
1113
1114 target->drawNonIndexed(primType, 0, vertCount);
1115 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001116#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001117 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001118 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1119 if (NULL == sqVB) {
1120 GrPrintf("Failed to create static rect vb.\n");
1121 return;
1122 }
1123 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001124 GrDrawState* drawState = target->drawState();
1125 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001126 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001127 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001128 0, rect.height(), rect.fTop,
1129 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130
1131 if (NULL != matrix) {
1132 m.postConcat(*matrix);
1133 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001134 drawState->preConcatViewMatrix(m);
1135 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001136
bsalomon@google.com27847de2011-02-22 20:59:41 +00001137 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001138#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001139 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001140#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001141 }
1142}
1143
1144void GrContext::drawRectToRect(const GrPaint& paint,
1145 const GrRect& dstRect,
1146 const GrRect& srcRect,
1147 const GrMatrix* dstMatrix,
1148 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001149 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001150
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001151 // srcRect refers to paint's first texture
1152 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001153 drawRect(paint, dstRect, -1, dstMatrix);
1154 return;
1155 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001156
bsalomon@google.com27847de2011-02-22 20:59:41 +00001157 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1158
1159#if GR_STATIC_RECT_VB
1160 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001161 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001162 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001163 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001164
1165 GrMatrix m;
1166
1167 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1168 0, dstRect.height(), dstRect.fTop,
1169 0, 0, GrMatrix::I()[8]);
1170 if (NULL != dstMatrix) {
1171 m.postConcat(*dstMatrix);
1172 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001173 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001174
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001175 // srcRect refers to first stage
1176 int otherStageMask = paint.getActiveStageMask() &
1177 (~(1 << GrPaint::kFirstTextureStage));
1178 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001179 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001180 }
1181
bsalomon@google.com27847de2011-02-22 20:59:41 +00001182 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1183 0, srcRect.height(), srcRect.fTop,
1184 0, 0, GrMatrix::I()[8]);
1185 if (NULL != srcMatrix) {
1186 m.postConcat(*srcMatrix);
1187 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001188 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001189
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001190 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1191 if (NULL == sqVB) {
1192 GrPrintf("Failed to create static rect vb.\n");
1193 return;
1194 }
1195 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1197#else
1198
1199 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001200#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001201 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001202#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001203 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1204#endif
1205
tomhudson@google.com93813632011-10-27 20:21:16 +00001206 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1207 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001208 srcRects[0] = &srcRect;
1209 srcMatrices[0] = srcMatrix;
1210
1211 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1212#endif
1213}
1214
1215void GrContext::drawVertices(const GrPaint& paint,
1216 GrPrimitiveType primitiveType,
1217 int vertexCount,
1218 const GrPoint positions[],
1219 const GrPoint texCoords[],
1220 const GrColor colors[],
1221 const uint16_t indices[],
1222 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001223 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001224
1225 GrDrawTarget::AutoReleaseGeometry geo;
1226
1227 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1228
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001229 bool hasTexCoords[GrPaint::kTotalStages] = {
1230 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1231 0 // remaining stages use positions
1232 };
1233
1234 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001235
1236 if (NULL != colors) {
1237 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001238 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001239 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240
1241 if (sizeof(GrPoint) != vertexSize) {
1242 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001243 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001244 return;
1245 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001246 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001247 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001248 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1249 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001250 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001251 NULL,
1252 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253 void* curVertex = geo.vertices();
1254
1255 for (int i = 0; i < vertexCount; ++i) {
1256 *((GrPoint*)curVertex) = positions[i];
1257
1258 if (texOffsets[0] > 0) {
1259 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1260 }
1261 if (colorOffset > 0) {
1262 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1263 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001264 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265 }
1266 } else {
1267 target->setVertexSourceToArray(layout, positions, vertexCount);
1268 }
1269
bsalomon@google.com91958362011-06-13 17:58:13 +00001270 // we don't currently apply offscreen AA to this path. Need improved
1271 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001272
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001273 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001274 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001275 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001277 target->drawNonIndexed(primitiveType, 0, vertexCount);
1278 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001279}
1280
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001281///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001282namespace {
1283
bsalomon@google.com93c96602012-04-27 13:05:21 +00001284struct CircleVertex {
1285 GrPoint fPos;
1286 GrPoint fCenter;
1287 GrScalar fOuterRadius;
1288 GrScalar fInnerRadius;
1289};
1290
1291/* Returns true if will map a circle to another circle. This can be true
1292 * if the matrix only includes square-scale, rotation, translation.
1293 */
1294inline bool isSimilarityTransformation(const SkMatrix& matrix,
1295 SkScalar tol = SK_ScalarNearlyZero) {
1296 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1297 return true;
1298 }
1299 if (matrix.hasPerspective()) {
1300 return false;
1301 }
1302
1303 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1304 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1305 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1306 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1307
1308 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1309 return false;
1310 }
1311
1312 // it has scales or skews, but it could also be rotation, check it out.
1313 SkVector vec[2];
1314 vec[0].set(mx, sx);
1315 vec[1].set(sy, my);
1316
1317 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1318 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1319 SkScalarSquare(tol));
1320}
1321
1322}
1323
1324// TODO: strokeWidth can't be larger than zero right now.
1325// It will be fixed when drawPath() can handle strokes.
1326void GrContext::drawOval(const GrPaint& paint,
1327 const GrRect& rect,
1328 SkScalar strokeWidth) {
1329 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1330 kUnbuffered_DrawCategory;
1331 GrDrawTarget* target = this->prepareToDraw(paint, category);
1332 GrDrawState* drawState = target->drawState();
1333 GrMatrix vm = drawState->getViewMatrix();
1334
1335 if (!isSimilarityTransformation(vm) ||
1336 !paint.fAntiAlias ||
1337 rect.height() != rect.width()) {
1338 SkPath path;
1339 path.addOval(rect);
1340 GrPathFill fill = (strokeWidth == 0) ?
1341 kHairLine_PathFill : kWinding_PathFill;
1342 this->internalDrawPath(paint, path, fill, NULL);
1343 return;
1344 }
1345
1346 const GrRenderTarget* rt = drawState->getRenderTarget();
1347 if (NULL == rt) {
1348 return;
1349 }
1350
1351 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1352
1353 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1354 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1355 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1356
1357 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1358 GrScalar radius = SkScalarHalf(rect.width());
1359
1360 vm.mapPoints(&center, 1);
1361 radius = vm.mapRadius(radius);
1362
1363 GrScalar outerRadius = radius;
1364 GrScalar innerRadius = 0;
1365 SkScalar halfWidth = 0;
1366 if (strokeWidth == 0) {
1367 halfWidth = SkScalarHalf(SK_Scalar1);
1368
1369 outerRadius += halfWidth;
1370 innerRadius = SkMaxScalar(0, radius - halfWidth);
1371 }
1372
1373 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1374 if (!geo.succeeded()) {
1375 GrPrintf("Failed to get space for vertices!\n");
1376 return;
1377 }
1378
1379 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1380
1381 SkScalar L = center.fX - outerRadius;
1382 SkScalar R = center.fX + outerRadius;
1383 SkScalar T = center.fY - outerRadius;
1384 SkScalar B = center.fY + outerRadius;
1385
1386 verts[0].fPos = SkPoint::Make(L, T);
1387 verts[1].fPos = SkPoint::Make(R, T);
1388 verts[2].fPos = SkPoint::Make(L, B);
1389 verts[3].fPos = SkPoint::Make(R, B);
1390
1391 for (int i = 0; i < 4; ++i) {
1392 // this goes to fragment shader, it should be in y-points-up space.
1393 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1394
1395 verts[i].fOuterRadius = outerRadius;
1396 verts[i].fInnerRadius = innerRadius;
1397 }
1398
1399 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
1400 target->drawNonIndexed(kTriangleStrip_PrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001401}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001403void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001404 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001406 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001407 if (GrIsFillInverted(fill)) {
1408 this->drawPaint(paint);
1409 }
1410 return;
1411 }
1412
bsalomon@google.com93c96602012-04-27 13:05:21 +00001413 SkRect ovalRect;
1414 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1415 if (translate) {
1416 ovalRect.offset(*translate);
1417 }
bsalomon@google.come7655f12012-04-27 13:55:29 +00001418 SkScalar width = (fill == kHairLine_PathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001419 this->drawOval(paint, ovalRect, width);
1420 return;
1421 }
1422
1423 internalDrawPath(paint, path, fill, translate);
1424}
1425
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001426void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001427 GrPathFill fill, const GrPoint* translate) {
1428
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001429 // Note that below we may sw-rasterize the path into a scratch texture.
1430 // Scratch textures can be recycled after they are returned to the texture
1431 // cache. This presents a potential hazard for buffered drawing. However,
1432 // the writePixels that uploads to the scratch will perform a flush so we're
1433 // OK.
1434 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1435 kUnbuffered_DrawCategory;
1436 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001437 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001438
bsalomon@google.com289533a2011-10-27 12:34:25 +00001439 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1440
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001441 // An Assumption here is that path renderer would use some form of tweaking
1442 // the src color (either the input alpha or in the frag shader) to implement
1443 // aa. If we have some future driver-mojo path AA that can do the right
1444 // thing WRT to the blend then we'll need some query on the PR.
1445 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001446#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001447 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001448#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001449 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001450 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001451
robertphillips@google.comed4155d2012-05-01 14:30:24 +00001452 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA);
bsalomon@google.com30085192011-08-19 15:42:31 +00001453 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001454#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001455 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001456#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001457 return;
1458 }
1459
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001460 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001462
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463////////////////////////////////////////////////////////////////////////////////
1464
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001465void GrContext::flush(int flagsBitfield) {
1466 if (kDiscard_FlushBit & flagsBitfield) {
1467 fDrawBuffer->reset();
1468 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001469 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001470 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001471 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472 fGpu->forceRenderTargetFlush();
1473 }
1474}
1475
bsalomon@google.com27847de2011-02-22 20:59:41 +00001476void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001477 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001478 // With addition of the AA clip path, flushing the draw buffer can
1479 // result in the generation of an AA clip mask. During this
1480 // process the SW path renderer may be invoked which recusively
1481 // calls this method (via internalWriteTexturePixels) creating
1482 // infinite recursion
1483 GrInOrderDrawBuffer* temp = fDrawBuffer;
1484 fDrawBuffer = NULL;
1485
1486 temp->flushTo(fGpu);
1487
1488 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001489 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001490}
1491
bsalomon@google.com6f379512011-11-16 20:36:03 +00001492void GrContext::internalWriteTexturePixels(GrTexture* texture,
1493 int left, int top,
1494 int width, int height,
1495 GrPixelConfig config,
1496 const void* buffer,
1497 size_t rowBytes,
1498 uint32_t flags) {
1499 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001500 ASSERT_OWNED_RESOURCE(texture);
1501
bsalomon@google.com6f379512011-11-16 20:36:03 +00001502 if (!(kDontFlush_PixelOpsFlag & flags)) {
1503 this->flush();
1504 }
1505 // TODO: use scratch texture to perform conversion
1506 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1507 GrPixelConfigIsUnpremultiplied(config)) {
1508 return;
1509 }
1510
1511 fGpu->writeTexturePixels(texture, left, top, width, height,
1512 config, buffer, rowBytes);
1513}
1514
1515bool GrContext::internalReadTexturePixels(GrTexture* texture,
1516 int left, int top,
1517 int width, int height,
1518 GrPixelConfig config,
1519 void* buffer,
1520 size_t rowBytes,
1521 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001522 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001523 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001524
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001525 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001526 GrRenderTarget* target = texture->asRenderTarget();
1527 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001528 return this->internalReadRenderTargetPixels(target,
1529 left, top, width, height,
1530 config, buffer, rowBytes,
1531 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001532 } else {
1533 return false;
1534 }
1535}
1536
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001537#include "SkConfig8888.h"
1538
1539namespace {
1540/**
1541 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1542 * formats are representable as Config8888 and so the function returns false
1543 * if the GrPixelConfig has no equivalent Config8888.
1544 */
1545bool grconfig_to_config8888(GrPixelConfig config,
1546 SkCanvas::Config8888* config8888) {
1547 switch (config) {
1548 case kRGBA_8888_PM_GrPixelConfig:
1549 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1550 return true;
1551 case kRGBA_8888_UPM_GrPixelConfig:
1552 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1553 return true;
1554 case kBGRA_8888_PM_GrPixelConfig:
1555 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1556 return true;
1557 case kBGRA_8888_UPM_GrPixelConfig:
1558 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1559 return true;
1560 default:
1561 return false;
1562 }
1563}
1564}
1565
bsalomon@google.com6f379512011-11-16 20:36:03 +00001566bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1567 int left, int top,
1568 int width, int height,
1569 GrPixelConfig config,
1570 void* buffer,
1571 size_t rowBytes,
1572 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001573 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001574 ASSERT_OWNED_RESOURCE(target);
1575
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001576 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001577 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001578 if (NULL == target) {
1579 return false;
1580 }
1581 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001582
bsalomon@google.com6f379512011-11-16 20:36:03 +00001583 if (!(kDontFlush_PixelOpsFlag & flags)) {
1584 this->flush();
1585 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001586
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001587 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1588 GrPixelConfigIsUnpremultiplied(config) &&
1589 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1590 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1591 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1592 !grconfig_to_config8888(config, &dstConfig8888)) {
1593 return false;
1594 }
1595 // do read back using target's own config
1596 this->internalReadRenderTargetPixels(target,
1597 left, top,
1598 width, height,
1599 target->config(),
1600 buffer, rowBytes,
1601 kDontFlush_PixelOpsFlag);
1602 // sw convert the pixels to unpremul config
1603 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1604 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1605 pixels, rowBytes, srcConfig8888,
1606 width, height);
1607 return true;
1608 }
1609
bsalomon@google.comc4364992011-11-07 15:54:49 +00001610 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001611 bool swapRAndB = NULL != src &&
1612 fGpu->preferredReadPixelsConfig(config) ==
1613 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001614
1615 bool flipY = NULL != src &&
1616 fGpu->readPixelsWillPayForYFlip(target, left, top,
1617 width, height, config,
1618 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001619 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1620 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001621
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001622 if (NULL == src && alphaConversion) {
1623 // we should fallback to cpu conversion here. This could happen when
1624 // we were given an external render target by the client that is not
1625 // also a texture (e.g. FBO 0 in GL)
1626 return false;
1627 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001628 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001629 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001630 if (flipY || swapRAndB || alphaConversion) {
1631 GrAssert(NULL != src);
1632 if (swapRAndB) {
1633 config = GrPixelConfigSwapRAndB(config);
1634 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001635 }
1636 // Make the scratch a render target because we don't have a robust
1637 // readTexturePixels as of yet (it calls this function).
1638 const GrTextureDesc desc = {
1639 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001640 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001641 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001642 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001643 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001644
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001645 // When a full readback is faster than a partial we could always make
1646 // the scratch exactly match the passed rect. However, if we see many
1647 // different size rectangles we will trash our texture cache and pay the
1648 // cost of creating and destroying many textures. So, we only request
1649 // an exact match when the caller is reading an entire RT.
1650 ScratchTexMatch match = kApprox_ScratchTexMatch;
1651 if (0 == left &&
1652 0 == top &&
1653 target->width() == width &&
1654 target->height() == height &&
1655 fGpu->fullReadPixelsIsFasterThanPartial()) {
1656 match = kExact_ScratchTexMatch;
1657 }
1658 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001659 GrTexture* texture = ast.texture();
1660 if (!texture) {
1661 return false;
1662 }
1663 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001664 GrAssert(NULL != target);
1665
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001666 GrDrawTarget::AutoStateRestore asr(fGpu,
1667 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001668 GrDrawState* drawState = fGpu->drawState();
1669 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001670
bsalomon@google.comc4364992011-11-07 15:54:49 +00001671 GrMatrix matrix;
1672 if (flipY) {
1673 matrix.setTranslate(SK_Scalar1 * left,
1674 SK_Scalar1 * (top + height));
1675 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1676 } else {
1677 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1678 }
1679 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001680 drawState->sampler(0)->reset(matrix);
1681 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001682 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001683 GrRect rect;
1684 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1685 fGpu->drawSimpleRect(rect, NULL, 0x1);
1686 left = 0;
1687 top = 0;
1688 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001689 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001690 left, top, width, height,
1691 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001692}
1693
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001694void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1695 GrAssert(target);
1696 ASSERT_OWNED_RESOURCE(target);
1697 // In the future we may track whether there are any pending draws to this
1698 // target. We don't today so we always perform a flush. We don't promise
1699 // this to our clients, though.
1700 this->flush();
1701 fGpu->resolveRenderTarget(target);
1702}
1703
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001704void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1705 if (NULL == src || NULL == dst) {
1706 return;
1707 }
1708 ASSERT_OWNED_RESOURCE(src);
1709
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001710 // Writes pending to the source texture are not tracked, so a flush
1711 // is required to ensure that the copy captures the most recent contents
1712 // of the source texture. See similar behaviour in
1713 // GrContext::resolveRenderTarget.
1714 this->flush();
1715
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001716 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001717 GrDrawState* drawState = fGpu->drawState();
1718 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001719 GrMatrix sampleM;
1720 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001721 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001722 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001723 SkRect rect = SkRect::MakeXYWH(0, 0,
1724 SK_Scalar1 * src->width(),
1725 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001726 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1727}
1728
bsalomon@google.com6f379512011-11-16 20:36:03 +00001729void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1730 int left, int top,
1731 int width, int height,
1732 GrPixelConfig config,
1733 const void* buffer,
1734 size_t rowBytes,
1735 uint32_t flags) {
1736 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001737 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001738
1739 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001740 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001741 if (NULL == target) {
1742 return;
1743 }
1744 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001745
1746 // TODO: when underlying api has a direct way to do this we should use it
1747 // (e.g. glDrawPixels on desktop GL).
1748
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001749 // If the RT is also a texture and we don't have to do PM/UPM conversion
1750 // then take the texture path, which we expect to be at least as fast or
1751 // faster since it doesn't use an intermediate texture as we do below.
1752
1753#if !GR_MAC_BUILD
1754 // At least some drivers on the Mac get confused when glTexImage2D is called
1755 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1756 // determine what OS versions and/or HW is affected.
1757 if (NULL != target->asTexture() &&
1758 GrPixelConfigIsUnpremultiplied(target->config()) ==
1759 GrPixelConfigIsUnpremultiplied(config)) {
1760
1761 this->internalWriteTexturePixels(target->asTexture(),
1762 left, top, width, height,
1763 config, buffer, rowBytes, flags);
1764 return;
1765 }
1766#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001767 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1768 GrPixelConfigIsUnpremultiplied(config) &&
1769 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1770 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1771 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1772 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1773 return;
1774 }
1775 // allocate a tmp buffer and sw convert the pixels to premul
1776 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1777 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1778 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1779 src, rowBytes, srcConfig8888,
1780 width, height);
1781 // upload the already premul pixels
1782 this->internalWriteRenderTargetPixels(target,
1783 left, top,
1784 width, height,
1785 target->config(),
1786 tmpPixels, 4 * width, flags);
1787 return;
1788 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001789
1790 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1791 GrPixelConfigSwapRAndB(config);
1792 if (swapRAndB) {
1793 config = GrPixelConfigSwapRAndB(config);
1794 }
1795
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001796 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001797 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001798 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001799 GrAutoScratchTexture ast(this, desc);
1800 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001801 if (NULL == texture) {
1802 return;
1803 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001804 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1805 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001806
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001807 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001808 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001809
1810 GrMatrix matrix;
1811 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001812 drawState->setViewMatrix(matrix);
1813 drawState->setRenderTarget(target);
1814 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001815
bsalomon@google.com5c638652011-07-18 19:31:59 +00001816 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001817 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1818 GrSamplerState::kNearest_Filter,
1819 matrix);
1820 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001821
1822 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1823 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001824 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001825 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1826 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001827 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001828 return;
1829 }
1830 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1831 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1832}
1833////////////////////////////////////////////////////////////////////////////////
1834
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001835void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001836
1837 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1838 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001839 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001840 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001841 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001842 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001843 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001844 }
1845
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001846 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001847
1848 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1849 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001850 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001851 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001852 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001853 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001854 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001855 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001856
1857 // disable all stages not accessible via the paint
1858 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001859 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001860 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001861
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001862 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001863
1864 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001865 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001866 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001867 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868 }
1869 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001870 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001872 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001873 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001874 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001875 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1876 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001877 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001878 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001879 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001880 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1881 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1882 fDrawState->setCoverage(paint.fCoverage);
reed@google.com4b2d3f32012-05-15 18:05:50 +00001883#if GR_DEBUG_PARTIAL_COVERAGE_CHECK
bsalomon@google.come79c8152012-03-29 19:07:12 +00001884 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001885 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001886 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1887 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001888#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889}
1890
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001891GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001892 DrawCategory category) {
1893 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001894 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001895 fLastDrawCategory = category;
1896 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001897 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001898 GrDrawTarget* target = fGpu;
1899 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001900 case kUnbuffered_DrawCategory:
1901 target = fGpu;
1902 break;
1903 case kBuffered_DrawCategory:
1904 target = fDrawBuffer;
1905 fDrawBuffer->setClip(fGpu->getClip());
1906 break;
1907 default:
1908 GrCrash("Unexpected DrawCategory.");
1909 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001910 }
1911 return target;
1912}
1913
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001914GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001915 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001916 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001917 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001918 if (NULL == fPathRendererChain) {
1919 fPathRendererChain =
1920 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1921 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001922 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001923}
1924
bsalomon@google.com27847de2011-02-22 20:59:41 +00001925////////////////////////////////////////////////////////////////////////////////
1926
bsalomon@google.com27847de2011-02-22 20:59:41 +00001927void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001928 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001929 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001930 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001931 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001932 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001933}
1934
1935GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001936 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001937}
1938
1939const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001940 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001941}
1942
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001943bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1944 return fGpu->isConfigRenderable(config);
1945}
1946
bsalomon@google.com27847de2011-02-22 20:59:41 +00001947const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001948 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001949}
1950
1951void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001952 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001953}
1954
1955void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001956 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001957}
1958
1959static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1960 intptr_t mask = 1 << shift;
1961 if (pred) {
1962 bits |= mask;
1963 } else {
1964 bits &= ~mask;
1965 }
1966 return bits;
1967}
1968
1969void GrContext::resetStats() {
1970 fGpu->resetStats();
1971}
1972
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001973const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001974 return fGpu->getStats();
1975}
1976
1977void GrContext::printStats() const {
1978 fGpu->printStats();
1979}
1980
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001981GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982 fGpu = gpu;
1983 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001984 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001985
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001986 fDrawState = new GrDrawState();
1987 fGpu->setDrawState(fDrawState);
1988
bsalomon@google.com30085192011-08-19 15:42:31 +00001989 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001990
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001991 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1992 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993 fFontCache = new GrFontCache(fGpu);
1994
1995 fLastDrawCategory = kUnbuffered_DrawCategory;
1996
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001997 fDrawBuffer = NULL;
1998 fDrawBufferVBAllocPool = NULL;
1999 fDrawBufferIBAllocPool = NULL;
2000
bsalomon@google.com205d4602011-04-25 12:43:45 +00002001 fAAFillRectIndexBuffer = NULL;
2002 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002003
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002004 this->setupDrawBuffer();
2005}
2006
2007void GrContext::setupDrawBuffer() {
2008
2009 GrAssert(NULL == fDrawBuffer);
2010 GrAssert(NULL == fDrawBufferVBAllocPool);
2011 GrAssert(NULL == fDrawBufferIBAllocPool);
2012
bsalomon@google.com92edd312012-04-04 21:40:21 +00002013#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002014 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002015 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002016 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2017 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002018 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002019 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002020 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002021 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2022
bsalomon@google.com471d4712011-08-23 15:45:25 +00002023 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2024 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002025 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002026#endif
2027
2028#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00002029 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00002030#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00002031 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002032 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002033}
2034
bsalomon@google.com27847de2011-02-22 20:59:41 +00002035GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002036#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00002037 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002038#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00002039 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002040#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002041}
2042
2043const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2044 return fGpu->getQuadIndexBuffer();
2045}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002046
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002047GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
2048 GrAutoScratchTexture* temp1,
2049 GrAutoScratchTexture* temp2,
2050 const SkRect& rect,
2051 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002052 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002053 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2054 GrClip oldClip = this->getClip();
2055 GrTexture* origTexture = srcTexture;
2056 GrAutoMatrix avm(this, GrMatrix::I());
2057 SkIRect clearRect;
2058 int scaleFactorX, halfWidthX, kernelWidthX;
2059 int scaleFactorY, halfWidthY, kernelWidthY;
2060 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
2061 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002062
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002063 SkRect srcRect(rect);
2064 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
2065 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00002066 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
2067 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002068 this->setClip(srcRect);
2069
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002070 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
2071 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
2072 kAlpha_8_GrPixelConfig == srcTexture->config());
2073
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002074 const GrTextureDesc desc = {
2075 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00002076 SkScalarFloorToInt(srcRect.width()),
2077 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002078 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002079 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002080 };
2081
2082 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002083 if (temp2) {
2084 temp2->set(this, desc);
2085 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002086
2087 GrTexture* dstTexture = temp1->texture();
2088 GrPaint paint;
2089 paint.reset();
2090 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2091
2092 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2093 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2094 srcTexture->height());
2095 this->setRenderTarget(dstTexture->asRenderTarget());
2096 SkRect dstRect(srcRect);
2097 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2098 i < scaleFactorY ? 0.5f : 1.0f);
2099 paint.setTexture(0, srcTexture);
2100 this->drawRectToRect(paint, dstRect, srcRect);
2101 srcRect = dstRect;
2102 SkTSwap(srcTexture, dstTexture);
2103 // If temp2 is non-NULL, don't render back to origTexture
2104 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2105 }
2106
robertphillips@google.com7a396332012-05-10 15:11:27 +00002107 SkIRect srcIRect;
2108 srcRect.roundOut(&srcIRect);
2109
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002110 if (sigmaX > 0.0f) {
2111 SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
2112 float* kernelX = kernelStorageX.get();
2113 build_kernel(sigmaX, kernelX, kernelWidthX);
2114
2115 if (scaleFactorX > 1) {
2116 // Clear out a halfWidth to the right of the srcRect to prevent the
2117 // X convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002118 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2119 halfWidthX, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002120 this->clear(&clearRect, 0x0);
2121 }
2122
2123 this->setRenderTarget(dstTexture->asRenderTarget());
2124 convolve(fGpu, srcTexture, srcRect, kernelX, kernelWidthX,
2125 GrSamplerState::kX_FilterDirection);
2126 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002127 if (temp2 && dstTexture == origTexture) {
2128 dstTexture = temp2->texture();
2129 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002130 }
2131
2132 if (sigmaY > 0.0f) {
2133 SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
2134 float* kernelY = kernelStorageY.get();
2135 build_kernel(sigmaY, kernelY, kernelWidthY);
2136
2137 if (scaleFactorY > 1 || sigmaX > 0.0f) {
2138 // Clear out a halfWidth below the srcRect to prevent the Y
2139 // convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002140 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2141 srcIRect.width(), halfWidthY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002142 this->clear(&clearRect, 0x0);
2143 }
2144
2145 this->setRenderTarget(dstTexture->asRenderTarget());
2146 convolve(fGpu, srcTexture, srcRect, kernelY, kernelWidthY,
2147 GrSamplerState::kY_FilterDirection);
2148 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002149 if (temp2 && dstTexture == origTexture) {
2150 dstTexture = temp2->texture();
2151 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002152 }
2153
2154 if (scaleFactorX > 1 || scaleFactorY > 1) {
2155 // Clear one pixel to the right and below, to accommodate bilinear
2156 // upsampling.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002157 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2158 srcIRect.width() + 1, 1);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002159 this->clear(&clearRect, 0x0);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002160 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2161 1, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002162 this->clear(&clearRect, 0x0);
2163 // FIXME: This should be mitchell, not bilinear.
2164 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2165 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2166 srcTexture->height());
2167 this->setRenderTarget(dstTexture->asRenderTarget());
2168 paint.setTexture(0, srcTexture);
2169 SkRect dstRect(srcRect);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002170 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002171 this->drawRectToRect(paint, dstRect, srcRect);
2172 srcRect = dstRect;
2173 SkTSwap(srcTexture, dstTexture);
2174 }
2175 this->setRenderTarget(oldRenderTarget);
2176 this->setClip(oldClip);
2177 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002178}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002179
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002180GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2181 const GrRect& rect,
2182 GrTexture* temp1, GrTexture* temp2,
2183 GrSamplerState::Filter filter,
2184 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002185 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002186 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2187 GrAutoMatrix avm(this, GrMatrix::I());
2188 GrClip oldClip = this->getClip();
robertphillips@google.com7a396332012-05-10 15:11:27 +00002189 this->setClip(GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
2190 SkIntToScalar(srcTexture->height())));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002191 if (radius.fWidth > 0) {
2192 this->setRenderTarget(temp1->asRenderTarget());
2193 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, filter,
2194 GrSamplerState::kX_FilterDirection);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002195 SkIRect clearRect = SkIRect::MakeXYWH(
2196 SkScalarFloorToInt(rect.fLeft),
2197 SkScalarFloorToInt(rect.fBottom),
2198 SkScalarFloorToInt(rect.width()),
2199 radius.fHeight);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002200 this->clear(&clearRect, 0x0);
2201 srcTexture = temp1;
2202 }
2203 if (radius.fHeight > 0) {
2204 this->setRenderTarget(temp2->asRenderTarget());
2205 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, filter,
2206 GrSamplerState::kY_FilterDirection);
2207 srcTexture = temp2;
2208 }
2209 this->setRenderTarget(oldRenderTarget);
2210 this->setClip(oldClip);
2211 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002212}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002213
2214///////////////////////////////////////////////////////////////////////////////