blob: 3708993674e1b38d438c9d7f3c45d935f0e8daa9 [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 const GrTextureDesc& desc,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000256 const GrSamplerState* sampler) {
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000257 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, desc, false);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000258 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
259 GrResourceCache::kNested_LockType));
260}
261
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000262bool GrContext::isTextureInCache(const GrTextureDesc& desc,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000263 const GrSamplerState* sampler) const {
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000264 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, desc, false);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000265 return fTextureCache->hasKey(resourceKey);
266}
267
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000268GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000269 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000270 uint32_t v[4];
271 gen_stencil_key_values(sb, v);
272 GrResourceKey resourceKey(v);
273 return fTextureCache->createAndLock(resourceKey, sb);
274}
275
276GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
277 int sampleCnt) {
278 uint32_t v[4];
279 gen_stencil_key_values(width, height, sampleCnt, v);
280 GrResourceKey resourceKey(v);
281 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
282 GrResourceCache::kSingle_LockType);
283 if (NULL != entry) {
284 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
285 return sb;
286 } else {
287 return NULL;
288 }
289}
290
291void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000292 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000293 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000294}
295
296static void stretchImage(void* dst,
297 int dstW,
298 int dstH,
299 void* src,
300 int srcW,
301 int srcH,
302 int bpp) {
303 GrFixed dx = (srcW << 16) / dstW;
304 GrFixed dy = (srcH << 16) / dstH;
305
306 GrFixed y = dy >> 1;
307
308 int dstXLimit = dstW*bpp;
309 for (int j = 0; j < dstH; ++j) {
310 GrFixed x = dx >> 1;
311 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
312 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
313 for (int i = 0; i < dstXLimit; i += bpp) {
314 memcpy((uint8_t*) dstRow + i,
315 (uint8_t*) srcRow + (x>>16)*bpp,
316 bpp);
317 x += dx;
318 }
319 y += dy;
320 }
321}
322
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000323GrContext::TextureCacheEntry GrContext::createAndLockTexture(
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000324 const GrSamplerState* sampler,
325 const GrTextureDesc& desc,
326 void* srcData,
327 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000328 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000329
330#if GR_DUMP_TEXTURE_UPLOAD
331 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
332#endif
333
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000334 TextureCacheEntry entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000335
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000336 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler,
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000337 desc, false);
338
339 if (GrTexture::NeedsResizing(resourceKey)) {
340 // The desired texture is NPOT and tiled but that isn't supported by
341 // the current hardware. Resize the texture to be a POT
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000342 GrAssert(NULL != sampler);
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000343 TextureCacheEntry clampEntry = this->findAndLockTexture(desc,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000344 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000345
346 if (NULL == clampEntry.texture()) {
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000347 clampEntry = this->createAndLockTexture(NULL, desc,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000348 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000349 GrAssert(NULL != clampEntry.texture());
350 if (NULL == clampEntry.texture()) {
351 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000352 }
353 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000354 GrTextureDesc rtDesc = desc;
355 rtDesc.fFlags = rtDesc.fFlags |
356 kRenderTarget_GrTextureFlagBit |
357 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000358 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
359 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000360
361 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
362
363 if (NULL != texture) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +0000364 GrDrawTarget::AutoStateRestore asr(fGpu,
365 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000366 GrDrawState* drawState = fGpu->drawState();
367 drawState->setRenderTarget(texture->asRenderTarget());
368 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000369
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000370 GrSamplerState::Filter filter;
371 // if filtering is not desired then we want to ensure all
372 // texels in the resampled image are copies of texels from
373 // the original.
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000374 if (GrTexture::NeedsFiltering(resourceKey)) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000375 filter = GrSamplerState::kBilinear_Filter;
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000376 } else {
377 filter = GrSamplerState::kNearest_Filter;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000378 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000379 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
380 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000381
382 static const GrVertexLayout layout =
383 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
384 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
385
386 if (arg.succeeded()) {
387 GrPoint* verts = (GrPoint*) arg.vertices();
388 verts[0].setIRectFan(0, 0,
389 texture->width(),
390 texture->height(),
391 2*sizeof(GrPoint));
392 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
bsalomon@google.com47059542012-06-06 20:51:20 +0000393 fGpu->drawNonIndexed(kTriangleFan_GrPrimitiveType,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000394 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000395 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000396 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000397 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 } else {
399 // TODO: Our CPU stretch doesn't filter. But we create separate
400 // stretched textures when the sampler state is either filtered or
401 // not. Either implement filtered stretch blit on CPU or just create
402 // one when FBO case fails.
403
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000404 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000405 // no longer need to clamp at min RT size.
406 rtDesc.fWidth = GrNextPow2(desc.fWidth);
407 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000408 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000409 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000410 rtDesc.fWidth *
411 rtDesc.fHeight);
412 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
413 srcData, desc.fWidth, desc.fHeight, bpp);
414
415 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
416
417 GrTexture* texture = fGpu->createTexture(rtDesc,
418 stretchedPixels.get(),
419 stretchedRowBytes);
420 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000422 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000423 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000424
425 } else {
426 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
427 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000428 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000429 }
430 }
431 return entry;
432}
433
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434GrContext::TextureCacheEntry GrContext::lockScratchTexture(
435 const GrTextureDesc& inDesc,
436 ScratchTexMatch match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000437 GrTextureDesc desc = inDesc;
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000438 desc.fClientCacheID = kScratch_CacheID;
439
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000440 if (kExact_ScratchTexMatch != match) {
441 // bin by pow2 with a reasonable min
442 static const int MIN_SIZE = 256;
443 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
444 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
445 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000446
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000447 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000448 int origWidth = desc.fWidth;
449 int origHeight = desc.fHeight;
450 bool doubledW = false;
451 bool doubledH = false;
452
453 do {
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000454 GrResourceKey key = GrTexture::ComputeKey(fGpu, NULL, desc, true);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000455 entry = fTextureCache->findAndLock(key,
456 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000457 // if we miss, relax the fit of the flags...
458 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000459 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000460 break;
461 }
462 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
463 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
464 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
465 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
466 } else if (!doubledW) {
467 desc.fFlags = inDesc.fFlags;
468 desc.fWidth *= 2;
469 doubledW = true;
470 } else if (!doubledH) {
471 desc.fFlags = inDesc.fFlags;
472 desc.fWidth = origWidth;
473 desc.fHeight *= 2;
474 doubledH = true;
475 } else {
476 break;
477 }
478
479 } while (true);
480
481 if (NULL == entry) {
482 desc.fFlags = inDesc.fFlags;
483 desc.fWidth = origWidth;
484 desc.fHeight = origHeight;
485 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
486 if (NULL != texture) {
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000487 GrResourceKey key = GrTexture::ComputeKey(fGpu, NULL,
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000488 texture->desc(),
489 true);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000490 entry = fTextureCache->createAndLock(key, texture);
491 }
492 }
493
494 // If the caller gives us the same desc/sampler twice we don't want
495 // to return the same texture the second time (unless it was previously
496 // released). So we detach the entry from the cache and reattach at release.
497 if (NULL != entry) {
498 fTextureCache->detach(entry);
499 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000501}
502
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000503void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000504 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000505 // If this is a scratch texture we detached it from the cache
506 // while it was locked (to avoid two callers simultaneously getting
507 // the same texture).
robertphillips@google.coma1e57952012-06-04 20:05:28 +0000508 if (GrTexture::IsScratchTexture(entry.cacheEntry()->key())) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000509 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000510 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000511 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000512 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000513}
514
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000515GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& descIn,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000516 void* srcData,
517 size_t rowBytes) {
robertphillips@google.com75b3c962012-06-07 12:08:45 +0000518 GrTextureDesc descCopy = descIn;
519 descCopy.fClientCacheID = kUncached_CacheID;
520 return fGpu->createTexture(descCopy, srcData, rowBytes);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000521}
522
523void GrContext::getTextureCacheLimits(int* maxTextures,
524 size_t* maxTextureBytes) const {
525 fTextureCache->getLimits(maxTextures, maxTextureBytes);
526}
527
528void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
529 fTextureCache->setLimits(maxTextures, maxTextureBytes);
530}
531
bsalomon@google.com91958362011-06-13 17:58:13 +0000532int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000533 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000534}
535
536int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000537 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000538}
539
540///////////////////////////////////////////////////////////////////////////////
541
bsalomon@google.come269f212011-11-07 13:29:52 +0000542GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
543 return fGpu->createPlatformTexture(desc);
544}
545
546GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
547 return fGpu->createPlatformRenderTarget(desc);
548}
549
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000550///////////////////////////////////////////////////////////////////////////////
551
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000552bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000553 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000554 const GrDrawTarget::Caps& caps = fGpu->getCaps();
555 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000556 return false;
557 }
558
bsalomon@google.com27847de2011-02-22 20:59:41 +0000559 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
560
561 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000562 bool tiled = NULL != sampler &&
563 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
564 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000565 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000566 return false;
567 }
568 }
569 return true;
570}
571
572////////////////////////////////////////////////////////////////////////////////
573
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000574const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
575
bsalomon@google.com27847de2011-02-22 20:59:41 +0000576void GrContext::setClip(const GrClip& clip) {
577 fGpu->setClip(clip);
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000578 fDrawState->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000579}
580
581void GrContext::setClip(const GrIRect& rect) {
582 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000583 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000584 fGpu->setClip(clip);
585}
586
587////////////////////////////////////////////////////////////////////////////////
588
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000589void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000590 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000591 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000592}
593
594void GrContext::drawPaint(const GrPaint& paint) {
595 // set rect to be big enough to fill the space, but not super-huge, so we
596 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000597 GrRect r;
598 r.setLTRB(0, 0,
599 GrIntToScalar(getRenderTarget()->width()),
600 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000601 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000602 SkTLazy<GrPaint> tmpPaint;
603 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000604 GrAutoMatrix am;
605
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000606 // We attempt to map r by the inverse matrix and draw that. mapRect will
607 // map the four corners and bound them with a new rect. This will not
608 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000609 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000610 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000611 GrPrintf("Could not invert matrix");
612 return;
613 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000614 inverse.mapRect(&r);
615 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000616 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +0000617 if (!fDrawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000618 GrPrintf("Could not invert matrix");
619 return;
620 }
621 tmpPaint.set(paint);
622 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
623 p = tmpPaint.get();
624 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000625 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000626 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000627 // by definition this fills the entire clip, no need for AA
628 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000629 if (!tmpPaint.isValid()) {
630 tmpPaint.set(paint);
631 p = tmpPaint.get();
632 }
633 GrAssert(p == tmpPaint.get());
634 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000635 }
636 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000637}
638
bsalomon@google.com205d4602011-04-25 12:43:45 +0000639////////////////////////////////////////////////////////////////////////////////
640
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000641namespace {
642inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
643 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
644}
645}
646
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000647////////////////////////////////////////////////////////////////////////////////
648
bsalomon@google.com27847de2011-02-22 20:59:41 +0000649/* create a triangle strip that strokes the specified triangle. There are 8
650 unique vertices, but we repreat the last 2 to close up. Alternatively we
651 could use an indices array, and then only send 8 verts, but not sure that
652 would be faster.
653 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000654static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000655 GrScalar width) {
656 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000657 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000658
659 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
660 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
661 verts[2].set(rect.fRight - rad, rect.fTop + rad);
662 verts[3].set(rect.fRight + rad, rect.fTop - rad);
663 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
664 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
665 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
666 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
667 verts[8] = verts[0];
668 verts[9] = verts[1];
669}
670
bsalomon@google.com205d4602011-04-25 12:43:45 +0000671static void setInsetFan(GrPoint* pts, size_t stride,
672 const GrRect& r, GrScalar dx, GrScalar dy) {
673 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
674}
675
676static const uint16_t gFillAARectIdx[] = {
677 0, 1, 5, 5, 4, 0,
678 1, 2, 6, 6, 5, 1,
679 2, 3, 7, 7, 6, 2,
680 3, 0, 4, 4, 7, 3,
681 4, 5, 6, 6, 7, 4,
682};
683
684int GrContext::aaFillRectIndexCount() const {
685 return GR_ARRAY_COUNT(gFillAARectIdx);
686}
687
688GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
689 if (NULL == fAAFillRectIndexBuffer) {
690 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
691 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000692 if (NULL != fAAFillRectIndexBuffer) {
693 #if GR_DEBUG
694 bool updated =
695 #endif
696 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
697 sizeof(gFillAARectIdx));
698 GR_DEBUGASSERT(updated);
699 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000700 }
701 return fAAFillRectIndexBuffer;
702}
703
704static const uint16_t gStrokeAARectIdx[] = {
705 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
706 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
707 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
708 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
709
710 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
711 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
712 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
713 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
714
715 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
716 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
717 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
718 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
719};
720
721int GrContext::aaStrokeRectIndexCount() const {
722 return GR_ARRAY_COUNT(gStrokeAARectIdx);
723}
724
725GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
726 if (NULL == fAAStrokeRectIndexBuffer) {
727 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
728 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000729 if (NULL != fAAStrokeRectIndexBuffer) {
730 #if GR_DEBUG
731 bool updated =
732 #endif
733 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
734 sizeof(gStrokeAARectIdx));
735 GR_DEBUGASSERT(updated);
736 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000737 }
738 return fAAStrokeRectIndexBuffer;
739}
740
bsalomon@google.coma3108262011-10-10 14:08:47 +0000741static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
742 bool useCoverage) {
743 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000744 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000745 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000746 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
747 }
748 }
749 if (useCoverage) {
750 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
751 } else {
752 layout |= GrDrawTarget::kColor_VertexLayoutBit;
753 }
754 return layout;
755}
756
bsalomon@google.com205d4602011-04-25 12:43:45 +0000757void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000758 const GrRect& devRect,
759 bool useVertexCoverage) {
760 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000761
762 size_t vsize = GrDrawTarget::VertexSize(layout);
763
764 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000765 if (!geo.succeeded()) {
766 GrPrintf("Failed to get space for vertices!\n");
767 return;
768 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000769 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
770 if (NULL == indexBuffer) {
771 GrPrintf("Failed to create index buffer!\n");
772 return;
773 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000774
775 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
776
777 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
778 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
779
780 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
781 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
782
783 verts += sizeof(GrPoint);
784 for (int i = 0; i < 4; ++i) {
785 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
786 }
787
bsalomon@google.coma3108262011-10-10 14:08:47 +0000788 GrColor innerColor;
789 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000790 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000791 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000792 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000793 }
794
bsalomon@google.com205d4602011-04-25 12:43:45 +0000795 verts += 4 * vsize;
796 for (int i = 0; i < 4; ++i) {
797 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
798 }
799
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000800 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000801
bsalomon@google.com47059542012-06-06 20:51:20 +0000802 target->drawIndexed(kTriangles_GrPrimitiveType, 0,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000803 0, 8, this->aaFillRectIndexCount());
804}
805
bsalomon@google.coma3108262011-10-10 14:08:47 +0000806void GrContext::strokeAARect(GrDrawTarget* target,
807 const GrRect& devRect,
808 const GrVec& devStrokeSize,
809 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000810 const GrScalar& dx = devStrokeSize.fX;
811 const GrScalar& dy = devStrokeSize.fY;
812 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
813 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
814
bsalomon@google.com205d4602011-04-25 12:43:45 +0000815 GrScalar spare;
816 {
817 GrScalar w = devRect.width() - dx;
818 GrScalar h = devRect.height() - dy;
819 spare = GrMin(w, h);
820 }
821
822 if (spare <= 0) {
823 GrRect r(devRect);
824 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000825 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000826 return;
827 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000828 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000829 size_t vsize = GrDrawTarget::VertexSize(layout);
830
831 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000832 if (!geo.succeeded()) {
833 GrPrintf("Failed to get space for vertices!\n");
834 return;
835 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000836 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
837 if (NULL == indexBuffer) {
838 GrPrintf("Failed to create index buffer!\n");
839 return;
840 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000841
842 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
843
844 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
845 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
846 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
847 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
848
849 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
850 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
851 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
852 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
853
854 verts += sizeof(GrPoint);
855 for (int i = 0; i < 4; ++i) {
856 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
857 }
858
bsalomon@google.coma3108262011-10-10 14:08:47 +0000859 GrColor innerColor;
860 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000861 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000862 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000863 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000864 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000865 verts += 4 * vsize;
866 for (int i = 0; i < 8; ++i) {
867 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
868 }
869
870 verts += 8 * vsize;
871 for (int i = 0; i < 8; ++i) {
872 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
873 }
874
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000875 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com47059542012-06-06 20:51:20 +0000876 target->drawIndexed(kTriangles_GrPrimitiveType,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000877 0, 0, 16, aaStrokeRectIndexCount());
878}
879
reed@google.com20efde72011-05-09 17:00:02 +0000880/**
881 * Returns true if the rects edges are integer-aligned.
882 */
883static bool isIRect(const GrRect& r) {
884 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
885 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
886}
887
bsalomon@google.com205d4602011-04-25 12:43:45 +0000888static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000889 const GrRect& rect,
890 GrScalar width,
891 const GrMatrix* matrix,
892 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000893 GrRect* devRect,
894 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000895 // we use a simple coverage ramp to do aa on axis-aligned rects
896 // we check if the rect will be axis-aligned, and the rect won't land on
897 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000898
bsalomon@google.coma3108262011-10-10 14:08:47 +0000899 // we are keeping around the "tweak the alpha" trick because
900 // it is our only hope for the fixed-pipe implementation.
901 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000902 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000903 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000904 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000905 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000906#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000907 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000908#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000909 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000910 } else {
911 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000912 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000913 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000914 const GrDrawState& drawState = target->getDrawState();
915 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000916 return false;
917 }
918
bsalomon@google.com471d4712011-08-23 15:45:25 +0000919 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000920 return false;
921 }
922
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000923 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000924 return false;
925 }
926
927 if (NULL != matrix &&
928 !matrix->preservesAxisAlignment()) {
929 return false;
930 }
931
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000932 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000933 if (NULL != matrix) {
934 combinedMatrix->preConcat(*matrix);
935 GrAssert(combinedMatrix->preservesAxisAlignment());
936 }
937
938 combinedMatrix->mapRect(devRect, rect);
939 devRect->sort();
940
941 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000942 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000943 } else {
944 return true;
945 }
946}
947
bsalomon@google.com27847de2011-02-22 20:59:41 +0000948void GrContext::drawRect(const GrPaint& paint,
949 const GrRect& rect,
950 GrScalar width,
951 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000952 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000953
954 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000955 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000956
bsalomon@google.com205d4602011-04-25 12:43:45 +0000957 GrRect devRect = rect;
958 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000959 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +0000960 bool needAA = paint.fAntiAlias &&
961 !this->getRenderTarget()->isMultisampled();
962 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
963 &combinedMatrix, &devRect,
964 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000965
966 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000967 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000968 if (width >= 0) {
969 GrVec strokeSize;;
970 if (width > 0) {
971 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000972 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000973 strokeSize.setAbs(strokeSize);
974 } else {
975 strokeSize.set(GR_Scalar1, GR_Scalar1);
976 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000977 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000978 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000979 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000980 }
981 return;
982 }
983
bsalomon@google.com27847de2011-02-22 20:59:41 +0000984 if (width >= 0) {
985 // TODO: consider making static vertex buffers for these cases.
986 // Hairline could be done by just adding closing vertex to
987 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000988 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
989
bsalomon@google.com27847de2011-02-22 20:59:41 +0000990 static const int worstCaseVertCount = 10;
991 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
992
993 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000994 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000995 return;
996 }
997
998 GrPrimitiveType primType;
999 int vertCount;
1000 GrPoint* vertex = geo.positions();
1001
1002 if (width > 0) {
1003 vertCount = 10;
bsalomon@google.com47059542012-06-06 20:51:20 +00001004 primType = kTriangleStrip_GrPrimitiveType;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001005 setStrokeRectStrip(vertex, rect, width);
1006 } else {
1007 // hairline
1008 vertCount = 5;
bsalomon@google.com47059542012-06-06 20:51:20 +00001009 primType = kLineStrip_GrPrimitiveType;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001010 vertex[0].set(rect.fLeft, rect.fTop);
1011 vertex[1].set(rect.fRight, rect.fTop);
1012 vertex[2].set(rect.fRight, rect.fBottom);
1013 vertex[3].set(rect.fLeft, rect.fBottom);
1014 vertex[4].set(rect.fLeft, rect.fTop);
1015 }
1016
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001017 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001018 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001019 GrDrawState* drawState = target->drawState();
1020 avmr.set(drawState);
1021 drawState->preConcatViewMatrix(*matrix);
1022 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001023 }
1024
1025 target->drawNonIndexed(primType, 0, vertCount);
1026 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001027#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001028 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001029 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1030 if (NULL == sqVB) {
1031 GrPrintf("Failed to create static rect vb.\n");
1032 return;
1033 }
1034 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001035 GrDrawState* drawState = target->drawState();
1036 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001037 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001038 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001039 0, rect.height(), rect.fTop,
1040 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001041
1042 if (NULL != matrix) {
1043 m.postConcat(*matrix);
1044 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001045 drawState->preConcatViewMatrix(m);
1046 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001047
bsalomon@google.com47059542012-06-06 20:51:20 +00001048 target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001049#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001050 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001051#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001052 }
1053}
1054
1055void GrContext::drawRectToRect(const GrPaint& paint,
1056 const GrRect& dstRect,
1057 const GrRect& srcRect,
1058 const GrMatrix* dstMatrix,
1059 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001060 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001061
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001062 // srcRect refers to paint's first texture
1063 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001064 drawRect(paint, dstRect, -1, dstMatrix);
1065 return;
1066 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001067
bsalomon@google.com27847de2011-02-22 20:59:41 +00001068 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1069
1070#if GR_STATIC_RECT_VB
1071 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001072 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001073 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001074 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001075
1076 GrMatrix m;
1077
1078 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1079 0, dstRect.height(), dstRect.fTop,
1080 0, 0, GrMatrix::I()[8]);
1081 if (NULL != dstMatrix) {
1082 m.postConcat(*dstMatrix);
1083 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001084 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001085
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001086 // srcRect refers to first stage
1087 int otherStageMask = paint.getActiveStageMask() &
1088 (~(1 << GrPaint::kFirstTextureStage));
1089 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001090 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001091 }
1092
bsalomon@google.com27847de2011-02-22 20:59:41 +00001093 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1094 0, srcRect.height(), srcRect.fTop,
1095 0, 0, GrMatrix::I()[8]);
1096 if (NULL != srcMatrix) {
1097 m.postConcat(*srcMatrix);
1098 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001099 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001100
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001101 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1102 if (NULL == sqVB) {
1103 GrPrintf("Failed to create static rect vb.\n");
1104 return;
1105 }
1106 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com47059542012-06-06 20:51:20 +00001107 target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001108#else
1109
1110 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001111#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001112 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001113#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001114 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1115#endif
1116
tomhudson@google.com93813632011-10-27 20:21:16 +00001117 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1118 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119 srcRects[0] = &srcRect;
1120 srcMatrices[0] = srcMatrix;
1121
1122 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1123#endif
1124}
1125
1126void GrContext::drawVertices(const GrPaint& paint,
1127 GrPrimitiveType primitiveType,
1128 int vertexCount,
1129 const GrPoint positions[],
1130 const GrPoint texCoords[],
1131 const GrColor colors[],
1132 const uint16_t indices[],
1133 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001134 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001135
1136 GrDrawTarget::AutoReleaseGeometry geo;
1137
1138 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1139
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001140 bool hasTexCoords[GrPaint::kTotalStages] = {
1141 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1142 0 // remaining stages use positions
1143 };
1144
1145 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146
1147 if (NULL != colors) {
1148 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001149 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001150 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001151
1152 if (sizeof(GrPoint) != vertexSize) {
1153 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001154 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001155 return;
1156 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001157 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001158 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001159 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1160 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001161 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001162 NULL,
1163 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001164 void* curVertex = geo.vertices();
1165
1166 for (int i = 0; i < vertexCount; ++i) {
1167 *((GrPoint*)curVertex) = positions[i];
1168
1169 if (texOffsets[0] > 0) {
1170 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1171 }
1172 if (colorOffset > 0) {
1173 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1174 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001175 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001176 }
1177 } else {
1178 target->setVertexSourceToArray(layout, positions, vertexCount);
1179 }
1180
bsalomon@google.com91958362011-06-13 17:58:13 +00001181 // we don't currently apply offscreen AA to this path. Need improved
1182 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001183
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001184 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001185 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001186 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001187 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001188 target->drawNonIndexed(primitiveType, 0, vertexCount);
1189 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001190}
1191
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001192///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001193namespace {
1194
bsalomon@google.com93c96602012-04-27 13:05:21 +00001195struct CircleVertex {
1196 GrPoint fPos;
1197 GrPoint fCenter;
1198 GrScalar fOuterRadius;
1199 GrScalar fInnerRadius;
1200};
1201
1202/* Returns true if will map a circle to another circle. This can be true
1203 * if the matrix only includes square-scale, rotation, translation.
1204 */
1205inline bool isSimilarityTransformation(const SkMatrix& matrix,
1206 SkScalar tol = SK_ScalarNearlyZero) {
1207 if (matrix.isIdentity() || matrix.getType() == SkMatrix::kTranslate_Mask) {
1208 return true;
1209 }
1210 if (matrix.hasPerspective()) {
1211 return false;
1212 }
1213
1214 SkScalar mx = matrix.get(SkMatrix::kMScaleX);
1215 SkScalar sx = matrix.get(SkMatrix::kMSkewX);
1216 SkScalar my = matrix.get(SkMatrix::kMScaleY);
1217 SkScalar sy = matrix.get(SkMatrix::kMSkewY);
1218
1219 if (mx == 0 && sx == 0 && my == 0 && sy == 0) {
1220 return false;
1221 }
1222
1223 // it has scales or skews, but it could also be rotation, check it out.
1224 SkVector vec[2];
1225 vec[0].set(mx, sx);
1226 vec[1].set(sy, my);
1227
1228 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
1229 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
1230 SkScalarSquare(tol));
1231}
1232
1233}
1234
1235// TODO: strokeWidth can't be larger than zero right now.
1236// It will be fixed when drawPath() can handle strokes.
1237void GrContext::drawOval(const GrPaint& paint,
1238 const GrRect& rect,
1239 SkScalar strokeWidth) {
1240 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1241 kUnbuffered_DrawCategory;
1242 GrDrawTarget* target = this->prepareToDraw(paint, category);
1243 GrDrawState* drawState = target->drawState();
1244 GrMatrix vm = drawState->getViewMatrix();
1245
1246 if (!isSimilarityTransformation(vm) ||
1247 !paint.fAntiAlias ||
1248 rect.height() != rect.width()) {
1249 SkPath path;
1250 path.addOval(rect);
1251 GrPathFill fill = (strokeWidth == 0) ?
bsalomon@google.com47059542012-06-06 20:51:20 +00001252 kHairLine_GrPathFill : kWinding_GrPathFill;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001253 this->internalDrawPath(paint, path, fill, NULL);
1254 return;
1255 }
1256
1257 const GrRenderTarget* rt = drawState->getRenderTarget();
1258 if (NULL == rt) {
1259 return;
1260 }
1261
1262 GrDrawTarget::AutoDeviceCoordDraw adcd(target, paint.getActiveStageMask());
1263
1264 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1265 layout |= GrDrawTarget::kEdge_VertexLayoutBit;
1266 GrAssert(sizeof(CircleVertex) == GrDrawTarget::VertexSize(layout));
1267
1268 GrPoint center = GrPoint::Make(rect.centerX(), rect.centerY());
1269 GrScalar radius = SkScalarHalf(rect.width());
1270
1271 vm.mapPoints(&center, 1);
1272 radius = vm.mapRadius(radius);
1273
1274 GrScalar outerRadius = radius;
1275 GrScalar innerRadius = 0;
1276 SkScalar halfWidth = 0;
1277 if (strokeWidth == 0) {
1278 halfWidth = SkScalarHalf(SK_Scalar1);
1279
1280 outerRadius += halfWidth;
1281 innerRadius = SkMaxScalar(0, radius - halfWidth);
1282 }
1283
1284 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 4, 0);
1285 if (!geo.succeeded()) {
1286 GrPrintf("Failed to get space for vertices!\n");
1287 return;
1288 }
1289
1290 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
1291
1292 SkScalar L = center.fX - outerRadius;
1293 SkScalar R = center.fX + outerRadius;
1294 SkScalar T = center.fY - outerRadius;
1295 SkScalar B = center.fY + outerRadius;
1296
1297 verts[0].fPos = SkPoint::Make(L, T);
1298 verts[1].fPos = SkPoint::Make(R, T);
1299 verts[2].fPos = SkPoint::Make(L, B);
1300 verts[3].fPos = SkPoint::Make(R, B);
1301
1302 for (int i = 0; i < 4; ++i) {
1303 // this goes to fragment shader, it should be in y-points-up space.
1304 verts[i].fCenter = SkPoint::Make(center.fX, rt->height() - center.fY);
1305
1306 verts[i].fOuterRadius = outerRadius;
1307 verts[i].fInnerRadius = innerRadius;
1308 }
1309
1310 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType);
bsalomon@google.com47059542012-06-06 20:51:20 +00001311 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001312}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001313
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001314void GrContext::drawPath(const GrPaint& paint, const SkPath& path,
reed@google.com07f3ee12011-05-16 17:21:57 +00001315 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001316
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001317 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001318 if (GrIsFillInverted(fill)) {
1319 this->drawPaint(paint);
1320 }
1321 return;
1322 }
1323
bsalomon@google.com93c96602012-04-27 13:05:21 +00001324 SkRect ovalRect;
1325 if (!GrIsFillInverted(fill) && path.isOval(&ovalRect)) {
1326 if (translate) {
1327 ovalRect.offset(*translate);
1328 }
bsalomon@google.com47059542012-06-06 20:51:20 +00001329 SkScalar width = (fill == kHairLine_GrPathFill) ? 0 : -SK_Scalar1;
bsalomon@google.com93c96602012-04-27 13:05:21 +00001330 this->drawOval(paint, ovalRect, width);
1331 return;
1332 }
1333
1334 internalDrawPath(paint, path, fill, translate);
1335}
1336
bsalomon@google.com8d033a12012-04-27 15:52:53 +00001337void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
bsalomon@google.com93c96602012-04-27 13:05:21 +00001338 GrPathFill fill, const GrPoint* translate) {
1339
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001340 // Note that below we may sw-rasterize the path into a scratch texture.
1341 // Scratch textures can be recycled after they are returned to the texture
1342 // cache. This presents a potential hazard for buffered drawing. However,
1343 // the writePixels that uploads to the scratch will perform a flush so we're
1344 // OK.
1345 DrawCategory category = (DEFER_PATHS) ? kBuffered_DrawCategory :
1346 kUnbuffered_DrawCategory;
1347 GrDrawTarget* target = this->prepareToDraw(paint, category);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001348 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001349
bsalomon@google.com289533a2011-10-27 12:34:25 +00001350 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1351
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001352 // An Assumption here is that path renderer would use some form of tweaking
1353 // the src color (either the input alpha or in the frag shader) to implement
1354 // aa. If we have some future driver-mojo path AA that can do the right
1355 // thing WRT to the blend then we'll need some query on the PR.
1356 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001357#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001358 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001359#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001360 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001361 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001362
robertphillips@google.com72176b22012-05-23 13:19:12 +00001363 GrPathRenderer* pr = this->getPathRenderer(path, fill, target, prAA, true);
bsalomon@google.com30085192011-08-19 15:42:31 +00001364 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001365#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001366 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001367#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001368 return;
1369 }
1370
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001371 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001373
bsalomon@google.com27847de2011-02-22 20:59:41 +00001374////////////////////////////////////////////////////////////////////////////////
1375
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001376void GrContext::flush(int flagsBitfield) {
1377 if (kDiscard_FlushBit & flagsBitfield) {
1378 fDrawBuffer->reset();
1379 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001380 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001381 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001382 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001383 fGpu->forceRenderTargetFlush();
1384 }
1385}
1386
bsalomon@google.com27847de2011-02-22 20:59:41 +00001387void GrContext::flushDrawBuffer() {
junov@google.com53a55842011-06-08 22:55:10 +00001388 if (fDrawBuffer) {
robertphillips@google.com58b38182012-05-03 16:29:41 +00001389 // With addition of the AA clip path, flushing the draw buffer can
1390 // result in the generation of an AA clip mask. During this
1391 // process the SW path renderer may be invoked which recusively
1392 // calls this method (via internalWriteTexturePixels) creating
1393 // infinite recursion
1394 GrInOrderDrawBuffer* temp = fDrawBuffer;
1395 fDrawBuffer = NULL;
1396
1397 temp->flushTo(fGpu);
1398
1399 fDrawBuffer = temp;
junov@google.com53a55842011-06-08 22:55:10 +00001400 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001401}
1402
bsalomon@google.com6f379512011-11-16 20:36:03 +00001403void GrContext::internalWriteTexturePixels(GrTexture* texture,
1404 int left, int top,
1405 int width, int height,
1406 GrPixelConfig config,
1407 const void* buffer,
1408 size_t rowBytes,
1409 uint32_t flags) {
1410 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001411 ASSERT_OWNED_RESOURCE(texture);
1412
bsalomon@google.com6f379512011-11-16 20:36:03 +00001413 if (!(kDontFlush_PixelOpsFlag & flags)) {
1414 this->flush();
1415 }
1416 // TODO: use scratch texture to perform conversion
1417 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1418 GrPixelConfigIsUnpremultiplied(config)) {
1419 return;
1420 }
1421
1422 fGpu->writeTexturePixels(texture, left, top, width, height,
1423 config, buffer, rowBytes);
1424}
1425
1426bool GrContext::internalReadTexturePixels(GrTexture* texture,
1427 int left, int top,
1428 int width, int height,
1429 GrPixelConfig config,
1430 void* buffer,
1431 size_t rowBytes,
1432 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001433 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001434 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001435
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001436 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001437 GrRenderTarget* target = texture->asRenderTarget();
1438 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001439 return this->internalReadRenderTargetPixels(target,
1440 left, top, width, height,
1441 config, buffer, rowBytes,
1442 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001443 } else {
1444 return false;
1445 }
1446}
1447
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001448#include "SkConfig8888.h"
1449
1450namespace {
1451/**
1452 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1453 * formats are representable as Config8888 and so the function returns false
1454 * if the GrPixelConfig has no equivalent Config8888.
1455 */
1456bool grconfig_to_config8888(GrPixelConfig config,
1457 SkCanvas::Config8888* config8888) {
1458 switch (config) {
1459 case kRGBA_8888_PM_GrPixelConfig:
1460 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1461 return true;
1462 case kRGBA_8888_UPM_GrPixelConfig:
1463 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1464 return true;
1465 case kBGRA_8888_PM_GrPixelConfig:
1466 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1467 return true;
1468 case kBGRA_8888_UPM_GrPixelConfig:
1469 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1470 return true;
1471 default:
1472 return false;
1473 }
1474}
1475}
1476
bsalomon@google.com6f379512011-11-16 20:36:03 +00001477bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1478 int left, int top,
1479 int width, int height,
1480 GrPixelConfig config,
1481 void* buffer,
1482 size_t rowBytes,
1483 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001484 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001485 ASSERT_OWNED_RESOURCE(target);
1486
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001487 if (NULL == target) {
bsalomon@google.com10e04bf2012-03-30 14:35:04 +00001488 target = fDrawState->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001489 if (NULL == target) {
1490 return false;
1491 }
1492 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001493
bsalomon@google.com6f379512011-11-16 20:36:03 +00001494 if (!(kDontFlush_PixelOpsFlag & flags)) {
1495 this->flush();
1496 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001497
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001498 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1499 GrPixelConfigIsUnpremultiplied(config) &&
1500 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1501 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1502 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1503 !grconfig_to_config8888(config, &dstConfig8888)) {
1504 return false;
1505 }
1506 // do read back using target's own config
1507 this->internalReadRenderTargetPixels(target,
1508 left, top,
1509 width, height,
1510 target->config(),
1511 buffer, rowBytes,
1512 kDontFlush_PixelOpsFlag);
1513 // sw convert the pixels to unpremul config
1514 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1515 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1516 pixels, rowBytes, srcConfig8888,
1517 width, height);
1518 return true;
1519 }
1520
bsalomon@google.comc4364992011-11-07 15:54:49 +00001521 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001522 bool swapRAndB = NULL != src &&
1523 fGpu->preferredReadPixelsConfig(config) ==
1524 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001525
1526 bool flipY = NULL != src &&
1527 fGpu->readPixelsWillPayForYFlip(target, left, top,
1528 width, height, config,
1529 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001530 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1531 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001532
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001533 if (NULL == src && alphaConversion) {
1534 // we should fallback to cpu conversion here. This could happen when
1535 // we were given an external render target by the client that is not
1536 // also a texture (e.g. FBO 0 in GL)
1537 return false;
1538 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001539 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001540 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001541 if (flipY || swapRAndB || alphaConversion) {
1542 GrAssert(NULL != src);
1543 if (swapRAndB) {
1544 config = GrPixelConfigSwapRAndB(config);
1545 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001546 }
1547 // Make the scratch a render target because we don't have a robust
1548 // readTexturePixels as of yet (it calls this function).
robertphillips@google.com75b3c962012-06-07 12:08:45 +00001549 GrTextureDesc desc;
1550 desc.fFlags = kRenderTarget_GrTextureFlagBit;
1551 desc.fWidth = width;
1552 desc.fHeight = height;
1553 desc.fConfig = config;
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001554
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001555 // When a full readback is faster than a partial we could always make
1556 // the scratch exactly match the passed rect. However, if we see many
1557 // different size rectangles we will trash our texture cache and pay the
1558 // cost of creating and destroying many textures. So, we only request
1559 // an exact match when the caller is reading an entire RT.
1560 ScratchTexMatch match = kApprox_ScratchTexMatch;
1561 if (0 == left &&
1562 0 == top &&
1563 target->width() == width &&
1564 target->height() == height &&
1565 fGpu->fullReadPixelsIsFasterThanPartial()) {
1566 match = kExact_ScratchTexMatch;
1567 }
1568 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001569 GrTexture* texture = ast.texture();
1570 if (!texture) {
1571 return false;
1572 }
1573 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001574 GrAssert(NULL != target);
1575
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001576 GrDrawTarget::AutoStateRestore asr(fGpu,
1577 GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001578 GrDrawState* drawState = fGpu->drawState();
1579 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001580
bsalomon@google.comc4364992011-11-07 15:54:49 +00001581 GrMatrix matrix;
1582 if (flipY) {
1583 matrix.setTranslate(SK_Scalar1 * left,
1584 SK_Scalar1 * (top + height));
1585 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1586 } else {
1587 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1588 }
1589 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001590 drawState->sampler(0)->reset(matrix);
1591 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001592 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001593 GrRect rect;
1594 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1595 fGpu->drawSimpleRect(rect, NULL, 0x1);
1596 left = 0;
1597 top = 0;
1598 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001599 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001600 left, top, width, height,
1601 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001602}
1603
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001604void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1605 GrAssert(target);
1606 ASSERT_OWNED_RESOURCE(target);
1607 // In the future we may track whether there are any pending draws to this
1608 // target. We don't today so we always perform a flush. We don't promise
1609 // this to our clients, though.
1610 this->flush();
1611 fGpu->resolveRenderTarget(target);
1612}
1613
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001614void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1615 if (NULL == src || NULL == dst) {
1616 return;
1617 }
1618 ASSERT_OWNED_RESOURCE(src);
1619
twiz@google.com1ac87ff2012-04-27 19:39:33 +00001620 // Writes pending to the source texture are not tracked, so a flush
1621 // is required to ensure that the copy captures the most recent contents
1622 // of the source texture. See similar behaviour in
1623 // GrContext::resolveRenderTarget.
1624 this->flush();
1625
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001626 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001627 GrDrawState* drawState = fGpu->drawState();
1628 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001629 GrMatrix sampleM;
1630 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001631 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001632 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001633 SkRect rect = SkRect::MakeXYWH(0, 0,
1634 SK_Scalar1 * src->width(),
1635 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001636 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1637}
1638
bsalomon@google.com6f379512011-11-16 20:36:03 +00001639void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1640 int left, int top,
1641 int width, int height,
1642 GrPixelConfig config,
1643 const void* buffer,
1644 size_t rowBytes,
1645 uint32_t flags) {
1646 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001647 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001648
1649 if (NULL == target) {
bsalomon@google.com873ea0c2012-03-30 15:55:32 +00001650 target = fDrawState->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001651 if (NULL == target) {
1652 return;
1653 }
1654 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001655
1656 // TODO: when underlying api has a direct way to do this we should use it
1657 // (e.g. glDrawPixels on desktop GL).
1658
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001659 // If the RT is also a texture and we don't have to do PM/UPM conversion
1660 // then take the texture path, which we expect to be at least as fast or
1661 // faster since it doesn't use an intermediate texture as we do below.
1662
1663#if !GR_MAC_BUILD
1664 // At least some drivers on the Mac get confused when glTexImage2D is called
1665 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1666 // determine what OS versions and/or HW is affected.
1667 if (NULL != target->asTexture() &&
1668 GrPixelConfigIsUnpremultiplied(target->config()) ==
1669 GrPixelConfigIsUnpremultiplied(config)) {
1670
1671 this->internalWriteTexturePixels(target->asTexture(),
1672 left, top, width, height,
1673 config, buffer, rowBytes, flags);
1674 return;
1675 }
1676#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001677 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1678 GrPixelConfigIsUnpremultiplied(config) &&
1679 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1680 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1681 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1682 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1683 return;
1684 }
1685 // allocate a tmp buffer and sw convert the pixels to premul
1686 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1687 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1688 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1689 src, rowBytes, srcConfig8888,
1690 width, height);
1691 // upload the already premul pixels
1692 this->internalWriteRenderTargetPixels(target,
1693 left, top,
1694 width, height,
1695 target->config(),
1696 tmpPixels, 4 * width, flags);
1697 return;
1698 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001699
1700 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1701 GrPixelConfigSwapRAndB(config);
1702 if (swapRAndB) {
1703 config = GrPixelConfigSwapRAndB(config);
1704 }
1705
robertphillips@google.com75b3c962012-06-07 12:08:45 +00001706 GrTextureDesc desc;
1707 desc.fWidth = width;
1708 desc.fHeight = height;
1709 desc.fConfig = config;
1710
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
robertphillips@google.com75b3c962012-06-07 12:08:45 +00001995 GrTextureDesc desc;
1996 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
1997 desc.fWidth = SkScalarFloorToInt(srcRect.width());
1998 desc.fHeight = SkScalarFloorToInt(srcRect.height());
1999 desc.fConfig = srcTexture->config();
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002000
2001 temp1->set(this, desc);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002002 if (temp2) {
2003 temp2->set(this, desc);
2004 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002005
2006 GrTexture* dstTexture = temp1->texture();
2007 GrPaint paint;
2008 paint.reset();
2009 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2010
2011 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
2012 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2013 srcTexture->height());
2014 this->setRenderTarget(dstTexture->asRenderTarget());
2015 SkRect dstRect(srcRect);
2016 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
2017 i < scaleFactorY ? 0.5f : 1.0f);
2018 paint.setTexture(0, srcTexture);
2019 this->drawRectToRect(paint, dstRect, srcRect);
2020 srcRect = dstRect;
2021 SkTSwap(srcTexture, dstTexture);
2022 // If temp2 is non-NULL, don't render back to origTexture
2023 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
2024 }
2025
robertphillips@google.com7a396332012-05-10 15:11:27 +00002026 SkIRect srcIRect;
2027 srcRect.roundOut(&srcIRect);
2028
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002029 if (sigmaX > 0.0f) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002030 if (scaleFactorX > 1) {
bsalomon@google.comb505a122012-05-31 18:40:36 +00002031 // Clear out a radius to the right of the srcRect to prevent the
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002032 // X convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002033 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002034 radiusX, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002035 this->clear(&clearRect, 0x0);
2036 }
2037
2038 this->setRenderTarget(dstTexture->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002039 convolve_gaussian(fGpu, srcTexture, srcRect, sigmaX, radiusX,
2040 Gr1DKernelEffect::kX_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002041 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002042 if (temp2 && dstTexture == origTexture) {
2043 dstTexture = temp2->texture();
2044 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002045 }
2046
2047 if (sigmaY > 0.0f) {
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002048 if (scaleFactorY > 1 || sigmaX > 0.0f) {
bsalomon@google.comb505a122012-05-31 18:40:36 +00002049 // Clear out a radius below the srcRect to prevent the Y
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002050 // convolution from reading garbage.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002051 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002052 srcIRect.width(), radiusY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002053 this->clear(&clearRect, 0x0);
2054 }
2055
2056 this->setRenderTarget(dstTexture->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002057 convolve_gaussian(fGpu, srcTexture, srcRect, sigmaY, radiusY,
2058 Gr1DKernelEffect::kY_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002059 SkTSwap(srcTexture, dstTexture);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00002060 if (temp2 && dstTexture == origTexture) {
2061 dstTexture = temp2->texture();
2062 }
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002063 }
2064
2065 if (scaleFactorX > 1 || scaleFactorY > 1) {
2066 // Clear one pixel to the right and below, to accommodate bilinear
2067 // upsampling.
robertphillips@google.com7a396332012-05-10 15:11:27 +00002068 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
2069 srcIRect.width() + 1, 1);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002070 this->clear(&clearRect, 0x0);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002071 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
2072 1, srcIRect.height());
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002073 this->clear(&clearRect, 0x0);
2074 // FIXME: This should be mitchell, not bilinear.
2075 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
2076 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
2077 srcTexture->height());
2078 this->setRenderTarget(dstTexture->asRenderTarget());
2079 paint.setTexture(0, srcTexture);
2080 SkRect dstRect(srcRect);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002081 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002082 this->drawRectToRect(paint, dstRect, srcRect);
2083 srcRect = dstRect;
2084 SkTSwap(srcTexture, dstTexture);
2085 }
2086 this->setRenderTarget(oldRenderTarget);
2087 this->setClip(oldClip);
2088 return srcTexture;
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002089}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002090
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002091GrTexture* GrContext::applyMorphology(GrTexture* srcTexture,
2092 const GrRect& rect,
2093 GrTexture* temp1, GrTexture* temp2,
bsalomon@google.comb505a122012-05-31 18:40:36 +00002094 MorphologyType morphType,
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002095 SkISize radius) {
senorblanco@chromium.orgceb44142012-03-05 20:53:36 +00002096 ASSERT_OWNED_RESOURCE(srcTexture);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002097 GrRenderTarget* oldRenderTarget = this->getRenderTarget();
2098 GrAutoMatrix avm(this, GrMatrix::I());
2099 GrClip oldClip = this->getClip();
robertphillips@google.com7a396332012-05-10 15:11:27 +00002100 this->setClip(GrRect::MakeWH(SkIntToScalar(srcTexture->width()),
2101 SkIntToScalar(srcTexture->height())));
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002102 if (radius.fWidth > 0) {
2103 this->setRenderTarget(temp1->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002104 apply_morphology(fGpu, srcTexture, rect, radius.fWidth, morphType,
2105 Gr1DKernelEffect::kX_Direction);
robertphillips@google.com7a396332012-05-10 15:11:27 +00002106 SkIRect clearRect = SkIRect::MakeXYWH(
2107 SkScalarFloorToInt(rect.fLeft),
2108 SkScalarFloorToInt(rect.fBottom),
2109 SkScalarFloorToInt(rect.width()),
2110 radius.fHeight);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002111 this->clear(&clearRect, 0x0);
2112 srcTexture = temp1;
2113 }
2114 if (radius.fHeight > 0) {
2115 this->setRenderTarget(temp2->asRenderTarget());
bsalomon@google.comb505a122012-05-31 18:40:36 +00002116 apply_morphology(fGpu, srcTexture, rect, radius.fHeight, morphType,
2117 Gr1DKernelEffect::kY_Direction);
senorblanco@chromium.org3b4dd902012-03-05 20:41:22 +00002118 srcTexture = temp2;
2119 }
2120 this->setRenderTarget(oldRenderTarget);
2121 this->setClip(oldClip);
2122 return srcTexture;
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002123}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002124
robertphillips@google.com49d9fd52012-05-23 11:44:08 +00002125void GrContext::postClipPush() {
2126 fGpu->postClipPush();
2127}
2128
2129void GrContext::preClipPop() {
2130 fGpu->preClipPop();
2131};
2132
bsalomon@google.comc4364992011-11-07 15:54:49 +00002133///////////////////////////////////////////////////////////////////////////////