blob: 1c55ecf627e0113d5b4269316a43c488882b4938 [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
bsalomon@google.comb505a122012-05-31 18:40:36 +000012#include "effects/GrMorphologyEffect.h"
13#include "effects/GrConvolutionEffect.h"
14
tomhudson@google.com278cbb42011-06-30 19:37:01 +000015#include "GrBufferAllocPool.h"
16#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000017#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000018#include "GrIndexBuffer.h"
19#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000020#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000021#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000022#include "GrResourceCache.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000023#include "GrSoftwarePathRenderer.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000024#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000025#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000026#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000027#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000028
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000029#define DEFER_TEXT_RENDERING 1
bsalomon@google.com27847de2011-02-22 20:59:41 +000030
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000031#define DEFER_PATHS 1
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000032
bsalomon@google.com3c4d0322012-04-03 18:04:51 +000033#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
bsalomon@google.com27847de2011-02-22 20:59:41 +000034
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +000035#define MAX_BLUR_SIGMA 4.0f
36
bsalomon@google.comd46e2422011-09-23 17:40:07 +000037// When we're using coverage AA but the blend is incompatible (given gpu
38// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000039#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000040
reed@google.com4b2d3f32012-05-15 18:05:50 +000041#if GR_DEBUG
42 // change this to a 1 to see notifications when partial coverage fails
43 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
44#else
45 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
46#endif
47
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000048static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
49static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000050
bsalomon@google.com60361492012-03-15 17:47:06 +000051static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000052static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
53
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +000054// path rendering is the only thing we defer today that uses non-static indices
55static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = DEFER_PATHS ? 1 << 11 : 0;
56static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = DEFER_PATHS ? 4 : 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +000057
bsalomon@google.combc4b6542011-11-19 13:56:11 +000058#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
59
bsalomon@google.com05ef5102011-05-02 21:14:59 +000060GrContext* GrContext::Create(GrEngine engine,
61 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 GrContext* ctx = NULL;
63 GrGpu* fGpu = GrGpu::Create(engine, context3D);
64 if (NULL != fGpu) {
65 ctx = new GrContext(fGpu);
66 fGpu->unref();
67 }
68 return ctx;
69}
70
bsalomon@google.com27847de2011-02-22 20:59:41 +000071GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000072 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +000073
74 // Since the gpu can hold scratch textures, give it a chance to let go
75 // of them before freeing the texture cache
76 fGpu->purgeResources();
77
bsalomon@google.com27847de2011-02-22 20:59:41 +000078 delete fTextureCache;
79 delete fFontCache;
80 delete fDrawBuffer;
81 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000082 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000083
bsalomon@google.com205d4602011-04-25 12:43:45 +000084 GrSafeUnref(fAAFillRectIndexBuffer);
85 GrSafeUnref(fAAStrokeRectIndexBuffer);
86 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000087 GrSafeUnref(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +000088 GrSafeUnref(fSoftwarePathRenderer);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +000089 fDrawState->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000090}
91
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000093 contextDestroyed();
94 this->setupDrawBuffer();
95}
96
97void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 // abandon first to so destructors
99 // don't try to free the resources in the API.
100 fGpu->abandonResources();
101
bsalomon@google.com30085192011-08-19 15:42:31 +0000102 // a path renderer may be holding onto resources that
103 // are now unusable
104 GrSafeSetNull(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +0000105 GrSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com30085192011-08-19 15:42:31 +0000106
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000107 delete fDrawBuffer;
108 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000109
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000110 delete fDrawBufferVBAllocPool;
111 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000112
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000113 delete fDrawBufferIBAllocPool;
114 fDrawBufferIBAllocPool = NULL;
115
bsalomon@google.com205d4602011-04-25 12:43:45 +0000116 GrSafeSetNull(fAAFillRectIndexBuffer);
117 GrSafeSetNull(fAAStrokeRectIndexBuffer);
118
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000119 fTextureCache->removeAll();
120 fFontCache->freeAll();
121 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000122}
123
124void GrContext::resetContext() {
125 fGpu->markContextDirty();
126}
127
128void GrContext::freeGpuResources() {
129 this->flush();
robertphillips@google.comff175842012-05-14 19:31:39 +0000130
131 fGpu->purgeResources();
132
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000133 fTextureCache->removeAll();
134 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000135 // a path renderer may be holding onto resources
136 GrSafeSetNull(fPathRendererChain);
robertphillips@google.com72176b22012-05-23 13:19:12 +0000137 GrSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000138}
139
twiz@google.com05e70242012-01-27 19:12:00 +0000140size_t GrContext::getGpuTextureCacheBytes() const {
141 return fTextureCache->getCachedResourceBytes();
142}
143
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000144////////////////////////////////////////////////////////////////////////////////
145
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000146int GrContext::PaintStageVertexLayoutBits(
147 const GrPaint& paint,
148 const bool hasTexCoords[GrPaint::kTotalStages]) {
149 int stageMask = paint.getActiveStageMask();
150 int layout = 0;
151 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
152 if ((1 << i) & stageMask) {
153 if (NULL != hasTexCoords && hasTexCoords[i]) {
154 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
155 } else {
156 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
157 }
158 }
159 }
160 return layout;
161}
162
163
164////////////////////////////////////////////////////////////////////////////////
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 {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000175
176// we should never have more than one stencil buffer with same combo of
177// (width,height,samplecount)
178void gen_stencil_key_values(int width, int height,
179 int sampleCnt, uint32_t v[4]) {
180 v[0] = width;
181 v[1] = height;
182 v[2] = sampleCnt;
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000183 v[3] = GrResourceKey::kStencilBuffer_TypeBit;
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000184}
185
186void gen_stencil_key_values(const GrStencilBuffer* sb,
187 uint32_t v[4]) {
188 gen_stencil_key_values(sb->width(), sb->height(),
189 sb->numSamples(), v);
190}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000191
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000192void scale_rect(SkRect* rect, float xScale, float yScale) {
robertphillips@google.com5af56062012-04-27 15:39:52 +0000193 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
194 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
195 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
196 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000197}
198
bsalomon@google.comb505a122012-05-31 18:40:36 +0000199float adjust_sigma(float sigma, int *scaleFactor, int *radius) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000200 *scaleFactor = 1;
201 while (sigma > MAX_BLUR_SIGMA) {
202 *scaleFactor *= 2;
203 sigma *= 0.5f;
204 }
bsalomon@google.comb505a122012-05-31 18:40:36 +0000205 *radius = static_cast<int>(ceilf(sigma * 3.0f));
206 GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000207 return sigma;
208}
209
210void apply_morphology(GrGpu* gpu,
211 GrTexture* texture,
212 const SkRect& rect,
213 int radius,
bsalomon@google.comb505a122012-05-31 18:40:36 +0000214 GrContext::MorphologyType morphType,
215 Gr1DKernelEffect::Direction direction) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000216
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000217 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
218 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000219 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000220 drawState->setRenderTarget(target);
221 GrMatrix sampleM;
222 sampleM.setIDiv(texture->width(), texture->height());
bsalomon@google.comb505a122012-05-31 18:40:36 +0000223 drawState->sampler(0)->reset(sampleM);
224 SkAutoTUnref<GrCustomStage> morph(
225 new GrMorphologyEffect(direction, radius, morphType));
226 drawState->sampler(0)->setCustomStage(morph);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000227 drawState->setTexture(0, texture);
228 gpu->drawSimpleRect(rect, NULL, 1 << 0);
229}
230
bsalomon@google.comb505a122012-05-31 18:40:36 +0000231void convolve_gaussian(GrGpu* gpu,
232 GrTexture* texture,
233 const SkRect& rect,
234 float sigma,
235 int radius,
236 Gr1DKernelEffect::Direction direction) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000237 GrRenderTarget* target = gpu->drawState()->getRenderTarget();
238 GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000239 GrDrawState* drawState = gpu->drawState();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000240 drawState->setRenderTarget(target);
241 GrMatrix sampleM;
242 sampleM.setIDiv(texture->width(), texture->height());
bsalomon@google.comb505a122012-05-31 18:40:36 +0000243 drawState->sampler(0)->reset(sampleM);
244 SkAutoTUnref<GrConvolutionEffect> conv(new
245 GrConvolutionEffect(direction, radius));
246 conv->setGaussianKernel(sigma);
247 drawState->sampler(0)->setCustomStage(conv);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +0000248 drawState->setTexture(0, texture);
249 gpu->drawSimpleRect(rect, NULL, 1 << 0);
250}
251
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000252}
253
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000254GrContext::TextureCacheEntry GrContext::findAndLockTexture(
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000255 GrTexture::TextureKey key,
256 const GrTextureDesc& desc,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000257 const GrSamplerState* sampler) {
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000258 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, key, desc, false);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000259 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
260 GrResourceCache::kNested_LockType));
261}
262
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000263bool GrContext::isTextureInCache(GrTexture::TextureKey key,
264 const GrTextureDesc& desc,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000265 const GrSamplerState* sampler) const {
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000266 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, key, desc, false);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000267 return fTextureCache->hasKey(resourceKey);
268}
269
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000270GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000271 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000272 uint32_t v[4];
273 gen_stencil_key_values(sb, v);
274 GrResourceKey resourceKey(v);
275 return fTextureCache->createAndLock(resourceKey, sb);
276}
277
278GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
279 int sampleCnt) {
280 uint32_t v[4];
281 gen_stencil_key_values(width, height, sampleCnt, v);
282 GrResourceKey resourceKey(v);
283 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
284 GrResourceCache::kSingle_LockType);
285 if (NULL != entry) {
286 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
287 return sb;
288 } else {
289 return NULL;
290 }
291}
292
293void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000294 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000295 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000296}
297
298static void stretchImage(void* dst,
299 int dstW,
300 int dstH,
301 void* src,
302 int srcW,
303 int srcH,
304 int bpp) {
305 GrFixed dx = (srcW << 16) / dstW;
306 GrFixed dy = (srcH << 16) / dstH;
307
308 GrFixed y = dy >> 1;
309
310 int dstXLimit = dstW*bpp;
311 for (int j = 0; j < dstH; ++j) {
312 GrFixed x = dx >> 1;
313 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
314 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
315 for (int i = 0; i < dstXLimit; i += bpp) {
316 memcpy((uint8_t*) dstRow + i,
317 (uint8_t*) srcRow + (x>>16)*bpp,
318 bpp);
319 x += dx;
320 }
321 y += dy;
322 }
323}
324
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000325GrContext::TextureCacheEntry GrContext::createAndLockTexture(
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000326 GrTexture::TextureKey key,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000327 const GrSamplerState* sampler,
328 const GrTextureDesc& desc,
329 void* srcData,
330 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000331 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000332
333#if GR_DUMP_TEXTURE_UPLOAD
334 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
335#endif
336
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000337 TextureCacheEntry entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000338
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000339 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, key,
340 desc, false);
341
342 if (GrTexture::NeedsResizing(resourceKey)) {
343 // The desired texture is NPOT and tiled but that isn't supported by
344 // the current hardware. Resize the texture to be a POT
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000345 GrAssert(NULL != sampler);
346 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000347 desc,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000348 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000349
350 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000351 clampEntry = this->createAndLockTexture(key, NULL, desc,
352 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000353 GrAssert(NULL != clampEntry.texture());
354 if (NULL == clampEntry.texture()) {
355 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000356 }
357 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000358 GrTextureDesc rtDesc = desc;
359 rtDesc.fFlags = rtDesc.fFlags |
360 kRenderTarget_GrTextureFlagBit |
361 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000362 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
363 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000364
365 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
366
367 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000368 GrDrawTarget::AutoStateRestore asr(fGpu,
369 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000370 GrDrawState* drawState = fGpu->drawState();
371 drawState->setRenderTarget(texture->asRenderTarget());
372 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000373
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000374 GrSamplerState::Filter filter;
375 // if filtering is not desired then we want to ensure all
376 // texels in the resampled image are copies of texels from
377 // the original.
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000378 if (GrTexture::NeedsFiltering(resourceKey)) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000379 filter = GrSamplerState::kBilinear_Filter;
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000380 } else {
381 filter = GrSamplerState::kNearest_Filter;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000382 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000383 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
384 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000385
386 static const GrVertexLayout layout =
387 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
388 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
389
390 if (arg.succeeded()) {
391 GrPoint* verts = (GrPoint*) arg.vertices();
392 verts[0].setIRectFan(0, 0,
393 texture->width(),
394 texture->height(),
395 2*sizeof(GrPoint));
396 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
bsalomon@google.com47059542012-06-06 20:51:20 +0000397 fGpu->drawNonIndexed(kTriangleFan_GrPrimitiveType,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000399 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000400 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000401 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402 } else {
403 // TODO: Our CPU stretch doesn't filter. But we create separate
404 // stretched textures when the sampler state is either filtered or
405 // not. Either implement filtered stretch blit on CPU or just create
406 // one when FBO case fails.
407
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000408 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000409 // no longer need to clamp at min RT size.
410 rtDesc.fWidth = GrNextPow2(desc.fWidth);
411 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000412 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000413 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000414 rtDesc.fWidth *
415 rtDesc.fHeight);
416 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
417 srcData, desc.fWidth, desc.fHeight, bpp);
418
419 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
420
421 GrTexture* texture = fGpu->createTexture(rtDesc,
422 stretchedPixels.get(),
423 stretchedRowBytes);
424 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000425 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000426 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000428
429 } else {
430 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
431 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000432 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000433 }
434 }
435 return entry;
436}
437
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000438GrContext::TextureCacheEntry GrContext::lockScratchTexture(
439 const GrTextureDesc& inDesc,
440 ScratchTexMatch match) {
441
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000443 if (kExact_ScratchTexMatch != match) {
444 // bin by pow2 with a reasonable min
445 static const int MIN_SIZE = 256;
446 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
447 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
448 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000449
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000450 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000451 int origWidth = desc.fWidth;
452 int origHeight = desc.fHeight;
453 bool doubledW = false;
454 bool doubledH = false;
455
456 do {
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000457 GrResourceKey key = GrTexture::ComputeKey(fGpu, NULL, 0, desc, true);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000458 entry = fTextureCache->findAndLock(key,
459 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000460 // if we miss, relax the fit of the flags...
461 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000462 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000463 break;
464 }
465 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
466 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
467 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
468 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
469 } else if (!doubledW) {
470 desc.fFlags = inDesc.fFlags;
471 desc.fWidth *= 2;
472 doubledW = true;
473 } else if (!doubledH) {
474 desc.fFlags = inDesc.fFlags;
475 desc.fWidth = origWidth;
476 desc.fHeight *= 2;
477 doubledH = true;
478 } else {
479 break;
480 }
481
482 } while (true);
483
484 if (NULL == entry) {
485 desc.fFlags = inDesc.fFlags;
486 desc.fWidth = origWidth;
487 desc.fHeight = origHeight;
488 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
489 if (NULL != texture) {
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000490 GrResourceKey key = GrTexture::ComputeKey(fGpu, NULL, 0,
491 texture->desc(),
492 true);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000493 entry = fTextureCache->createAndLock(key, texture);
494 }
495 }
496
497 // If the caller gives us the same desc/sampler twice we don't want
498 // to return the same texture the second time (unless it was previously
499 // released). So we detach the entry from the cache and reattach at release.
500 if (NULL != entry) {
501 fTextureCache->detach(entry);
502 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000503 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000504}
505
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000506void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000507 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000508 // If this is a scratch texture we detached it from the cache
509 // while it was locked (to avoid two callers simultaneously getting
510 // the same texture).
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000511 if (GrTexture::IsScratchTexture(entry.cacheEntry()->key())) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000512 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000513 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000514 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000515 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000516}
517
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000518GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000519 void* srcData,
520 size_t rowBytes) {
521 return fGpu->createTexture(desc, srcData, rowBytes);
522}
523
524void GrContext::getTextureCacheLimits(int* maxTextures,
525 size_t* maxTextureBytes) const {
526 fTextureCache->getLimits(maxTextures, maxTextureBytes);
527}
528
529void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
530 fTextureCache->setLimits(maxTextures, maxTextureBytes);
531}
532
bsalomon@google.com91958362011-06-13 17:58:13 +0000533int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000534 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000535}
536
537int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000538 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000539}
540
541///////////////////////////////////////////////////////////////////////////////
542
bsalomon@google.come269f212011-11-07 13:29:52 +0000543GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
544 return fGpu->createPlatformTexture(desc);
545}
546
547GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
548 return fGpu->createPlatformRenderTarget(desc);
549}
550
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000553bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000554 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000555 const GrDrawTarget::Caps& caps = fGpu->getCaps();
556 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000557 return false;
558 }
559
bsalomon@google.com27847de2011-02-22 20:59:41 +0000560 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
561
562 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000563 bool tiled = NULL != sampler &&
564 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
565 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000566 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000567 return false;
568 }
569 }
570 return true;
571}
572
573////////////////////////////////////////////////////////////////////////////////
574
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000575const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
576
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577void GrContext::setClip(const GrClip& clip) {
578 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000579 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580}
581
582void GrContext::setClip(const GrIRect& rect) {
583 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000584 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585 fGpu->setClip(clip);
586}
587
588////////////////////////////////////////////////////////////////////////////////
589
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000590void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000591 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000592 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000593}
594
595void GrContext::drawPaint(const GrPaint& paint) {
596 // set rect to be big enough to fill the space, but not super-huge, so we
597 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000598 GrRect r;
599 r.setLTRB(0, 0,
600 GrIntToScalar(getRenderTarget()->width()),
601 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000602 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000603 SkTLazy<GrPaint> tmpPaint;
604 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000605 GrAutoMatrix am;
606
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000607 // We attempt to map r by the inverse matrix and draw that. mapRect will
608 // map the four corners and bound them with a new rect. This will not
609 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000610 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000611 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000612 GrPrintf("Could not invert matrix");
613 return;
614 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000615 inverse.mapRect(&r);
616 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000617 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000618 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000619 GrPrintf("Could not invert matrix");
620 return;
621 }
622 tmpPaint.set(paint);
623 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
624 p = tmpPaint.get();
625 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000626 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000627 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000628 // by definition this fills the entire clip, no need for AA
629 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000630 if (!tmpPaint.isValid()) {
631 tmpPaint.set(paint);
632 p = tmpPaint.get();
633 }
634 GrAssert(p == tmpPaint.get());
635 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000636 }
637 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000638}
639
bsalomon@google.com205d4602011-04-25 12:43:45 +0000640////////////////////////////////////////////////////////////////////////////////
641
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000642namespace {
643inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
644 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
645}
646}
647
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000648////////////////////////////////////////////////////////////////////////////////
649
bsalomon@google.com27847de2011-02-22 20:59:41 +0000650/* create a triangle strip that strokes the specified triangle. There are 8
651 unique vertices, but we repreat the last 2 to close up. Alternatively we
652 could use an indices array, and then only send 8 verts, but not sure that
653 would be faster.
654 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000655static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656 GrScalar width) {
657 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000658 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000659
660 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
661 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
662 verts[2].set(rect.fRight - rad, rect.fTop + rad);
663 verts[3].set(rect.fRight + rad, rect.fTop - rad);
664 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
665 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
666 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
667 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
668 verts[8] = verts[0];
669 verts[9] = verts[1];
670}
671
bsalomon@google.com205d4602011-04-25 12:43:45 +0000672static void setInsetFan(GrPoint* pts, size_t stride,
673 const GrRect& r, GrScalar dx, GrScalar dy) {
674 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
675}
676
677static const uint16_t gFillAARectIdx[] = {
678 0, 1, 5, 5, 4, 0,
679 1, 2, 6, 6, 5, 1,
680 2, 3, 7, 7, 6, 2,
681 3, 0, 4, 4, 7, 3,
682 4, 5, 6, 6, 7, 4,
683};
684
685int GrContext::aaFillRectIndexCount() const {
686 return GR_ARRAY_COUNT(gFillAARectIdx);
687}
688
689GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
690 if (NULL == fAAFillRectIndexBuffer) {
691 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
692 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000693 if (NULL != fAAFillRectIndexBuffer) {
694 #if GR_DEBUG
695 bool updated =
696 #endif
697 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
698 sizeof(gFillAARectIdx));
699 GR_DEBUGASSERT(updated);
700 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000701 }
702 return fAAFillRectIndexBuffer;
703}
704
705static const uint16_t gStrokeAARectIdx[] = {
706 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
707 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
708 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
709 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
710
711 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
712 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
713 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
714 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
715
716 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
717 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
718 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
719 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
720};
721
722int GrContext::aaStrokeRectIndexCount() const {
723 return GR_ARRAY_COUNT(gStrokeAARectIdx);
724}
725
726GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
727 if (NULL == fAAStrokeRectIndexBuffer) {
728 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
729 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000730 if (NULL != fAAStrokeRectIndexBuffer) {
731 #if GR_DEBUG
732 bool updated =
733 #endif
734 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
735 sizeof(gStrokeAARectIdx));
736 GR_DEBUGASSERT(updated);
737 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000738 }
739 return fAAStrokeRectIndexBuffer;
740}
741
bsalomon@google.coma3108262011-10-10 14:08:47 +0000742static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
743 bool useCoverage) {
744 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000745 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000746 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000747 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
748 }
749 }
750 if (useCoverage) {
751 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
752 } else {
753 layout |= GrDrawTarget::kColor_VertexLayoutBit;
754 }
755 return layout;
756}
757
bsalomon@google.com205d4602011-04-25 12:43:45 +0000758void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000759 const GrRect& devRect,
760 bool useVertexCoverage) {
761 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000762
763 size_t vsize = GrDrawTarget::VertexSize(layout);
764
765 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000766 if (!geo.succeeded()) {
767 GrPrintf("Failed to get space for vertices!\n");
768 return;
769 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000770 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
771 if (NULL == indexBuffer) {
772 GrPrintf("Failed to create index buffer!\n");
773 return;
774 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000775
776 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
777
778 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
779 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
780
781 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
782 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
783
784 verts += sizeof(GrPoint);
785 for (int i = 0; i < 4; ++i) {
786 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
787 }
788
bsalomon@google.coma3108262011-10-10 14:08:47 +0000789 GrColor innerColor;
790 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000791 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000792 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000793 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000794 }
795
bsalomon@google.com205d4602011-04-25 12:43:45 +0000796 verts += 4 * vsize;
797 for (int i = 0; i < 4; ++i) {
798 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
799 }
800
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000801 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000802
bsalomon@google.com47059542012-06-06 20:51:20 +0000803 target->drawIndexed(kTriangles_GrPrimitiveType, 0,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000804 0, 8, this->aaFillRectIndexCount());
805}
806
bsalomon@google.coma3108262011-10-10 14:08:47 +0000807void GrContext::strokeAARect(GrDrawTarget* target,
808 const GrRect& devRect,
809 const GrVec& devStrokeSize,
810 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000811 const GrScalar& dx = devStrokeSize.fX;
812 const GrScalar& dy = devStrokeSize.fY;
813 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
814 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
815
bsalomon@google.com205d4602011-04-25 12:43:45 +0000816 GrScalar spare;
817 {
818 GrScalar w = devRect.width() - dx;
819 GrScalar h = devRect.height() - dy;
820 spare = GrMin(w, h);
821 }
822
823 if (spare <= 0) {
824 GrRect r(devRect);
825 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000826 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000827 return;
828 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000829 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000830 size_t vsize = GrDrawTarget::VertexSize(layout);
831
832 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000833 if (!geo.succeeded()) {
834 GrPrintf("Failed to get space for vertices!\n");
835 return;
836 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000837 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
838 if (NULL == indexBuffer) {
839 GrPrintf("Failed to create index buffer!\n");
840 return;
841 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000842
843 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
844
845 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
846 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
847 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
848 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
849
850 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
851 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
852 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
853 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
854
855 verts += sizeof(GrPoint);
856 for (int i = 0; i < 4; ++i) {
857 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
858 }
859
bsalomon@google.coma3108262011-10-10 14:08:47 +0000860 GrColor innerColor;
861 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000862 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000863 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000864 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000865 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000866 verts += 4 * vsize;
867 for (int i = 0; i < 8; ++i) {
868 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
869 }
870
871 verts += 8 * vsize;
872 for (int i = 0; i < 8; ++i) {
873 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
874 }
875
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000876 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com47059542012-06-06 20:51:20 +0000877 target->drawIndexed(kTriangles_GrPrimitiveType,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000878 0, 0, 16, aaStrokeRectIndexCount());
879}
880
reed@google.com20efde72011-05-09 17:00:02 +0000881/**
882 * Returns true if the rects edges are integer-aligned.
883 */
884static bool isIRect(const GrRect& r) {
885 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
886 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
887}
888
bsalomon@google.com205d4602011-04-25 12:43:45 +0000889static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000890 const GrRect& rect,
891 GrScalar width,
892 const GrMatrix* matrix,
893 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000894 GrRect* devRect,
895 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000896 // we use a simple coverage ramp to do aa on axis-aligned rects
897 // we check if the rect will be axis-aligned, and the rect won't land on
898 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000899
bsalomon@google.coma3108262011-10-10 14:08:47 +0000900 // we are keeping around the "tweak the alpha" trick because
901 // it is our only hope for the fixed-pipe implementation.
902 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000903 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000904 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000905 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000906 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000907#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000908 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000909#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000910 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000911 } else {
912 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000913 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000914 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000915 const GrDrawState& drawState = target->getDrawState();
916 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000917 return false;
918 }
919
bsalomon@google.com471d4712011-08-23 15:45:25 +0000920 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000921 return false;
922 }
923
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000924 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000925 return false;
926 }
927
928 if (NULL != matrix &&
929 !matrix->preservesAxisAlignment()) {
930 return false;
931 }
932
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000933 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000934 if (NULL != matrix) {
935 combinedMatrix->preConcat(*matrix);
936 GrAssert(combinedMatrix->preservesAxisAlignment());
937 }
938
939 combinedMatrix->mapRect(devRect, rect);
940 devRect->sort();
941
942 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000943 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000944 } else {
945 return true;
946 }
947}
948
bsalomon@google.com27847de2011-02-22 20:59:41 +0000949void GrContext::drawRect(const GrPaint& paint,
950 const GrRect& rect,
951 GrScalar width,
952 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000953 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000954
955 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000956 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000957
bsalomon@google.com205d4602011-04-25 12:43:45 +0000958 GrRect devRect = rect;
959 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000960 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +0000961 bool needAA = paint.fAntiAlias &&
962 !this->getRenderTarget()->isMultisampled();
963 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
964 &combinedMatrix, &devRect,
965 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000966
967 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000968 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000969 if (width >= 0) {
970 GrVec strokeSize;;
971 if (width > 0) {
972 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000973 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000974 strokeSize.setAbs(strokeSize);
975 } else {
976 strokeSize.set(GR_Scalar1, GR_Scalar1);
977 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000978 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000979 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000980 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000981 }
982 return;
983 }
984
bsalomon@google.com27847de2011-02-22 20:59:41 +0000985 if (width >= 0) {
986 // TODO: consider making static vertex buffers for these cases.
987 // Hairline could be done by just adding closing vertex to
988 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000989 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
990
bsalomon@google.com27847de2011-02-22 20:59:41 +0000991 static const int worstCaseVertCount = 10;
992 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
993
994 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000995 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000996 return;
997 }
998
999 GrPrimitiveType primType;
1000 int vertCount;
1001 GrPoint* vertex = geo.positions();
1002
1003 if (width > 0) {
1004 vertCount = 10;
bsalomon@google.com47059542012-06-06 20:51:20 +00001005 primType = kTriangleStrip_GrPrimitiveType;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001006 setStrokeRectStrip(vertex, rect, width);
1007 } else {
1008 // hairline
1009 vertCount = 5;
bsalomon@google.com47059542012-06-06 20:51:20 +00001010 primType = kLineStrip_GrPrimitiveType;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001011 vertex[0].set(rect.fLeft, rect.fTop);
1012 vertex[1].set(rect.fRight, rect.fTop);
1013 vertex[2].set(rect.fRight, rect.fBottom);
1014 vertex[3].set(rect.fLeft, rect.fBottom);
1015 vertex[4].set(rect.fLeft, rect.fTop);
1016 }
1017
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001018 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001019 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001020 GrDrawState* drawState = target->drawState();
1021 avmr.set(drawState);
1022 drawState->preConcatViewMatrix(*matrix);
1023 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001024 }
1025
1026 target->drawNonIndexed(primType, 0, vertCount);
1027 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001028#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001029 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001030 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1031 if (NULL == sqVB) {
1032 GrPrintf("Failed to create static rect vb.\n");
1033 return;
1034 }
1035 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001036 GrDrawState* drawState = target->drawState();
1037 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001038 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001039 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001040 0, rect.height(), rect.fTop,
1041 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001042
1043 if (NULL != matrix) {
1044 m.postConcat(*matrix);
1045 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001046 drawState->preConcatViewMatrix(m);
1047 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001048
bsalomon@google.com47059542012-06-06 20:51:20 +00001049 target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001050#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001051 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001052#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001053 }
1054}
1055
1056void GrContext::drawRectToRect(const GrPaint& paint,
1057 const GrRect& dstRect,
1058 const GrRect& srcRect,
1059 const GrMatrix* dstMatrix,
1060 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001061 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001062
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001063 // srcRect refers to paint's first texture
1064 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001065 drawRect(paint, dstRect, -1, dstMatrix);
1066 return;
1067 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001068
bsalomon@google.com27847de2011-02-22 20:59:41 +00001069 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1070
1071#if GR_STATIC_RECT_VB
1072 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001073 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001074 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001075 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001076
1077 GrMatrix m;
1078
1079 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1080 0, dstRect.height(), dstRect.fTop,
1081 0, 0, GrMatrix::I()[8]);
1082 if (NULL != dstMatrix) {
1083 m.postConcat(*dstMatrix);
1084 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001085 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001086
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001087 // srcRect refers to first stage
1088 int otherStageMask = paint.getActiveStageMask() &
1089 (~(1 << GrPaint::kFirstTextureStage));
1090 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001091 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001092 }
1093
bsalomon@google.com27847de2011-02-22 20:59:41 +00001094 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1095 0, srcRect.height(), srcRect.fTop,
1096 0, 0, GrMatrix::I()[8]);
1097 if (NULL != srcMatrix) {
1098 m.postConcat(*srcMatrix);
1099 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001100 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001101
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001102 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1103 if (NULL == sqVB) {
1104 GrPrintf("Failed to create static rect vb.\n");
1105 return;
1106 }
1107 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com47059542012-06-06 20:51:20 +00001108 target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001109#else
1110
1111 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001112#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001113 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001114#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001115 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1116#endif
1117
tomhudson@google.com93813632011-10-27 20:21:16 +00001118 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1119 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001120 srcRects[0] = &srcRect;
1121 srcMatrices[0] = srcMatrix;
1122
1123 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1124#endif
1125}
1126
1127void GrContext::drawVertices(const GrPaint& paint,
1128 GrPrimitiveType primitiveType,
1129 int vertexCount,
1130 const GrPoint positions[],
1131 const GrPoint texCoords[],
1132 const GrColor colors[],
1133 const uint16_t indices[],
1134 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001135 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001136
1137 GrDrawTarget::AutoReleaseGeometry geo;
1138
1139 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1140
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001141 bool hasTexCoords[GrPaint::kTotalStages] = {
1142 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1143 0 // remaining stages use positions
1144 };
1145
1146 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001147
1148 if (NULL != colors) {
1149 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001150 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001151 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001152
1153 if (sizeof(GrPoint) != vertexSize) {
1154 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001155 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001156 return;
1157 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001158 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001160 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1161 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001162 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001163 NULL,
1164 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001165 void* curVertex = geo.vertices();
1166
1167 for (int i = 0; i < vertexCount; ++i) {
1168 *((GrPoint*)curVertex) = positions[i];
1169
1170 if (texOffsets[0] > 0) {
1171 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1172 }
1173 if (colorOffset > 0) {
1174 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1175 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001176 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001177 }
1178 } else {
1179 target->setVertexSourceToArray(layout, positions, vertexCount);
1180 }
1181
bsalomon@google.com91958362011-06-13 17:58:13 +00001182 // we don't currently apply offscreen AA to this path. Need improved
1183 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001184
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001185 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001186 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001187 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001188 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001189 target->drawNonIndexed(primitiveType, 0, vertexCount);
1190 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001191}
1192
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001193///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001194namespace {
1195
bsalomon@google.com93c96602012-04-27 13:05:21 +00001196struct CircleVertex {
1197 GrPoint fPos;
1198 GrPoint fCenter;
1199 GrScalar fOuterRadius;
1200 GrScalar fInnerRadius;
1201};
1202
1203/* Returns true if will map a circle to another circle. This can be true
1204 * if the matrix only includes square-scale, rotation, translation.
1205 */
1206inline bool isSimilarityTransformation(const SkMatrix& matrix,
1207 SkScalar tol = SK_ScalarNearlyZero) {
1208 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1209 return true;
1210 }
1211 if (matrix.hasPerspective()) {
1212 return false;
1213 }
1214
1215 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1216 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1217 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1218 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1219
1220 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1221 return false;
1222 }
1223
1224 // it has scales or skews, but it could also be rotation, check it out.
1225 SkVector vec[2];
1226 vec[0].set(mx, sx);
1227 vec[1].set(sy, my);
1228
1229 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1230 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1231 SkScalarSquare(tol));
1232}
1233
1234}
1235
1236// TODO: strokeWidth can't be larger than zero right now.
1237// It will be fixed when drawPath() can handle strokes.
1238void GrContext::drawOval(const GrPaint& paint,
1239 const GrRect& rect,
1240 SkScalar strokeWidth) {
1241 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1242 kUnbuffered_DrawCategory;
1243 GrDrawTarget* target = this->prepareToDraw(paint, category);
1244 GrDrawState* drawState = target->drawState();
1245 GrMatrix vm = drawState->getViewMatrix();
1246
1247 if (!isSimilarityTransformation(vm) ||
1248 !paint.fAntiAlias ||
1249 rect.height() != rect.width()) {
1250 SkPath path;
1251 path.addOval(rect);
1252 GrPathFill fill = (strokeWidth == 0) ?
bsalomon@google.com47059542012-06-06 20:51:20 +00001253 kHairLine_GrPathFill : kWinding_GrPathFill;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001254 this->internalDrawPath(paint, path, fill, NULL);
1255 return;
1256 }
1257
1258 const GrRenderTarget* rt = drawState->getRenderTarget();
1259 if (NULL == rt) {
1260 return;
1261 }
1262
1263 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1264
1265 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1266 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1267 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1268
1269 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1270 GrScalar radius = SkScalarHalf(rect.width());
1271
1272 vm.mapPoints(&center, 1);
1273 radius = vm.mapRadius(radius);
1274
1275 GrScalar outerRadius = radius;
1276 GrScalar innerRadius = 0;
1277 SkScalar halfWidth = 0;
1278 if (strokeWidth == 0) {
1279 halfWidth = SkScalarHalf(SK_Scalar1);
1280
1281 outerRadius += halfWidth;
1282 innerRadius = SkMaxScalar(0, radius - halfWidth);
1283 }
1284
1285 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1286 if (!geo.succeeded()) {
1287 GrPrintf("Failed to get space for vertices!\n");
1288 return;
1289 }
1290
1291 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1292
1293 SkScalar L = center.fX - outerRadius;
1294 SkScalar R = center.fX + outerRadius;
1295 SkScalar T = center.fY - outerRadius;
1296 SkScalar B = center.fY + outerRadius;
1297
1298 verts[0].fPos = SkPoint::Make(L, T);
1299 verts[1].fPos = SkPoint::Make(R, T);
1300 verts[2].fPos = SkPoint::Make(L, B);
1301 verts[3].fPos = SkPoint::Make(R, B);
1302
1303 for (int i = 0; i < 4; ++i) {
1304 // this goes to fragment shader, it should be in y-points-up space.
1305 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1306
1307 verts[i].fOuterRadius = outerRadius;
1308 verts[i].fInnerRadius = innerRadius;
1309 }
1310
1311 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
bsalomon@google.com47059542012-06-06 20:51:20 +00001312 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001313}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001315void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001316 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001318 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001319 if (GrIsFillInverted(fill)) {
1320 this->drawPaint(paint);
1321 }
1322 return;
1323 }
1324
bsalomon@google.com93c96602012-04-27 13:05:21 +00001325 SkRect ovalRect;
1326 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1327 if (translate) {
1328 ovalRect.offset(*translate);
1329 }
bsalomon@google.com47059542012-06-06 20:51:20 +00001330 SkScalar width = (fill == kHairLine_GrPathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001331 this->drawOval(paint, ovalRect, width);
1332 return;
1333 }
1334
1335 internalDrawPath(paint, path, fill, translate);
1336}
1337
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001338void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001339 GrPathFill fill, const GrPoint* translate) {
1340
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001341 // Note that below we may sw-rasterize the path into a scratch texture.
1342 // Scratch textures can be recycled after they are returned to the texture
1343 // cache. This presents a potential hazard for buffered drawing. However,
1344 // the writePixels that uploads to the scratch will perform a flush so we're
1345 // OK.
1346 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1347 kUnbuffered_DrawCategory;
1348 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001349 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001350
bsalomon@google.com289533a2011-10-27 12:34:25 +00001351 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1352
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001353 // An Assumption here is that path renderer would use some form of tweaking
1354 // the src color (either the input alpha or in the frag shader) to implement
1355 // aa. If we have some future driver-mojo path AA that can do the right
1356 // thing WRT to the blend then we'll need some query on the PR.
1357 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001358#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001359 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001360#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001361 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001362 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001363
robertphillips@google.com72176b22012-05-23 13:19:12 +00001364 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA, true);
bsalomon@google.com30085192011-08-19 15:42:31 +00001365 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001366#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001367 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001368#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001369 return;
1370 }
1371
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001372 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001373}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001374
bsalomon@google.com27847de2011-02-22 20:59:41 +00001375////////////////////////////////////////////////////////////////////////////////
1376
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001377void GrContext::flush(int flagsBitfield) {
1378 if (kDiscard_FlushBit & flagsBitfield) {
1379 fDrawBuffer->reset();
1380 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001381 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001382 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001383 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384 fGpu->forceRenderTargetFlush();
1385 }
1386}
1387
bsalomon@google.com27847de2011-02-22 20:59:41 +00001388void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001389 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001390 // With addition of the AA clip path, flushing the draw buffer can
1391 // result in the generation of an AA clip mask. During this
1392 // process the SW path renderer may be invoked which recusively
1393 // calls this method (via internalWriteTexturePixels) creating
1394 // infinite recursion
1395 GrInOrderDrawBuffer* temp = fDrawBuffer;
1396 fDrawBuffer = NULL;
1397
1398 temp->flushTo(fGpu);
1399
1400 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001401 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402}
1403
bsalomon@google.com6f379512011-11-16 20:36:03 +00001404void GrContext::internalWriteTexturePixels(GrTexture* texture,
1405 int left, int top,
1406 int width, int height,
1407 GrPixelConfig config,
1408 const void* buffer,
1409 size_t rowBytes,
1410 uint32_t flags) {
1411 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001412 ASSERT_OWNED_RESOURCE(texture);
1413
bsalomon@google.com6f379512011-11-16 20:36:03 +00001414 if (!(kDontFlush_PixelOpsFlag & flags)) {
1415 this->flush();
1416 }
1417 // TODO: use scratch texture to perform conversion
1418 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1419 GrPixelConfigIsUnpremultiplied(config)) {
1420 return;
1421 }
1422
1423 fGpu->writeTexturePixels(texture, left, top, width, height,
1424 config, buffer, rowBytes);
1425}
1426
1427bool GrContext::internalReadTexturePixels(GrTexture* texture,
1428 int left, int top,
1429 int width, int height,
1430 GrPixelConfig config,
1431 void* buffer,
1432 size_t rowBytes,
1433 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001434 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001435 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001436
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001437 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001438 GrRenderTarget* target = texture->asRenderTarget();
1439 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001440 return this->internalReadRenderTargetPixels(target,
1441 left, top, width, height,
1442 config, buffer, rowBytes,
1443 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001444 } else {
1445 return false;
1446 }
1447}
1448
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001449#include "SkConfig8888.h"
1450
1451namespace {
1452/**
1453 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1454 * formats are representable as Config8888 and so the function returns false
1455 * if the GrPixelConfig has no equivalent Config8888.
1456 */
1457bool grconfig_to_config8888(GrPixelConfig config,
1458 SkCanvas::Config8888* config8888) {
1459 switch (config) {
1460 case kRGBA_8888_PM_GrPixelConfig:
1461 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1462 return true;
1463 case kRGBA_8888_UPM_GrPixelConfig:
1464 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1465 return true;
1466 case kBGRA_8888_PM_GrPixelConfig:
1467 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1468 return true;
1469 case kBGRA_8888_UPM_GrPixelConfig:
1470 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1471 return true;
1472 default:
1473 return false;
1474 }
1475}
1476}
1477
bsalomon@google.com6f379512011-11-16 20:36:03 +00001478bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1479 int left, int top,
1480 int width, int height,
1481 GrPixelConfig config,
1482 void* buffer,
1483 size_t rowBytes,
1484 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001485 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001486 ASSERT_OWNED_RESOURCE(target);
1487
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001488 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001489 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001490 if (NULL == target) {
1491 return false;
1492 }
1493 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001494
bsalomon@google.com6f379512011-11-16 20:36:03 +00001495 if (!(kDontFlush_PixelOpsFlag & flags)) {
1496 this->flush();
1497 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001498
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001499 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1500 GrPixelConfigIsUnpremultiplied(config) &&
1501 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1502 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1503 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1504 !grconfig_to_config8888(config, &dstConfig8888)) {
1505 return false;
1506 }
1507 // do read back using target's own config
1508 this->internalReadRenderTargetPixels(target,
1509 left, top,
1510 width, height,
1511 target->config(),
1512 buffer, rowBytes,
1513 kDontFlush_PixelOpsFlag);
1514 // sw convert the pixels to unpremul config
1515 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1516 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1517 pixels, rowBytes, srcConfig8888,
1518 width, height);
1519 return true;
1520 }
1521
bsalomon@google.comc4364992011-11-07 15:54:49 +00001522 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001523 bool swapRAndB = NULL != src &&
1524 fGpu->preferredReadPixelsConfig(config) ==
1525 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001526
1527 bool flipY = NULL != src &&
1528 fGpu->readPixelsWillPayForYFlip(target, left, top,
1529 width, height, config,
1530 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001531 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1532 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001533
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001534 if (NULL == src && alphaConversion) {
1535 // we should fallback to cpu conversion here. This could happen when
1536 // we were given an external render target by the client that is not
1537 // also a texture (e.g. FBO 0 in GL)
1538 return false;
1539 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001540 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001541 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001542 if (flipY || swapRAndB || alphaConversion) {
1543 GrAssert(NULL != src);
1544 if (swapRAndB) {
1545 config = GrPixelConfigSwapRAndB(config);
1546 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001547 }
1548 // Make the scratch a render target because we don't have a robust
1549 // readTexturePixels as of yet (it calls this function).
1550 const GrTextureDesc desc = {
1551 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001552 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001553 config,
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001554 0 // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001555 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001556
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001557 // When a full readback is faster than a partial we could always make
1558 // the scratch exactly match the passed rect. However, if we see many
1559 // different size rectangles we will trash our texture cache and pay the
1560 // cost of creating and destroying many textures. So, we only request
1561 // an exact match when the caller is reading an entire RT.
1562 ScratchTexMatch match = kApprox_ScratchTexMatch;
1563 if (0 == left &&
1564 0 == top &&
1565 target->width() == width &&
1566 target->height() == height &&
1567 fGpu->fullReadPixelsIsFasterThanPartial()) {
1568 match = kExact_ScratchTexMatch;
1569 }
1570 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001571 GrTexture* texture = ast.texture();
1572 if (!texture) {
1573 return false;
1574 }
1575 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001576 GrAssert(NULL != target);
1577
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001578 GrDrawTarget::AutoStateRestore asr(fGpu,
1579 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001580 GrDrawState* drawState = fGpu->drawState();
1581 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001582
bsalomon@google.comc4364992011-11-07 15:54:49 +00001583 GrMatrix matrix;
1584 if (flipY) {
1585 matrix.setTranslate(SK_Scalar1 * left,
1586 SK_Scalar1 * (top + height));
1587 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1588 } else {
1589 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1590 }
1591 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001592 drawState->sampler(0)->reset(matrix);
1593 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001594 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001595 GrRect rect;
1596 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1597 fGpu->drawSimpleRect(rect, NULL, 0x1);
1598 left = 0;
1599 top = 0;
1600 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001601 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001602 left, top, width, height,
1603 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001604}
1605
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001606void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1607 GrAssert(target);
1608 ASSERT_OWNED_RESOURCE(target);
1609 // In the future we may track whether there are any pending draws to this
1610 // target. We don't today so we always perform a flush. We don't promise
1611 // this to our clients, though.
1612 this->flush();
1613 fGpu->resolveRenderTarget(target);
1614}
1615
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001616void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1617 if (NULL == src || NULL == dst) {
1618 return;
1619 }
1620 ASSERT_OWNED_RESOURCE(src);
1621
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001622 // Writes pending to the source texture are not tracked, so a flush
1623 // is required to ensure that the copy captures the most recent contents
1624 // of the source texture. See similar behaviour in
1625 // GrContext::resolveRenderTarget.
1626 this->flush();
1627
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001628 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001629 GrDrawState* drawState = fGpu->drawState();
1630 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001631 GrMatrix sampleM;
1632 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001633 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001634 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001635 SkRect rect = SkRect::MakeXYWH(0, 0,
1636 SK_Scalar1 * src->width(),
1637 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001638 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1639}
1640
bsalomon@google.com6f379512011-11-16 20:36:03 +00001641void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1642 int left, int top,
1643 int width, int height,
1644 GrPixelConfig config,
1645 const void* buffer,
1646 size_t rowBytes,
1647 uint32_t flags) {
1648 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001649 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001650
1651 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001652 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001653 if (NULL == target) {
1654 return;
1655 }
1656 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001657
1658 // TODO: when underlying api has a direct way to do this we should use it
1659 // (e.g. glDrawPixels on desktop GL).
1660
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001661 // If the RT is also a texture and we don't have to do PM/UPM conversion
1662 // then take the texture path, which we expect to be at least as fast or
1663 // faster since it doesn't use an intermediate texture as we do below.
1664
1665#if !GR_MAC_BUILD
1666 // At least some drivers on the Mac get confused when glTexImage2D is called
1667 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1668 // determine what OS versions and/or HW is affected.
1669 if (NULL != target->asTexture() &&
1670 GrPixelConfigIsUnpremultiplied(target->config()) ==
1671 GrPixelConfigIsUnpremultiplied(config)) {
1672
1673 this->internalWriteTexturePixels(target->asTexture(),
1674 left, top, width, height,
1675 config, buffer, rowBytes, flags);
1676 return;
1677 }
1678#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001679 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1680 GrPixelConfigIsUnpremultiplied(config) &&
1681 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1682 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1683 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1684 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1685 return;
1686 }
1687 // allocate a tmp buffer and sw convert the pixels to premul
1688 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1689 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1690 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1691 src, rowBytes, srcConfig8888,
1692 width, height);
1693 // upload the already premul pixels
1694 this->internalWriteRenderTargetPixels(target,
1695 left, top,
1696 width, height,
1697 target->config(),
1698 tmpPixels, 4 * width, flags);
1699 return;
1700 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001701
1702 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1703 GrPixelConfigSwapRAndB(config);
1704 if (swapRAndB) {
1705 config = GrPixelConfigSwapRAndB(config);
1706 }
1707
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001708 const GrTextureDesc desc = {
bsalomon@google.comb9014f42012-03-30 14:22:41 +00001709 kNone_GrTextureFlags, width, height, config, 0
bsalomon@google.com27847de2011-02-22 20:59:41 +00001710 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001711 GrAutoScratchTexture ast(this, desc);
1712 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001713 if (NULL == texture) {
1714 return;
1715 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001716 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1717 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001718
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001719 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001720 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001721
1722 GrMatrix matrix;
1723 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001724 drawState->setViewMatrix(matrix);
1725 drawState->setRenderTarget(target);
1726 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001727
bsalomon@google.com5c638652011-07-18 19:31:59 +00001728 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001729 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1730 GrSamplerState::kNearest_Filter,
1731 matrix);
1732 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001733
1734 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1735 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001736 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001737 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1738 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001739 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001740 return;
1741 }
1742 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
bsalomon@google.com47059542012-06-06 20:51:20 +00001743 fGpu->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, VCOUNT);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001744}
1745////////////////////////////////////////////////////////////////////////////////
1746
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001747void GrContext::setPaint(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001748
1749 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1750 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001751 fDrawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001752 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001753 if (paint.getTexture(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001754 *fDrawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001755 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001756 }
1757
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001758 fDrawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001759
1760 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1761 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001762 fDrawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001763 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001764 if (paint.getMask(i)) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001765 *fDrawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001766 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001767 }
bsalomon@google.com26936d02012-03-19 13:06:19 +00001768
1769 // disable all stages not accessible via the paint
1770 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001771 fDrawState->setTexture(s, NULL);
bsalomon@google.com26936d02012-03-19 13:06:19 +00001772 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001773
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001774 fDrawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001775
1776 if (paint.fDither) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001777 fDrawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001778 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001779 fDrawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001780 }
1781 if (paint.fAntiAlias) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001782 fDrawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001783 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001784 fDrawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001785 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001786 if (paint.fColorMatrixEnabled) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001787 fDrawState->enableState(GrDrawState::kColorMatrix_StateBit);
1788 fDrawState->setColorMatrix(paint.fColorMatrix);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001789 } else {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001790 fDrawState->disableState(GrDrawState::kColorMatrix_StateBit);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001791 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001792 fDrawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1793 fDrawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1794 fDrawState->setCoverage(paint.fCoverage);
reed@google.com4b2d3f32012-05-15 18:05:50 +00001795#if GR_DEBUG_PARTIAL_COVERAGE_CHECK
bsalomon@google.come79c8152012-03-29 19:07:12 +00001796 if ((paint.getActiveMaskStageMask() || 0xff != paint.fCoverage) &&
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001797 !fGpu->canApplyCoverage()) {
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001798 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1799 }
bsalomon@google.com95cd7bd2012-03-28 15:35:05 +00001800#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001801}
1802
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001803GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001804 DrawCategory category) {
1805 if (category != fLastDrawCategory) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001806 this->flushDrawBuffer();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001807 fLastDrawCategory = category;
1808 }
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001809 this->setPaint(paint);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001810 GrDrawTarget* target = fGpu;
1811 switch (category) {
bsalomon@google.com193395c2012-03-30 17:35:12 +00001812 case kUnbuffered_DrawCategory:
1813 target = fGpu;
1814 break;
1815 case kBuffered_DrawCategory:
1816 target = fDrawBuffer;
1817 fDrawBuffer->setClip(fGpu->getClip());
1818 break;
1819 default:
1820 GrCrash("Unexpected DrawCategory.");
1821 break;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001822 }
1823 return target;
1824}
1825
robertphillips@google.com72176b22012-05-23 13:19:12 +00001826/*
1827 * This method finds a path renderer that can draw the specified path on
1828 * the provided target.
1829 * Due to its expense, the software path renderer has split out so it can
1830 * can be individually allowed/disallowed via the "allowSW" boolean.
1831 */
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001832GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001833 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001834 const GrDrawTarget* target,
robertphillips@google.com72176b22012-05-23 13:19:12 +00001835 bool antiAlias,
1836 bool allowSW) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001837 if (NULL == fPathRendererChain) {
1838 fPathRendererChain =
1839 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1840 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001841
1842 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path, fill,
1843 target,
1844 antiAlias);
1845
1846 if (NULL == pr && allowSW) {
1847 if (NULL == fSoftwarePathRenderer) {
1848 fSoftwarePathRenderer = new GrSoftwarePathRenderer(this);
1849 }
1850
1851 pr = fSoftwarePathRenderer;
1852 }
1853
1854 return pr;
bsalomon@google.com30085192011-08-19 15:42:31 +00001855}
1856
bsalomon@google.com27847de2011-02-22 20:59:41 +00001857////////////////////////////////////////////////////////////////////////////////
1858
bsalomon@google.com27847de2011-02-22 20:59:41 +00001859void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001860 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001861 if (fDrawState->getRenderTarget() != target) {
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001862 this->flush(false);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001863 fDrawState->setRenderTarget(target);
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001864 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001865}
1866
1867GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001868 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001869}
1870
1871const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001872 return fDrawState->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001873}
1874
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001875bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1876 return fGpu->isConfigRenderable(config);
1877}
1878
bsalomon@google.com27847de2011-02-22 20:59:41 +00001879const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001880 return fDrawState->getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001881}
1882
1883void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001884 fDrawState->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885}
1886
1887void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001888 fDrawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889}
1890
1891static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1892 intptr_t mask = 1 << shift;
1893 if (pred) {
1894 bits |= mask;
1895 } else {
1896 bits &= ~mask;
1897 }
1898 return bits;
1899}
1900
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001901GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001902 fGpu = gpu;
1903 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001904 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001905
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001906 fDrawState = new GrDrawState();
1907 fGpu->setDrawState(fDrawState);
1908
bsalomon@google.com30085192011-08-19 15:42:31 +00001909 fPathRendererChain = NULL;
robertphillips@google.com72176b22012-05-23 13:19:12 +00001910 fSoftwarePathRenderer = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001911
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001912 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1913 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001914 fFontCache = new GrFontCache(fGpu);
1915
1916 fLastDrawCategory = kUnbuffered_DrawCategory;
1917
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001918 fDrawBuffer = NULL;
1919 fDrawBufferVBAllocPool = NULL;
1920 fDrawBufferIBAllocPool = NULL;
1921
bsalomon@google.com205d4602011-04-25 12:43:45 +00001922 fAAFillRectIndexBuffer = NULL;
1923 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001924
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001925 this->setupDrawBuffer();
1926}
1927
1928void GrContext::setupDrawBuffer() {
1929
1930 GrAssert(NULL == fDrawBuffer);
1931 GrAssert(NULL == fDrawBufferVBAllocPool);
1932 GrAssert(NULL == fDrawBufferIBAllocPool);
1933
bsalomon@google.com92edd312012-04-04 21:40:21 +00001934#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT || DEFER_PATHS
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001935 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001936 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001937 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1938 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001939 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001940 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001941 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001942 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1943
bsalomon@google.com471d4712011-08-23 15:45:25 +00001944 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1945 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946 fDrawBufferIBAllocPool);
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00001947#endif
1948
1949#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001950 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com3c4d0322012-04-03 18:04:51 +00001951#endif
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001952 fDrawBuffer->setAutoFlushTarget(fGpu);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001953 fDrawBuffer->setDrawState(fDrawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001954}
1955
bsalomon@google.com27847de2011-02-22 20:59:41 +00001956GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001957#if DEFER_TEXT_RENDERING
bsalomon@google.com193395c2012-03-30 17:35:12 +00001958 return prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001959#else
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001960 return prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001961#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001962}
1963
1964const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1965 return fGpu->getQuadIndexBuffer();
1966}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001967
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00001968GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
1969 GrAutoScratchTexture* temp1,
1970 GrAutoScratchTexture* temp2,
1971 const SkRect& rect,
1972 float sigmaX, float sigmaY) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00001973 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00001974 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
1975 GrClip oldClip = this->getClip();
1976 GrTexture* origTexture = srcTexture;
1977 GrAutoMatrix avm(this, GrMatrix::I());
1978 SkIRect clearRect;
bsalomon@google.comb505a122012-05-31 18:40:36 +00001979 int scaleFactorX, radiusX;
1980 int scaleFactorY, radiusY;
1981 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX);
1982 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY);
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001983
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00001984 SkRect srcRect(rect);
1985 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
1986 srcRect.roundOut();
robertphillips@google.com8637a362012-04-10 18:32:35 +00001987 scale_rect(&srcRect, static_cast<float>(scaleFactorX),
1988 static_cast<float>(scaleFactorY));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00001989 this->setClip(srcRect);
1990
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001991 GrAssert(kBGRA_8888_PM_GrPixelConfig == srcTexture->config() ||
1992 kRGBA_8888_PM_GrPixelConfig == srcTexture->config() ||
1993 kAlpha_8_GrPixelConfig == srcTexture->config());
1994
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00001995 const GrTextureDesc desc = {
1996 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
bungeman@google.comf8aa18c2012-03-19 21:04:52 +00001997 SkScalarFloorToInt(srcRect.width()),
1998 SkScalarFloorToInt(srcRect.height()),
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001999 srcTexture->config(),
bsalomon@google.comb9014f42012-03-30 14:22:41 +00002000 0 // samples
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002001 };
2002
2003 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002004 if (temp2) {
2005 temp2->set(this, desc);
2006 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002007
2008 GrTexture* dstTexture = temp1->texture();
2009 GrPaint paint;
2010 paint.reset();
2011 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2012
2013 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2014 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2015 srcTexture->height());
2016 this->setRenderTarget(dstTexture->asRenderTarget());
2017 SkRect dstRect(srcRect);
2018 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2019 i < scaleFactorY ? 0.5f : 1.0f);
2020 paint.setTexture(0, srcTexture);
2021 this->drawRectToRect(paint, dstRect, srcRect);
2022 srcRect = dstRect;
2023 SkTSwap(srcTexture, dstTexture);
2024 // If temp2 is non-NULL, don't render back to origTexture
2025 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2026 }
2027
robertphillips@google.com7a396332012-05-10 15:11:27 +00002028 SkIRect srcIRect;
2029 srcRect.roundOut(&srcIRect);
2030
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002031 if (sigmaX > 0.0f) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002032 if (scaleFactorX > 1) {
bsalomon@google.comb505a122012-05-31 18:40:36 +00002033 // Clear out a radius to the right of the srcRect to prevent the
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002034 // X convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002035 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002036 radiusX, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002037 this->clear(&clearRect, 0x0);
2038 }
2039
2040 this->setRenderTarget(dstTexture->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002041 convolve_gaussian(fGpu, srcTexture, srcRect, sigmaX, radiusX,
2042 Gr1DKernelEffect::kX_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002043 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002044 if (temp2 && dstTexture == origTexture) {
2045 dstTexture = temp2->texture();
2046 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002047 }
2048
2049 if (sigmaY > 0.0f) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002050 if (scaleFactorY > 1 || sigmaX > 0.0f) {
bsalomon@google.comb505a122012-05-31 18:40:36 +00002051 // Clear out a radius below the srcRect to prevent the Y
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002052 // convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002053 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002054 srcIRect.width(), radiusY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002055 this->clear(&clearRect, 0x0);
2056 }
2057
2058 this->setRenderTarget(dstTexture->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002059 convolve_gaussian(fGpu, srcTexture, srcRect, sigmaY, radiusY,
2060 Gr1DKernelEffect::kY_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002061 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002062 if (temp2 && dstTexture == origTexture) {
2063 dstTexture = temp2->texture();
2064 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002065 }
2066
2067 if (scaleFactorX > 1 || scaleFactorY > 1) {
2068 // Clear one pixel to the right and below, to accommodate bilinear
2069 // upsampling.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002070 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2071 srcIRect.width() + 1, 1);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002072 this->clear(&clearRect, 0x0);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002073 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2074 1, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002075 this->clear(&clearRect, 0x0);
2076 // FIXME: This should be mitchell, not bilinear.
2077 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2078 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2079 srcTexture->height());
2080 this->setRenderTarget(dstTexture->asRenderTarget());
2081 paint.setTexture(0, srcTexture);
2082 SkRect dstRect(srcRect);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002083 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002084 this->drawRectToRect(paint, dstRect, srcRect);
2085 srcRect = dstRect;
2086 SkTSwap(srcTexture, dstTexture);
2087 }
2088 this->setRenderTarget(oldRenderTarget);
2089 this->setClip(oldClip);
2090 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002091}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002092
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002093GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2094 const GrRect& rect,
2095 GrTexture* temp1, GrTexture* temp2,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002096 MorphologyType morphType,
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002097 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002098 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002099 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2100 GrAutoMatrix avm(this, GrMatrix::I());
2101 GrClip oldClip = this->getClip();
robertphillips@google.com7a396332012-05-10 15:11:27 +00002102 this->setClip(GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
2103 SkIntToScalar(srcTexture->height())));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002104 if (radius.fWidth > 0) {
2105 this->setRenderTarget(temp1->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002106 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, morphType,
2107 Gr1DKernelEffect::kX_Direction);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002108 SkIRect clearRect = SkIRect::MakeXYWH(
2109 SkScalarFloorToInt(rect.fLeft),
2110 SkScalarFloorToInt(rect.fBottom),
2111 SkScalarFloorToInt(rect.width()),
2112 radius.fHeight);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002113 this->clear(&clearRect, 0x0);
2114 srcTexture = temp1;
2115 }
2116 if (radius.fHeight > 0) {
2117 this->setRenderTarget(temp2->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002118 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, morphType,
2119 Gr1DKernelEffect::kY_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002120 srcTexture = temp2;
2121 }
2122 this->setRenderTarget(oldRenderTarget);
2123 this->setClip(oldClip);
2124 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002125}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002126
robertphillips@google.com49d9fd52012-05-23 11:44:08 +00002127void GrContext::postClipPush() {
2128 fGpu->postClipPush();
2129}
2130
2131void GrContext::preClipPop() {
2132 fGpu->preClipPop();
2133};
2134
bsalomon@google.comc4364992011-11-07 15:54:49 +00002135///////////////////////////////////////////////////////////////////////////////