blob: 471ae1c59ff1e5e5dc731e1758a17bce7dbb4442 [file] [log] [blame]
tomhudson@google.com93813632011-10-27 20:21:16 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrDrawState_DEFINED
9#define GrDrawState_DEFINED
10
11#include "GrColor.h"
12#include "GrMatrix.h"
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000013#include "GrNoncopyable.h"
bsalomon@google.com2e3d1442012-03-26 20:33:54 +000014#include "GrRefCnt.h"
tomhudson@google.com93813632011-10-27 20:21:16 +000015#include "GrSamplerState.h"
16#include "GrStencil.h"
bsalomon@google.com64aef2b2012-06-11 15:36:13 +000017#include "GrTexture.h"
robertphillips@google.com9ec07532012-06-22 12:01:30 +000018#include "GrRenderTarget.h"
tomhudson@google.com1e8f0162012-07-20 16:25:18 +000019#include "effects/GrSingleTextureEffect.h"
tomhudson@google.com93813632011-10-27 20:21:16 +000020
21#include "SkXfermode.h"
22
tomhudson@google.com93813632011-10-27 20:21:16 +000023
bsalomon@google.com2e3d1442012-03-26 20:33:54 +000024class GrDrawState : public GrRefCnt {
bsalomon@google.com2e3d1442012-03-26 20:33:54 +000025public:
reed@google.comfa35e3d2012-06-26 20:16:17 +000026 SK_DECLARE_INST_COUNT(GrDrawState)
27
tomhudson@google.com93813632011-10-27 20:21:16 +000028 /**
29 * Number of texture stages. Each stage takes as input a color and
30 * 2D texture coordinates. The color input to the first enabled stage is the
31 * per-vertex color or the constant color (setColor/setAlpha) if there are
32 * no per-vertex colors. For subsequent stages the input color is the output
33 * color from the previous enabled stage. The output color of each stage is
34 * the input color modulated with the result of a texture lookup. Texture
35 * lookups are specified by a texture a sampler (setSamplerState). Texture
36 * coordinates for each stage come from the vertices based on a
37 * GrVertexLayout bitfield. The output fragment color is the output color of
38 * the last enabled stage. The presence or absence of texture coordinates
39 * for each stage in the vertex layout indicates whether a stage is enabled
40 * or not.
robertphillips@google.combf5cad42012-05-10 12:40:40 +000041 *
42 * Stages 0 through GrPaint::kTotalStages-1 are reserved for setting up
43 * the draw (i.e., textures and filter masks). Stages GrPaint::kTotalStages
44 * through kNumStages-1 are earmarked for use by GrTextContext and
45 * GrPathRenderer-derived classes.
tomhudson@google.com93813632011-10-27 20:21:16 +000046 */
47 enum {
twiz@google.com58071162012-07-18 21:41:50 +000048 kNumStages = 5,
tomhudson@google.com93813632011-10-27 20:21:16 +000049 kMaxTexCoords = kNumStages
50 };
51
robertphillips@google.com9ec07532012-06-22 12:01:30 +000052 GrDrawState()
53 : fRenderTarget(NULL) {
54
55 for (int i = 0; i < kNumStages; ++i) {
56 fTextures[i] = NULL;
57 }
58
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +000059 this->reset();
60 }
bsalomon@google.com46f7afb2012-01-18 19:51:55 +000061
robertphillips@google.com9ec07532012-06-22 12:01:30 +000062 GrDrawState(const GrDrawState& state)
63 : fRenderTarget(NULL) {
64
65 for (int i = 0; i < kNumStages; ++i) {
66 fTextures[i] = NULL;
67 }
68
bsalomon@google.com46f7afb2012-01-18 19:51:55 +000069 *this = state;
70 }
71
robertphillips@google.com9ec07532012-06-22 12:01:30 +000072 virtual ~GrDrawState() {
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +000073 this->disableStages();
robertphillips@google.com9ec07532012-06-22 12:01:30 +000074 GrSafeSetNull(fRenderTarget);
75 }
76
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +000077 /**
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +000078 * Resets to the default state.
79 * Sampler states *will* be modified: textures or CustomStage objects
80 * will be released.
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +000081 */
82 void reset() {
robertphillips@google.com9ec07532012-06-22 12:01:30 +000083
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +000084 this->disableStages();
robertphillips@google.com9ec07532012-06-22 12:01:30 +000085 GrSafeSetNull(fRenderTarget);
86
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000087 // make sure any pad is zero for memcmp
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +000088 // all GrDrawState members should default to something valid by the
89 // the memset except those initialized individually below. There should
90 // be no padding between the individually initialized members.
bsalomon@google.com2e3d1442012-03-26 20:33:54 +000091 memset(this->podStart(), 0, this->memsetSize());
92
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000093 // pedantic assertion that our ptrs will
94 // be NULL (0 ptr is mem addr 0)
95 GrAssert((intptr_t)(void*)NULL == 0LL);
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +000096 GR_STATIC_ASSERT(0 == kBoth_DrawFace);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000097 GrAssert(fStencilSettings.isDisabled());
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +000098
99 // memset exceptions
100 fColor = 0xffffffff;
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000101 fCoverage = 0xffffffff;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000102 fFirstCoverageStage = kNumStages;
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000103 fColorFilterMode = SkXfermode::kDst_Mode;
bsalomon@google.com47059542012-06-06 20:51:20 +0000104 fSrcBlend = kOne_GrBlendCoeff;
105 fDstBlend = kZero_GrBlendCoeff;
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000106 fViewMatrix.reset();
107
108 // ensure values that will be memcmp'ed in == but not memset in reset()
109 // are tightly packed
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000110 GrAssert(this->memsetSize() + sizeof(fColor) + sizeof(fCoverage) +
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000111 sizeof(fFirstCoverageStage) + sizeof(fColorFilterMode) +
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000112 sizeof(fSrcBlend) + sizeof(fDstBlend) + sizeof(fTextures) +
113 sizeof(fRenderTarget) == this->podSize());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000114 }
115
116 ///////////////////////////////////////////////////////////////////////////
117 /// @name Color
118 ////
119
120 /**
121 * Sets color for next draw to a premultiplied-alpha color.
122 *
123 * @param color the color to set.
124 */
125 void setColor(GrColor color) { fColor = color; }
126
127 GrColor getColor() const { return fColor; }
128
129 /**
130 * Sets the color to be used for the next draw to be
131 * (r,g,b,a) = (alpha, alpha, alpha, alpha).
132 *
133 * @param alpha The alpha value to set as the color.
134 */
135 void setAlpha(uint8_t a) {
136 this->setColor((a << 24) | (a << 16) | (a << 8) | a);
137 }
138
139 /**
140 * Add a color filter that can be represented by a color and a mode. Applied
141 * after color-computing texture stages.
142 */
143 void setColorFilter(GrColor c, SkXfermode::Mode mode) {
144 fColorFilterColor = c;
145 fColorFilterMode = mode;
146 }
147
148 GrColor getColorFilterColor() const { return fColorFilterColor; }
149 SkXfermode::Mode getColorFilterMode() const { return fColorFilterMode; }
150
151 /// @}
152
153 ///////////////////////////////////////////////////////////////////////////
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000154 /// @name Coverage
155 ////
156
157 /**
158 * Sets a constant fractional coverage to be applied to the draw. The
159 * initial value (after construction or reset()) is 0xff. The constant
160 * coverage is ignored when per-vertex coverage is provided.
161 */
162 void setCoverage(uint8_t coverage) {
163 fCoverage = GrColorPackRGBA(coverage, coverage, coverage, coverage);
164 }
165
166 /**
167 * Version of above that specifies 4 channel per-vertex color. The value
168 * should be premultiplied.
169 */
170 void setCoverage4(GrColor coverage) {
171 fCoverage = coverage;
172 }
173
174 GrColor getCoverage() const {
175 return fCoverage;
176 }
177
178 /// @}
179
180 ///////////////////////////////////////////////////////////////////////////
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000181 /// @name Textures
182 ////
183
184 /**
185 * Sets the texture used at the next drawing call
186 *
187 * @param stage The texture stage for which the texture will be set
188 *
189 * @param texture The texture to set. Can be NULL though there is no
190 * advantage to settings a NULL texture if doing non-textured drawing
tomhudson@google.com1e8f0162012-07-20 16:25:18 +0000191 *
192 * @deprecated
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000193 */
194 void setTexture(int stage, GrTexture* texture) {
195 GrAssert((unsigned)stage < kNumStages);
robertphillips@google.com1942c052012-05-03 17:58:27 +0000196
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000197 GrSafeAssign(fTextures[stage], texture);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000198 }
199
200 /**
tomhudson@google.com1e8f0162012-07-20 16:25:18 +0000201 * Creates a GrSingleTextureEffect.
202 *
203 * Replacement for setTexture.
204 */
205 void createTextureEffect(int stage, GrTexture* texture) {
206 GrAssert(!this->getSampler(stage).getCustomStage());
207 this->sampler(stage)->setCustomStage(
208 SkNEW_ARGS(GrSingleTextureEffect, (texture)))->unref();
209 }
210
211 /**
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000212 * Retrieves the currently set texture.
213 *
214 * @return The currently set texture. The return value will be NULL if no
215 * texture has been set, NULL was most recently passed to
216 * setTexture, or the last setTexture was destroyed.
217 */
218 const GrTexture* getTexture(int stage) const {
219 GrAssert((unsigned)stage < kNumStages);
tomhudson@google.come742bf02012-07-13 19:54:19 +0000220 GrAssert(!this->getSampler(stage).getCustomStage() ||
221 !fTextures[stage] ||
222 fTextures[stage] == this->getSampler(stage).getCustomStage()->texture(0));
223 if (this->getSampler(stage).getCustomStage()) {
224 return this->getSampler(stage).getCustomStage()->texture(0);
225 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000226 return fTextures[stage];
227 }
228 GrTexture* getTexture(int stage) {
229 GrAssert((unsigned)stage < kNumStages);
tomhudson@google.come742bf02012-07-13 19:54:19 +0000230 GrAssert(!this->getSampler(stage).getCustomStage() ||
231 !fTextures[stage] ||
232 fTextures[stage] == this->getSampler(stage).getCustomStage()->texture(0));
233 if (this->getSampler(stage).getCustomStage()) {
234 return this->getSampler(stage).getCustomStage()->texture(0);
235 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000236 return fTextures[stage];
237 }
238
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +0000239 bool stagesDisabled() {
240 for (int i = 0; i < kNumStages; ++i) {
241 if (NULL != fTextures[i] ||
242 NULL != fSamplerStates[i].getCustomStage()) {
243 return false;
244 }
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +0000245 }
tomhudson@google.com3eee8fb2012-06-25 12:30:34 +0000246 return true;
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +0000247 }
tomhudson@google.com676e6602012-07-10 17:21:48 +0000248
249 void disableStage(int index) {
250 GrSafeSetNull(fTextures[index]);
251 fSamplerStates[index].setCustomStage(NULL);
252 }
253
robertphillips@google.com972265d2012-06-13 18:49:30 +0000254 /**
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +0000255 * Release all the textures and custom stages referred to by this
256 * draw state.
robertphillips@google.com972265d2012-06-13 18:49:30 +0000257 */
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +0000258 void disableStages() {
robertphillips@google.com972265d2012-06-13 18:49:30 +0000259 for (int i = 0; i < kNumStages; ++i) {
tomhudson@google.com676e6602012-07-10 17:21:48 +0000260 this->disableStage(i);
robertphillips@google.com972265d2012-06-13 18:49:30 +0000261 }
262 }
263
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +0000264 class AutoStageDisable : public ::GrNoncopyable {
robertphillips@google.com972265d2012-06-13 18:49:30 +0000265 public:
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +0000266 AutoStageDisable(GrDrawState* ds) : fDrawState(ds) {}
267 ~AutoStageDisable() {
robertphillips@google.com972265d2012-06-13 18:49:30 +0000268 if (NULL != fDrawState) {
tomhudson@google.com7d6afdd2012-06-22 20:10:50 +0000269 fDrawState->disableStages();
robertphillips@google.com972265d2012-06-13 18:49:30 +0000270 }
271 }
272 private:
273 GrDrawState* fDrawState;
274 };
275
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000276 /// @}
277
278 ///////////////////////////////////////////////////////////////////////////
279 /// @name Samplers
280 ////
281
282 /**
283 * Returns the current sampler for a stage.
284 */
285 const GrSamplerState& getSampler(int stage) const {
286 GrAssert((unsigned)stage < kNumStages);
287 return fSamplerStates[stage];
288 }
289
290 /**
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000291 * Writable pointer to a stage's sampler.
292 */
293 GrSamplerState* sampler(int stage) {
294 GrAssert((unsigned)stage < kNumStages);
295 return fSamplerStates + stage;
296 }
297
298 /**
bsalomon@google.come3d32162012-07-20 13:37:06 +0000299 * Preconcats the matrix of all samplers of enabled stages with a matrix.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000300 */
bsalomon@google.come3d32162012-07-20 13:37:06 +0000301 void preConcatSamplerMatrices(const GrMatrix& matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000302 for (int i = 0; i < kNumStages; ++i) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000303 if (this->isStageEnabled(i)) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000304 fSamplerStates[i].preConcatMatrix(matrix);
305 }
306 }
307 }
308
bsalomon@google.come3d32162012-07-20 13:37:06 +0000309 /**
310 * Preconcats the matrix of all samplers in the mask with the inverse of a
311 * matrix. If the matrix inverse cannot be computed (and there is at least
312 * one enabled stage) then false is returned.
313 */
314 bool preConcatSamplerMatricesWithInverse(const GrMatrix& matrix) {
315 GrMatrix inv;
316 bool computed = false;
317 for (int i = 0; i < kNumStages; ++i) {
318 if (this->isStageEnabled(i)) {
319 if (!computed && !matrix.invert(&inv)) {
320 return false;
321 } else {
322 computed = true;
323 }
324 fSamplerStates[i].preConcatMatrix(inv);
325 }
326 }
327 return true;
328 }
329
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000330 /// @}
331
332 ///////////////////////////////////////////////////////////////////////////
333 /// @name Coverage / Color Stages
334 ////
335
336 /**
337 * A common pattern is to compute a color with the initial stages and then
338 * modulate that color by a coverage value in later stage(s) (AA, mask-
339 * filters, glyph mask, etc). Color-filters, xfermodes, etc should be
340 * computed based on the pre-coverage-modulated color. The division of
341 * stages between color-computing and coverage-computing is specified by
342 * this method. Initially this is kNumStages (all stages
343 * are color-computing).
344 */
345 void setFirstCoverageStage(int firstCoverageStage) {
346 GrAssert((unsigned)firstCoverageStage <= kNumStages);
347 fFirstCoverageStage = firstCoverageStage;
348 }
349
350 /**
351 * Gets the index of the first coverage-computing stage.
352 */
353 int getFirstCoverageStage() const {
354 return fFirstCoverageStage;
355 }
356
357 ///@}
358
359 ///////////////////////////////////////////////////////////////////////////
360 /// @name Blending
361 ////
362
363 /**
364 * Sets the blending function coeffecients.
365 *
366 * The blend function will be:
367 * D' = sat(S*srcCoef + D*dstCoef)
368 *
369 * where D is the existing destination color, S is the incoming source
370 * color, and D' is the new destination color that will be written. sat()
371 * is the saturation function.
372 *
373 * @param srcCoef coeffecient applied to the src color.
374 * @param dstCoef coeffecient applied to the dst color.
375 */
376 void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
377 fSrcBlend = srcCoeff;
378 fDstBlend = dstCoeff;
379 #if GR_DEBUG
380 switch (dstCoeff) {
bsalomon@google.com47059542012-06-06 20:51:20 +0000381 case kDC_GrBlendCoeff:
382 case kIDC_GrBlendCoeff:
383 case kDA_GrBlendCoeff:
384 case kIDA_GrBlendCoeff:
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000385 GrPrintf("Unexpected dst blend coeff. Won't work correctly with"
386 "coverage stages.\n");
387 break;
388 default:
389 break;
390 }
391 switch (srcCoeff) {
bsalomon@google.com47059542012-06-06 20:51:20 +0000392 case kSC_GrBlendCoeff:
393 case kISC_GrBlendCoeff:
394 case kSA_GrBlendCoeff:
395 case kISA_GrBlendCoeff:
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000396 GrPrintf("Unexpected src blend coeff. Won't work correctly with"
397 "coverage stages.\n");
398 break;
399 default:
400 break;
401 }
402 #endif
403 }
404
405 GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlend; }
406 GrBlendCoeff getDstBlendCoeff() const { return fDstBlend; }
407
408 void getDstBlendCoeff(GrBlendCoeff* srcBlendCoeff,
409 GrBlendCoeff* dstBlendCoeff) const {
410 *srcBlendCoeff = fSrcBlend;
411 *dstBlendCoeff = fDstBlend;
412 }
413
414 /**
415 * Sets the blending function constant referenced by the following blending
416 * coeffecients:
bsalomon@google.com47059542012-06-06 20:51:20 +0000417 * kConstC_GrBlendCoeff
418 * kIConstC_GrBlendCoeff
419 * kConstA_GrBlendCoeff
420 * kIConstA_GrBlendCoeff
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000421 *
422 * @param constant the constant to set
423 */
424 void setBlendConstant(GrColor constant) { fBlendConstant = constant; }
425
426 /**
427 * Retrieves the last value set by setBlendConstant()
428 * @return the blending constant value
429 */
430 GrColor getBlendConstant() const { return fBlendConstant; }
431
432 /// @}
433
434 ///////////////////////////////////////////////////////////////////////////
435 /// @name View Matrix
436 ////
437
438 /**
robertphillips@google.coma72eef32012-05-01 17:22:59 +0000439 * Sets the matrix applied to vertex positions.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000440 *
441 * In the post-view-matrix space the rectangle [0,w]x[0,h]
442 * fully covers the render target. (w and h are the width and height of the
443 * the rendertarget.)
444 */
445 void setViewMatrix(const GrMatrix& m) { fViewMatrix = m; }
446
447 /**
448 * Gets a writable pointer to the view matrix.
449 */
450 GrMatrix* viewMatrix() { return &fViewMatrix; }
451
452 /**
453 * Multiplies the current view matrix by a matrix
454 *
455 * After this call V' = V*m where V is the old view matrix,
456 * m is the parameter to this function, and V' is the new view matrix.
457 * (We consider positions to be column vectors so position vector p is
458 * transformed by matrix X as p' = X*p.)
459 *
460 * @param m the matrix used to modify the view matrix.
461 */
462 void preConcatViewMatrix(const GrMatrix& m) { fViewMatrix.preConcat(m); }
463
464 /**
465 * Multiplies the current view matrix by a matrix
466 *
467 * After this call V' = m*V where V is the old view matrix,
468 * m is the parameter to this function, and V' is the new view matrix.
469 * (We consider positions to be column vectors so position vector p is
470 * transformed by matrix X as p' = X*p.)
471 *
472 * @param m the matrix used to modify the view matrix.
473 */
474 void postConcatViewMatrix(const GrMatrix& m) { fViewMatrix.postConcat(m); }
475
476 /**
477 * Retrieves the current view matrix
478 * @return the current view matrix.
479 */
480 const GrMatrix& getViewMatrix() const { return fViewMatrix; }
481
482 /**
483 * Retrieves the inverse of the current view matrix.
484 *
485 * If the current view matrix is invertible, return true, and if matrix
486 * is non-null, copy the inverse into it. If the current view matrix is
487 * non-invertible, return false and ignore the matrix parameter.
488 *
489 * @param matrix if not null, will receive a copy of the current inverse.
490 */
491 bool getViewInverse(GrMatrix* matrix) const {
492 // TODO: determine whether we really need to leave matrix unmodified
493 // at call sites when inversion fails.
494 GrMatrix inverse;
495 if (fViewMatrix.invert(&inverse)) {
496 if (matrix) {
497 *matrix = inverse;
498 }
499 return true;
500 }
501 return false;
502 }
503
504 class AutoViewMatrixRestore : public ::GrNoncopyable {
505 public:
506 AutoViewMatrixRestore() : fDrawState(NULL) {}
507 AutoViewMatrixRestore(GrDrawState* ds, const GrMatrix& newMatrix) {
508 fDrawState = NULL;
509 this->set(ds, newMatrix);
510 }
511 AutoViewMatrixRestore(GrDrawState* ds) {
512 fDrawState = NULL;
513 this->set(ds);
514 }
515 ~AutoViewMatrixRestore() {
516 this->set(NULL, GrMatrix::I());
517 }
518 void set(GrDrawState* ds, const GrMatrix& newMatrix) {
519 if (NULL != fDrawState) {
520 fDrawState->setViewMatrix(fSavedMatrix);
521 }
522 if (NULL != ds) {
523 fSavedMatrix = ds->getViewMatrix();
524 ds->setViewMatrix(newMatrix);
525 }
526 fDrawState = ds;
527 }
528 void set(GrDrawState* ds) {
529 if (NULL != fDrawState) {
530 fDrawState->setViewMatrix(fSavedMatrix);
531 }
532 if (NULL != ds) {
533 fSavedMatrix = ds->getViewMatrix();
534 }
535 fDrawState = ds;
536 }
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000537 bool isSet() const { return NULL != fDrawState; }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000538 private:
539 GrDrawState* fDrawState;
540 GrMatrix fSavedMatrix;
tomhudson@google.com93813632011-10-27 20:21:16 +0000541 };
542
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000543 /// @}
544
545 ///////////////////////////////////////////////////////////////////////////
546 /// @name Render Target
547 ////
548
549 /**
550 * Sets the rendertarget used at the next drawing call
551 *
552 * @param target The render target to set.
553 */
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000554 void setRenderTarget(GrRenderTarget* target) {
555 GrSafeAssign(fRenderTarget, target);
556 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000557
558 /**
559 * Retrieves the currently set rendertarget.
560 *
561 * @return The currently set render target.
562 */
563 const GrRenderTarget* getRenderTarget() const { return fRenderTarget; }
564 GrRenderTarget* getRenderTarget() { return fRenderTarget; }
565
566 class AutoRenderTargetRestore : public ::GrNoncopyable {
567 public:
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000568 AutoRenderTargetRestore() : fDrawState(NULL), fSavedTarget(NULL) {}
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000569 AutoRenderTargetRestore(GrDrawState* ds, GrRenderTarget* newTarget) {
570 fDrawState = NULL;
robertphillips@google.com7460b372012-04-25 16:54:51 +0000571 fSavedTarget = NULL;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000572 this->set(ds, newTarget);
573 }
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000574 ~AutoRenderTargetRestore() { this->restore(); }
575
576 void restore() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000577 if (NULL != fDrawState) {
578 fDrawState->setRenderTarget(fSavedTarget);
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000579 fDrawState = NULL;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000580 }
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000581 GrSafeSetNull(fSavedTarget);
582 }
583
584 void set(GrDrawState* ds, GrRenderTarget* newTarget) {
585 this->restore();
586
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000587 if (NULL != ds) {
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000588 GrAssert(NULL == fSavedTarget);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000589 fSavedTarget = ds->getRenderTarget();
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000590 SkSafeRef(fSavedTarget);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000591 ds->setRenderTarget(newTarget);
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000592 fDrawState = ds;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000593 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000594 }
595 private:
596 GrDrawState* fDrawState;
597 GrRenderTarget* fSavedTarget;
598 };
599
600 /// @}
601
602 ///////////////////////////////////////////////////////////////////////////
603 /// @name Stencil
604 ////
605
606 /**
607 * Sets the stencil settings to use for the next draw.
608 * Changing the clip has the side-effect of possibly zeroing
609 * out the client settable stencil bits. So multipass algorithms
610 * using stencil should not change the clip between passes.
611 * @param settings the stencil settings to use.
612 */
613 void setStencil(const GrStencilSettings& settings) {
614 fStencilSettings = settings;
615 }
616
617 /**
618 * Shortcut to disable stencil testing and ops.
619 */
620 void disableStencil() {
621 fStencilSettings.setDisabled();
622 }
623
624 const GrStencilSettings& getStencil() const { return fStencilSettings; }
625
626 GrStencilSettings* stencil() { return &fStencilSettings; }
627
628 /// @}
629
630 ///////////////////////////////////////////////////////////////////////////
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +0000631 /// @name Color Matrix
632 ////
633
634 /**
635 * Sets the color matrix to use for the next draw.
636 * @param matrix the 5x4 matrix to apply to the incoming color
637 */
638 void setColorMatrix(const float matrix[20]) {
639 memcpy(fColorMatrix, matrix, sizeof(fColorMatrix));
640 }
641
642 const float* getColorMatrix() const { return fColorMatrix; }
643
644 /// @}
645
646 ///////////////////////////////////////////////////////////////////////////
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000647 // @name Edge AA
bsalomon@google.com7ffe6812012-05-11 17:32:43 +0000648 // Edge equations can be specified to perform antialiasing. Because the
649 // edges are specified as per-vertex data, vertices that are shared by
650 // multiple edges must be split.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000651 //
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000652 ////
653
654 /**
tomhudson@google.com93813632011-10-27 20:21:16 +0000655 * When specifying edges as vertex data this enum specifies what type of
656 * edges are in use. The edges are always 4 GrScalars in memory, even when
657 * the edge type requires fewer than 4.
bsalomon@google.com93c96602012-04-27 13:05:21 +0000658 *
659 * TODO: Fix the fact that HairLine and Circle edge types use y-down coords.
660 * (either adjust in VS or use origin_upper_left in GLSL)
tomhudson@google.com93813632011-10-27 20:21:16 +0000661 */
662 enum VertexEdgeType {
663 /* 1-pixel wide line
664 2D implicit line eq (a*x + b*y +c = 0). 4th component unused */
665 kHairLine_EdgeType,
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000666 /* Quadratic specified by u^2-v canonical coords (only 2
667 components used). Coverage based on signed distance with negative
bsalomon@google.com93c96602012-04-27 13:05:21 +0000668 being inside, positive outside. Edge specified in window space
669 (y-down) */
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000670 kQuad_EdgeType,
671 /* Same as above but for hairline quadratics. Uses unsigned distance.
672 Coverage is min(0, 1-distance). */
673 kHairQuad_EdgeType,
bsalomon@google.com93c96602012-04-27 13:05:21 +0000674 /* Circle specified as center_x, center_y, outer_radius, inner_radius
675 all in window space (y-down). */
676 kCircle_EdgeType,
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000677
678 kVertexEdgeTypeCnt
tomhudson@google.com93813632011-10-27 20:21:16 +0000679 };
680
681 /**
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000682 * Determines the interpretation per-vertex edge data when the
683 * kEdge_VertexLayoutBit is set (see GrDrawTarget). When per-vertex edges
684 * are not specified the value of this setting has no effect.
685 */
686 void setVertexEdgeType(VertexEdgeType type) {
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000687 GrAssert(type >=0 && type < kVertexEdgeTypeCnt);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000688 fVertexEdgeType = type;
689 }
690
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000691 VertexEdgeType getVertexEdgeType() const { return fVertexEdgeType; }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000692
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000693 /// @}
tomhudson@google.com62b09682011-11-09 16:39:17 +0000694
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000695 ///////////////////////////////////////////////////////////////////////////
696 /// @name State Flags
697 ////
tomhudson@google.com62b09682011-11-09 16:39:17 +0000698
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000699 /**
700 * Flags that affect rendering. Controlled using enable/disableState(). All
701 * default to disabled.
702 */
703 enum StateBits {
704 /**
705 * Perform dithering. TODO: Re-evaluate whether we need this bit
706 */
707 kDither_StateBit = 0x01,
708 /**
709 * Perform HW anti-aliasing. This means either HW FSAA, if supported
710 * by the render target, or smooth-line rendering if a line primitive
711 * is drawn and line smoothing is supported by the 3D API.
712 */
713 kHWAntialias_StateBit = 0x02,
714 /**
715 * Draws will respect the clip, otherwise the clip is ignored.
716 */
717 kClip_StateBit = 0x04,
718 /**
719 * Disables writing to the color buffer. Useful when performing stencil
720 * operations.
721 */
722 kNoColorWrites_StateBit = 0x08,
723 /**
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +0000724 * Draws will apply the color matrix, otherwise the color matrix is
725 * ignored.
726 */
727 kColorMatrix_StateBit = 0x20,
tomhudson@google.com62b09682011-11-09 16:39:17 +0000728
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000729 // Users of the class may add additional bits to the vector
730 kDummyStateBit,
731 kLastPublicStateBit = kDummyStateBit-1,
732 };
733
734 void resetStateFlags() {
735 fFlagBits = 0;
736 }
737
738 /**
739 * Enable render state settings.
740 *
741 * @param flags bitfield of StateBits specifing the states to enable
742 */
743 void enableState(uint32_t stateBits) {
744 fFlagBits |= stateBits;
745 }
746
747 /**
748 * Disable render state settings.
749 *
750 * @param flags bitfield of StateBits specifing the states to disable
751 */
752 void disableState(uint32_t stateBits) {
753 fFlagBits &= ~(stateBits);
754 }
755
756 bool isDitherState() const {
757 return 0 != (fFlagBits & kDither_StateBit);
758 }
759
760 bool isHWAntialiasState() const {
761 return 0 != (fFlagBits & kHWAntialias_StateBit);
762 }
763
764 bool isClipState() const {
765 return 0 != (fFlagBits & kClip_StateBit);
766 }
767
768 bool isColorWriteDisabled() const {
769 return 0 != (fFlagBits & kNoColorWrites_StateBit);
770 }
771
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000772 bool isStateFlagEnabled(uint32_t stateBit) const {
773 return 0 != (stateBit & fFlagBits);
774 }
775
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000776 /// @}
777
778 ///////////////////////////////////////////////////////////////////////////
779 /// @name Face Culling
780 ////
781
782 enum DrawFace {
bsalomon@google.com978c8c62012-05-21 14:45:49 +0000783 kInvalid_DrawFace = -1,
784
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000785 kBoth_DrawFace,
786 kCCW_DrawFace,
787 kCW_DrawFace,
788 };
789
790 /**
791 * Controls whether clockwise, counterclockwise, or both faces are drawn.
792 * @param face the face(s) to draw.
793 */
794 void setDrawFace(DrawFace face) {
bsalomon@google.com978c8c62012-05-21 14:45:49 +0000795 GrAssert(kInvalid_DrawFace != face);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000796 fDrawFace = face;
797 }
798
799 /**
800 * Gets whether the target is drawing clockwise, counterclockwise,
801 * or both faces.
802 * @return the current draw face(s).
803 */
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000804 DrawFace getDrawFace() const { return fDrawFace; }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000805
806 /// @}
807
808 ///////////////////////////////////////////////////////////////////////////
tomhudson@google.com62b09682011-11-09 16:39:17 +0000809
tomhudson@google.comf13f5882012-06-25 17:27:28 +0000810 bool isStageEnabled(int s) const {
811 GrAssert((unsigned)s < kNumStages);
812 return (NULL != fTextures[s]) ||
813 (NULL != fSamplerStates[s].getCustomStage());
814 }
815
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000816 // Most stages are usually not used, so conditionals here
817 // reduce the expected number of bytes touched by 50%.
818 bool operator ==(const GrDrawState& s) const {
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000819 if (memcmp(this->podStart(), s.podStart(), this->podSize())) {
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000820 return false;
821 }
822
823 if (!s.fViewMatrix.cheapEqualTo(fViewMatrix)) {
824 return false;
825 }
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000826
827 for (int i = 0; i < kNumStages; i++) {
bsalomon@google.comf2f8fc32012-07-18 18:25:07 +0000828 bool enabled = this->isStageEnabled(i);
829 if (enabled != s.isStageEnabled(i)) {
830 return false;
831 }
832 if (enabled && this->fSamplerStates[i] != s.fSamplerStates[i]) {
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000833 return false;
834 }
835 }
bsalomon@google.com9b1517e2012-03-05 17:58:34 +0000836 if (kColorMatrix_StateBit & s.fFlagBits) {
837 if (memcmp(fColorMatrix,
838 s.fColorMatrix,
839 sizeof(fColorMatrix))) {
840 return false;
841 }
842 }
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000843
844 return true;
845 }
846 bool operator !=(const GrDrawState& s) const { return !(*this == s); }
847
848 // Most stages are usually not used, so conditionals here
849 // reduce the expected number of bytes touched by 50%.
850 GrDrawState& operator =(const GrDrawState& s) {
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000851 memcpy(this->podStart(), s.podStart(), this->podSize());
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000852
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000853 fViewMatrix = s.fViewMatrix;
854
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000855 for (int i = 0; i < kNumStages; i++) {
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000856 SkSafeRef(fTextures[i]); // already copied by memcpy
tomhudson@google.come742bf02012-07-13 19:54:19 +0000857 if (s.isStageEnabled(i)) {
tomhudson@google.com02b1ea22012-04-30 20:19:07 +0000858 this->fSamplerStates[i] = s.fSamplerStates[i];
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000859 }
860 }
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000861
862 SkSafeRef(fRenderTarget); // already copied by memcpy
863
bsalomon@google.com9b1517e2012-03-05 17:58:34 +0000864 if (kColorMatrix_StateBit & s.fFlagBits) {
865 memcpy(this->fColorMatrix, s.fColorMatrix, sizeof(fColorMatrix));
866 }
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000867
868 return *this;
869 }
870
871private:
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000872
873 const void* podStart() const {
874 return reinterpret_cast<const void*>(&fPodStartMarker);
875 }
876 void* podStart() {
877 return reinterpret_cast<void*>(&fPodStartMarker);
878 }
879 size_t memsetSize() const {
880 return reinterpret_cast<size_t>(&fMemsetEndMarker) -
881 reinterpret_cast<size_t>(&fPodStartMarker) +
882 sizeof(fMemsetEndMarker);
883 }
884 size_t podSize() const {
885 // Can't use offsetof() with non-POD types, so stuck with pointer math.
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000886 return reinterpret_cast<size_t>(&fPodEndMarker) -
887 reinterpret_cast<size_t>(&fPodStartMarker) +
888 sizeof(fPodEndMarker);
889 }
890
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000891 // @{ these fields can be initialized with memset to 0
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000892 union {
893 GrColor fBlendConstant;
894 GrColor fPodStartMarker;
895 };
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000896 GrColor fColorFilterColor;
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000897 DrawFace fDrawFace;
robertphillips@google.comc077d1e2012-05-28 14:10:15 +0000898 VertexEdgeType fVertexEdgeType;
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000899 GrStencilSettings fStencilSettings;
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000900 union {
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000901 uint32_t fFlagBits;
902 uint32_t fMemsetEndMarker;
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000903 };
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000904 // @}
905
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000906 // @{ Initialized to values other than zero, but memcmp'ed in operator==
907 // and memcpy'ed in operator=.
robertphillips@google.com9ec07532012-06-22 12:01:30 +0000908 GrTexture* fTextures[kNumStages];
909 GrRenderTarget* fRenderTarget;
910
robertphillips@google.com69ffcf02012-06-26 21:01:05 +0000911 int fFirstCoverageStage;
912
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000913 GrColor fColor;
bsalomon@google.com2401ae82012-01-17 21:03:05 +0000914 GrColor fCoverage;
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000915 SkXfermode::Mode fColorFilterMode;
916 GrBlendCoeff fSrcBlend;
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000917 union {
robertphillips@google.comc077d1e2012-05-28 14:10:15 +0000918 GrBlendCoeff fDstBlend;
919 GrBlendCoeff fPodEndMarker;
bsalomon@google.com2e3d1442012-03-26 20:33:54 +0000920 };
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000921 // @}
922
bsalomon@google.com8fe84b52012-03-26 15:24:27 +0000923 GrMatrix fViewMatrix;
924
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000925 // This field must be last; it will not be copied or compared
926 // if the corresponding fTexture[] is NULL.
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000927 GrSamplerState fSamplerStates[kNumStages];
bsalomon@google.com9b1517e2012-03-05 17:58:34 +0000928 // only compared if the color matrix enable flag is set
929 float fColorMatrix[20]; // 5 x 4 matrix
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000930
reed@google.comfa35e3d2012-06-26 20:16:17 +0000931 typedef GrRefCnt INHERITED;
tomhudson@google.com93813632011-10-27 20:21:16 +0000932};
933
934#endif