blob: aa5cf201d2576b228ec9da2b28575a07af9919df [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.comac10a2d2010-12-22 21:39:39 +000011#include "GrDrawTarget.h"
12#include "GrGpuVertex.h"
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +000013#include "GrIndexBuffer.h"
14#include "GrRenderTarget.h"
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000015#include "GrTexture.h"
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000016#include "GrVertexBuffer.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000017
junov@google.com6acc9b32011-05-16 18:32:07 +000018namespace {
19
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000020// recursive helper for creating mask with all the tex coord bits set for
21// one stage
22template <int N>
reed@google.com34cec242011-04-19 15:53:12 +000023int stage_mask_recur(int stage) {
bsalomon@google.com5782d712011-01-21 21:03:59 +000024 return GrDrawTarget::StageTexCoordVertexLayoutBit(stage, N) |
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000025 stage_mask_recur<N+1>(stage);
26}
junov@google.com6acc9b32011-05-16 18:32:07 +000027template<>
tomhudson@google.com93813632011-10-27 20:21:16 +000028int stage_mask_recur<GrDrawState::kNumStages>(int) { return 0; }
reed@google.comac10a2d2010-12-22 21:39:39 +000029
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000030// mask of all tex coord indices for one stage
junov@google.com6acc9b32011-05-16 18:32:07 +000031int stage_tex_coord_mask(int stage) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000032 return stage_mask_recur<0>(stage);
reed@google.comac10a2d2010-12-22 21:39:39 +000033}
34
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000035// mask of all bits relevant to one stage
junov@google.com6acc9b32011-05-16 18:32:07 +000036int stage_mask(int stage) {
bsalomon@google.com5782d712011-01-21 21:03:59 +000037 return stage_tex_coord_mask(stage) |
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000038 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(stage);
39}
40
41// recursive helper for creating mask of with all bits set relevant to one
42// texture coordinate index
43template <int N>
reed@google.com34cec242011-04-19 15:53:12 +000044int tex_coord_mask_recur(int texCoordIdx) {
bsalomon@google.com5782d712011-01-21 21:03:59 +000045 return GrDrawTarget::StageTexCoordVertexLayoutBit(N, texCoordIdx) |
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000046 tex_coord_mask_recur<N+1>(texCoordIdx);
47}
junov@google.com6acc9b32011-05-16 18:32:07 +000048template<>
tomhudson@google.com93813632011-10-27 20:21:16 +000049int tex_coord_mask_recur<GrDrawState::kMaxTexCoords>(int) { return 0; }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000050
51// mask of all bits relevant to one texture coordinate index
junov@google.com6acc9b32011-05-16 18:32:07 +000052int tex_coord_idx_mask(int texCoordIdx) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000053 return tex_coord_mask_recur<0>(texCoordIdx);
54}
55
56bool check_layout(GrVertexLayout layout) {
57 // can only have 1 or 0 bits set for each stage.
tomhudson@google.com93813632011-10-27 20:21:16 +000058 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000059 int stageBits = layout & stage_mask(s);
60 if (stageBits && !GrIsPow2(stageBits)) {
61 return false;
62 }
63 }
64 return true;
65}
66
bsalomon@google.comaeb21602011-08-30 18:13:44 +000067int num_tex_coords(GrVertexLayout layout) {
68 int cnt = 0;
69 // figure out how many tex coordinates are present
tomhudson@google.com93813632011-10-27 20:21:16 +000070 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
bsalomon@google.comaeb21602011-08-30 18:13:44 +000071 if (tex_coord_idx_mask(t) & layout) {
72 ++cnt;
73 }
74 }
75 return cnt;
76}
77
junov@google.com6acc9b32011-05-16 18:32:07 +000078} //unnamed namespace
79
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000080size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
81 GrAssert(check_layout(vertexLayout));
bsalomon@google.com5782d712011-01-21 21:03:59 +000082
83 size_t vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000084 sizeof(GrGpuTextVertex) :
85 sizeof(GrPoint);
86
87 size_t size = vecSize; // position
bsalomon@google.comaeb21602011-08-30 18:13:44 +000088 size += num_tex_coords(vertexLayout) * vecSize;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000089 if (vertexLayout & kColor_VertexLayoutBit) {
90 size += sizeof(GrColor);
91 }
bsalomon@google.coma3108262011-10-10 14:08:47 +000092 if (vertexLayout & kCoverage_VertexLayoutBit) {
93 size += sizeof(GrColor);
94 }
bsalomon@google.comaeb21602011-08-30 18:13:44 +000095 if (vertexLayout & kEdge_VertexLayoutBit) {
96 size += 4 * sizeof(GrScalar);
97 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000098 return size;
99}
100
bsalomon@google.coma3108262011-10-10 14:08:47 +0000101////////////////////////////////////////////////////////////////////////////////
102
103/**
104 * Functions for computing offsets of various components from the layout
105 * bitfield.
106 *
107 * Order of vertex components:
108 * Position
109 * Tex Coord 0
110 * ...
tomhudson@google.com93813632011-10-27 20:21:16 +0000111 * Tex Coord GrDrawState::kMaxTexCoords-1
bsalomon@google.coma3108262011-10-10 14:08:47 +0000112 * Color
113 * Coverage
114 */
115
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000116int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout) {
117 GrAssert(check_layout(vertexLayout));
118 if (StagePosAsTexCoordVertexLayoutBit(stage) & vertexLayout) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000119 return 0;
120 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000121 int tcIdx = VertexTexCoordsForStage(stage, vertexLayout);
122 if (tcIdx >= 0) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000123
124 int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000125 sizeof(GrGpuTextVertex) :
126 sizeof(GrPoint);
127 int offset = vecSize; // position
128 // figure out how many tex coordinates are present and precede this one.
129 for (int t = 0; t < tcIdx; ++t) {
130 if (tex_coord_idx_mask(t) & vertexLayout) {
131 offset += vecSize;
132 }
133 }
134 return offset;
135 }
136
reed@google.comac10a2d2010-12-22 21:39:39 +0000137 return -1;
138}
139
140int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000141 GrAssert(check_layout(vertexLayout));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000142
reed@google.comac10a2d2010-12-22 21:39:39 +0000143 if (vertexLayout & kColor_VertexLayoutBit) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000144 int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000145 sizeof(GrGpuTextVertex) :
146 sizeof(GrPoint);
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000147 return vecSize * (num_tex_coords(vertexLayout) + 1); //+1 for pos
148 }
149 return -1;
150}
151
bsalomon@google.coma3108262011-10-10 14:08:47 +0000152int GrDrawTarget::VertexCoverageOffset(GrVertexLayout vertexLayout) {
153 GrAssert(check_layout(vertexLayout));
154
155 if (vertexLayout & kCoverage_VertexLayoutBit) {
156 int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
157 sizeof(GrGpuTextVertex) :
158 sizeof(GrPoint);
159
160 int offset = vecSize * (num_tex_coords(vertexLayout) + 1);
161 if (vertexLayout & kColor_VertexLayoutBit) {
162 offset += sizeof(GrColor);
163 }
164 return offset;
165 }
166 return -1;
167}
168
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000169int GrDrawTarget::VertexEdgeOffset(GrVertexLayout vertexLayout) {
170 GrAssert(check_layout(vertexLayout));
171
172 // edge pts are after the pos, tex coords, and color
173 if (vertexLayout & kEdge_VertexLayoutBit) {
174 int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
175 sizeof(GrGpuTextVertex) :
176 sizeof(GrPoint);
177 int offset = vecSize * (num_tex_coords(vertexLayout) + 1); //+1 for pos
178 if (vertexLayout & kColor_VertexLayoutBit) {
179 offset += sizeof(GrColor);
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000181 if (vertexLayout & kCoverage_VertexLayoutBit) {
182 offset += sizeof(GrColor);
183 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000184 return offset;
reed@google.comac10a2d2010-12-22 21:39:39 +0000185 }
186 return -1;
187}
188
tomhudson@google.com93813632011-10-27 20:21:16 +0000189int GrDrawTarget::VertexSizeAndOffsetsByIdx(
190 GrVertexLayout vertexLayout,
191 int texCoordOffsetsByIdx[GrDrawState::kMaxTexCoords],
192 int* colorOffset,
193 int* coverageOffset,
194 int* edgeOffset) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000195 GrAssert(check_layout(vertexLayout));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000196
bsalomon@google.com5782d712011-01-21 21:03:59 +0000197 int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000198 sizeof(GrGpuTextVertex) :
199 sizeof(GrPoint);
200 int size = vecSize; // position
bsalomon@google.com5782d712011-01-21 21:03:59 +0000201
tomhudson@google.com93813632011-10-27 20:21:16 +0000202 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000203 if (tex_coord_idx_mask(t) & vertexLayout) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000204 if (NULL != texCoordOffsetsByIdx) {
205 texCoordOffsetsByIdx[t] = size;
206 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000207 size += vecSize;
reed@google.comac10a2d2010-12-22 21:39:39 +0000208 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000209 if (NULL != texCoordOffsetsByIdx) {
210 texCoordOffsetsByIdx[t] = -1;
211 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000212 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000213 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000214 if (kColor_VertexLayoutBit & vertexLayout) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000215 if (NULL != colorOffset) {
216 *colorOffset = size;
217 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000218 size += sizeof(GrColor);
219 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000220 if (NULL != colorOffset) {
221 *colorOffset = -1;
222 }
223 }
224 if (kCoverage_VertexLayoutBit & vertexLayout) {
225 if (NULL != coverageOffset) {
226 *coverageOffset = size;
227 }
228 size += sizeof(GrColor);
229 } else {
230 if (NULL != coverageOffset) {
231 *coverageOffset = -1;
232 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000233 }
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000234 if (kEdge_VertexLayoutBit & vertexLayout) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000235 if (NULL != edgeOffset) {
236 *edgeOffset = size;
237 }
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000238 size += 4 * sizeof(GrScalar);
239 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000240 if (NULL != edgeOffset) {
241 *edgeOffset = -1;
242 }
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000243 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000244 return size;
reed@google.comac10a2d2010-12-22 21:39:39 +0000245}
246
tomhudson@google.com93813632011-10-27 20:21:16 +0000247int GrDrawTarget::VertexSizeAndOffsetsByStage(
248 GrVertexLayout vertexLayout,
249 int texCoordOffsetsByStage[GrDrawState::kNumStages],
250 int* colorOffset,
251 int* coverageOffset,
252 int* edgeOffset) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000253 GrAssert(check_layout(vertexLayout));
254
tomhudson@google.com93813632011-10-27 20:21:16 +0000255 int texCoordOffsetsByIdx[GrDrawState::kMaxTexCoords];
bsalomon@google.com5782d712011-01-21 21:03:59 +0000256 int size = VertexSizeAndOffsetsByIdx(vertexLayout,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000257 (NULL == texCoordOffsetsByStage) ?
258 NULL :
259 texCoordOffsetsByIdx,
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000260 colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000261 coverageOffset,
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000262 edgeOffset);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000263 if (NULL != texCoordOffsetsByStage) {
tomhudson@google.com93813632011-10-27 20:21:16 +0000264 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000265 int tcIdx;
266 if (StagePosAsTexCoordVertexLayoutBit(s) & vertexLayout) {
267 texCoordOffsetsByStage[s] = 0;
268 } else if ((tcIdx = VertexTexCoordsForStage(s, vertexLayout)) >= 0) {
269 texCoordOffsetsByStage[s] = texCoordOffsetsByIdx[tcIdx];
270 } else {
271 texCoordOffsetsByStage[s] = -1;
272 }
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000273 }
274 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000275 return size;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000276}
277
bsalomon@google.coma3108262011-10-10 14:08:47 +0000278////////////////////////////////////////////////////////////////////////////////
279
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000280bool GrDrawTarget::VertexUsesStage(int stage, GrVertexLayout vertexLayout) {
tomhudson@google.com93813632011-10-27 20:21:16 +0000281 GrAssert(stage < GrDrawState::kNumStages);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000282 GrAssert(check_layout(vertexLayout));
283 return !!(stage_mask(stage) & vertexLayout);
284}
285
bsalomon@google.com5782d712011-01-21 21:03:59 +0000286bool GrDrawTarget::VertexUsesTexCoordIdx(int coordIndex,
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000287 GrVertexLayout vertexLayout) {
tomhudson@google.com93813632011-10-27 20:21:16 +0000288 GrAssert(coordIndex < GrDrawState::kMaxTexCoords);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000289 GrAssert(check_layout(vertexLayout));
290 return !!(tex_coord_idx_mask(coordIndex) & vertexLayout);
291}
292
tomhudson@google.com93813632011-10-27 20:21:16 +0000293int GrDrawTarget::VertexTexCoordsForStage(int stage,
294 GrVertexLayout vertexLayout) {
295 GrAssert(stage < GrDrawState::kNumStages);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000296 GrAssert(check_layout(vertexLayout));
297 int bit = vertexLayout & stage_tex_coord_mask(stage);
298 if (bit) {
299 // figure out which set of texture coordates is used
300 // bits are ordered T0S0, T0S1, T0S2, ..., T1S0, T1S1, ...
301 // and start at bit 0.
302 GR_STATIC_ASSERT(sizeof(GrVertexLayout) <= sizeof(uint32_t));
tomhudson@google.com93813632011-10-27 20:21:16 +0000303 return (32 - Gr_clz(bit) - 1) / GrDrawState::kNumStages;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000304 }
305 return -1;
306}
307
bsalomon@google.coma3108262011-10-10 14:08:47 +0000308////////////////////////////////////////////////////////////////////////////////
309
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000310void GrDrawTarget::VertexLayoutUnitTest() {
311 // not necessarily exhaustive
312 static bool run;
313 if (!run) {
314 run = true;
tomhudson@google.com93813632011-10-27 20:21:16 +0000315 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000316
317 GrAssert(!VertexUsesStage(s, 0));
318 GrAssert(-1 == VertexStageCoordOffset(s, 0));
319 GrVertexLayout stageMask = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000320 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000321 stageMask |= StageTexCoordVertexLayoutBit(s,t);
322 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000323 GrAssert(1 == GrDrawState::kMaxTexCoords ||
324 !check_layout(stageMask));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000325 GrAssert(stage_tex_coord_mask(s) == stageMask);
326 stageMask |= StagePosAsTexCoordVertexLayoutBit(s);
327 GrAssert(stage_mask(s) == stageMask);
328 GrAssert(!check_layout(stageMask));
329 }
tomhudson@google.com93813632011-10-27 20:21:16 +0000330 for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000331 GrVertexLayout tcMask = 0;
332 GrAssert(!VertexUsesTexCoordIdx(t, 0));
tomhudson@google.com93813632011-10-27 20:21:16 +0000333 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000334 tcMask |= StageTexCoordVertexLayoutBit(s,t);
335 GrAssert(VertexUsesStage(s, tcMask));
336 GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
337 GrAssert(VertexUsesTexCoordIdx(t, tcMask));
338 GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask));
339 GrAssert(t == VertexTexCoordsForStage(s, tcMask));
tomhudson@google.com93813632011-10-27 20:21:16 +0000340 for (int s2 = s + 1; s2 < GrDrawState::kNumStages; ++s2) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000341 GrAssert(-1 == VertexStageCoordOffset(s2, tcMask));
342 GrAssert(!VertexUsesStage(s2, tcMask));
343 GrAssert(-1 == VertexTexCoordsForStage(s2, tcMask));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000344
bsalomon@google.com19628322011-02-03 21:30:17 +0000345 #if GR_DEBUG
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000346 GrVertexLayout posAsTex = tcMask | StagePosAsTexCoordVertexLayoutBit(s2);
bsalomon@google.com19628322011-02-03 21:30:17 +0000347 #endif
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000348 GrAssert(0 == VertexStageCoordOffset(s2, posAsTex));
349 GrAssert(VertexUsesStage(s2, posAsTex));
350 GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex));
351 GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex));
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000352 GrAssert(-1 == VertexEdgeOffset(posAsTex));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000353 }
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000354 GrAssert(-1 == VertexEdgeOffset(tcMask));
355 GrAssert(-1 == VertexColorOffset(tcMask));
bsalomon@google.coma3108262011-10-10 14:08:47 +0000356 GrAssert(-1 == VertexCoverageOffset(tcMask));
bsalomon@google.com19628322011-02-03 21:30:17 +0000357 #if GR_DEBUG
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000358 GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
bsalomon@google.com19628322011-02-03 21:30:17 +0000359 #endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000360 GrAssert(-1 == VertexCoverageOffset(withColor));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000361 GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
362 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000363 #if GR_DEBUG
364 GrVertexLayout withEdge = tcMask | kEdge_VertexLayoutBit;
365 #endif
366 GrAssert(-1 == VertexColorOffset(withEdge));
367 GrAssert(2*sizeof(GrPoint) == VertexEdgeOffset(withEdge));
368 GrAssert(4*sizeof(GrPoint) == VertexSize(withEdge));
369 #if GR_DEBUG
370 GrVertexLayout withColorAndEdge = withColor | kEdge_VertexLayoutBit;
371 #endif
372 GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge));
373 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge));
374 GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge));
bsalomon@google.coma3108262011-10-10 14:08:47 +0000375 #if GR_DEBUG
376 GrVertexLayout withCoverage = tcMask | kCoverage_VertexLayoutBit;
377 #endif
378 GrAssert(-1 == VertexColorOffset(withCoverage));
379 GrAssert(2*sizeof(GrPoint) == VertexCoverageOffset(withCoverage));
380 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withCoverage));
381 #if GR_DEBUG
382 GrVertexLayout withCoverageAndColor = tcMask | kCoverage_VertexLayoutBit |
383 kColor_VertexLayoutBit;
384 #endif
385 GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withCoverageAndColor));
386 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor));
387 GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor));
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000388 }
389 GrAssert(tex_coord_idx_mask(t) == tcMask);
390 GrAssert(check_layout(tcMask));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000391
tomhudson@google.com93813632011-10-27 20:21:16 +0000392 int stageOffsets[GrDrawState::kNumStages];
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000393 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000394 int edgeOffset;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000395 int coverageOffset;
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000396 int size;
tomhudson@google.com93813632011-10-27 20:21:16 +0000397 size = VertexSizeAndOffsetsByStage(tcMask,
398 stageOffsets, &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000399 &coverageOffset, &edgeOffset);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000400 GrAssert(2*sizeof(GrPoint) == size);
401 GrAssert(-1 == colorOffset);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000402 GrAssert(-1 == coverageOffset);
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000403 GrAssert(-1 == edgeOffset);
tomhudson@google.com93813632011-10-27 20:21:16 +0000404 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000405 GrAssert(VertexUsesStage(s, tcMask));
406 GrAssert(sizeof(GrPoint) == stageOffsets[s]);
407 GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
408 }
409 }
410 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000411}
412
413////////////////////////////////////////////////////////////////////////////////
414
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000415#define DEBUG_INVAL_BUFFER 0xdeadcafe
416#define DEBUG_INVAL_START_IDX -1
417
bsalomon@google.com92669012011-09-27 19:10:05 +0000418GrDrawTarget::GrDrawTarget() {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000419#if GR_DEBUG
420 VertexLayoutUnitTest();
421#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000422 GeometrySrcState& geoSrc = fGeoSrcStateStack.push_back();
reed@google.comac10a2d2010-12-22 21:39:39 +0000423#if GR_DEBUG
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000424 geoSrc.fVertexCount = DEBUG_INVAL_START_IDX;
425 geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
426 geoSrc.fIndexCount = DEBUG_INVAL_START_IDX;
427 geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
reed@google.comac10a2d2010-12-22 21:39:39 +0000428#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000429 geoSrc.fVertexSrc = kNone_GeometrySrcType;
430 geoSrc.fIndexSrc = kNone_GeometrySrcType;
431}
432
433GrDrawTarget::~GrDrawTarget() {
bsalomon@google.com4a018bb2011-10-28 19:50:21 +0000434 GrAssert(1 == fGeoSrcStateStack.count());
435 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
436 GrAssert(kNone_GeometrySrcType == geoSrc.fIndexSrc);
437 GrAssert(kNone_GeometrySrcType == geoSrc.fVertexSrc);
438}
439
440void GrDrawTarget::releaseGeometry() {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000441 int popCnt = fGeoSrcStateStack.count() - 1;
442 while (popCnt) {
443 this->popGeometrySource();
444 --popCnt;
445 }
bsalomon@google.com4a018bb2011-10-28 19:50:21 +0000446 this->resetVertexSource();
447 this->resetIndexSource();
reed@google.comac10a2d2010-12-22 21:39:39 +0000448}
449
450void GrDrawTarget::setClip(const GrClip& clip) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000451 clipWillBeSet(clip);
reed@google.comac10a2d2010-12-22 21:39:39 +0000452 fClip = clip;
453}
454
455const GrClip& GrDrawTarget::getClip() const {
456 return fClip;
457}
458
reed@google.comac10a2d2010-12-22 21:39:39 +0000459void GrDrawTarget::saveCurrentDrawState(SavedDrawState* state) const {
460 state->fState = fCurrDrawState;
461}
462
463void GrDrawTarget::restoreDrawState(const SavedDrawState& state) {
464 fCurrDrawState = state.fState;
465}
466
467void GrDrawTarget::copyDrawState(const GrDrawTarget& srcTarget) {
468 fCurrDrawState = srcTarget.fCurrDrawState;
469}
470
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000471bool GrDrawTarget::reserveVertexSpace(GrVertexLayout vertexLayout,
472 int vertexCount,
473 void** vertices) {
474 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
475 bool acquired = false;
476 if (vertexCount > 0) {
477 GrAssert(NULL != vertices);
478 this->releasePreviousVertexSource();
479 geoSrc.fVertexSrc = kNone_GeometrySrcType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000480
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000481 acquired = this->onReserveVertexSpace(vertexLayout,
482 vertexCount,
483 vertices);
reed@google.comac10a2d2010-12-22 21:39:39 +0000484 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000485 if (acquired) {
486 geoSrc.fVertexSrc = kReserved_GeometrySrcType;
487 geoSrc.fVertexCount = vertexCount;
488 geoSrc.fVertexLayout = vertexLayout;
489 } else if (NULL != vertices) {
490 *vertices = NULL;
491 }
492 return acquired;
493}
494
495bool GrDrawTarget::reserveIndexSpace(int indexCount,
496 void** indices) {
497 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
498 bool acquired = false;
499 if (indexCount > 0) {
500 GrAssert(NULL != indices);
501 this->releasePreviousIndexSource();
502 geoSrc.fIndexSrc = kNone_GeometrySrcType;
503
504 acquired = this->onReserveIndexSpace(indexCount, indices);
505 }
506 if (acquired) {
507 geoSrc.fIndexSrc = kReserved_GeometrySrcType;
508 geoSrc.fIndexCount = indexCount;
509 } else if (NULL != indices) {
510 *indices = NULL;
511 }
512 return acquired;
513
reed@google.comac10a2d2010-12-22 21:39:39 +0000514}
515
516bool GrDrawTarget::geometryHints(GrVertexLayout vertexLayout,
517 int32_t* vertexCount,
518 int32_t* indexCount) const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000519 if (NULL != vertexCount) {
520 *vertexCount = -1;
521 }
522 if (NULL != indexCount) {
523 *indexCount = -1;
524 }
525 return false;
526}
527
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000528void GrDrawTarget::releasePreviousVertexSource() {
529 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
530 switch (geoSrc.fVertexSrc) {
531 case kNone_GeometrySrcType:
532 break;
533 case kArray_GeometrySrcType:
534 this->releaseVertexArray();
535 break;
536 case kReserved_GeometrySrcType:
537 this->releaseReservedVertexSpace();
538 break;
539 case kBuffer_GeometrySrcType:
540 geoSrc.fVertexBuffer->unref();
541#if GR_DEBUG
542 geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
543#endif
544 break;
545 default:
546 GrCrash("Unknown Vertex Source Type.");
547 break;
548 }
549}
550
551void GrDrawTarget::releasePreviousIndexSource() {
552 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
553 switch (geoSrc.fIndexSrc) {
554 case kNone_GeometrySrcType: // these two don't require
555 break;
556 case kArray_GeometrySrcType:
557 this->releaseIndexArray();
558 break;
559 case kReserved_GeometrySrcType:
560 this->releaseReservedIndexSpace();
561 break;
562 case kBuffer_GeometrySrcType:
563 geoSrc.fIndexBuffer->unref();
564#if GR_DEBUG
565 geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
566#endif
567 break;
568 default:
569 GrCrash("Unknown Index Source Type.");
570 break;
571 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000572}
573
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000574void GrDrawTarget::setVertexSourceToArray(GrVertexLayout vertexLayout,
575 const void* vertexArray,
576 int vertexCount) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000577 this->releasePreviousVertexSource();
578 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
579 geoSrc.fVertexSrc = kArray_GeometrySrcType;
580 geoSrc.fVertexLayout = vertexLayout;
581 geoSrc.fVertexCount = vertexCount;
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000582 this->onSetVertexSourceToArray(vertexArray, vertexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000583}
584
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000585void GrDrawTarget::setIndexSourceToArray(const void* indexArray,
586 int indexCount) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000587 this->releasePreviousIndexSource();
588 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
589 geoSrc.fIndexSrc = kArray_GeometrySrcType;
590 geoSrc.fIndexCount = indexCount;
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000591 this->onSetIndexSourceToArray(indexArray, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000592}
593
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000594void GrDrawTarget::setVertexSourceToBuffer(GrVertexLayout vertexLayout,
595 const GrVertexBuffer* buffer) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000596 this->releasePreviousVertexSource();
597 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
598 geoSrc.fVertexSrc = kBuffer_GeometrySrcType;
599 geoSrc.fVertexBuffer = buffer;
600 buffer->ref();
601 geoSrc.fVertexLayout = vertexLayout;
reed@google.comac10a2d2010-12-22 21:39:39 +0000602}
603
604void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000605 this->releasePreviousIndexSource();
606 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
607 geoSrc.fIndexSrc = kBuffer_GeometrySrcType;
608 geoSrc.fIndexBuffer = buffer;
609 buffer->ref();
reed@google.comac10a2d2010-12-22 21:39:39 +0000610}
611
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000612void GrDrawTarget::resetVertexSource() {
613 this->releasePreviousVertexSource();
614 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
615 geoSrc.fVertexSrc = kNone_GeometrySrcType;
616}
617
618void GrDrawTarget::resetIndexSource() {
619 this->releasePreviousIndexSource();
620 GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
621 geoSrc.fIndexSrc = kNone_GeometrySrcType;
622}
623
624void GrDrawTarget::pushGeometrySource() {
625 this->geometrySourceWillPush();
626 GeometrySrcState& newState = fGeoSrcStateStack.push_back();
627 newState.fIndexSrc = kNone_GeometrySrcType;
628 newState.fVertexSrc = kNone_GeometrySrcType;
629#if GR_DEBUG
630 newState.fVertexCount = ~0;
631 newState.fVertexBuffer = (GrVertexBuffer*)~0;
632 newState.fIndexCount = ~0;
633 newState.fIndexBuffer = (GrIndexBuffer*)~0;
634#endif
635}
636
637void GrDrawTarget::popGeometrySource() {
638 const GeometrySrcState& geoSrc = this->getGeomSrc();
639 // if popping last element then pops are unbalanced with pushes
640 GrAssert(fGeoSrcStateStack.count() > 1);
641
642 this->geometrySourceWillPop(fGeoSrcStateStack.fromBack(1));
643 this->releasePreviousVertexSource();
644 this->releasePreviousIndexSource();
645 fGeoSrcStateStack.pop_back();
646}
647
648////////////////////////////////////////////////////////////////////////////////
649
bsalomon@google.come8262622011-11-07 02:30:51 +0000650bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex,
651 int startIndex, int vertexCount,
652 int indexCount) const {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000653#if GR_DEBUG
bsalomon@google.come8262622011-11-07 02:30:51 +0000654 const GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000655 int maxVertex = startVertex + vertexCount;
656 int maxValidVertex;
657 switch (geoSrc.fVertexSrc) {
658 case kNone_GeometrySrcType:
bsalomon@google.come8262622011-11-07 02:30:51 +0000659 GrCrash("Attempting to draw without vertex src.");
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000660 case kReserved_GeometrySrcType: // fallthrough
661 case kArray_GeometrySrcType:
662 maxValidVertex = geoSrc.fVertexCount;
663 break;
664 case kBuffer_GeometrySrcType:
bsalomon@google.comcee661a2011-07-26 12:32:36 +0000665 maxValidVertex = geoSrc.fVertexBuffer->sizeInBytes() /
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000666 VertexSize(geoSrc.fVertexLayout);
667 break;
668 }
669 if (maxVertex > maxValidVertex) {
bsalomon@google.come8262622011-11-07 02:30:51 +0000670 GrCrash("Drawing outside valid vertex range.");
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000671 }
bsalomon@google.come8262622011-11-07 02:30:51 +0000672 if (indexCount > 0) {
673 int maxIndex = startIndex + indexCount;
674 int maxValidIndex;
675 switch (geoSrc.fIndexSrc) {
676 case kNone_GeometrySrcType:
677 GrCrash("Attempting to draw indexed geom without index src.");
678 case kReserved_GeometrySrcType: // fallthrough
679 case kArray_GeometrySrcType:
680 maxValidIndex = geoSrc.fIndexCount;
681 break;
682 case kBuffer_GeometrySrcType:
683 maxValidIndex = geoSrc.fIndexBuffer->sizeInBytes() / sizeof(uint16_t);
684 break;
685 }
686 if (maxIndex > maxValidIndex) {
687 GrCrash("Index reads outside valid index range.");
688 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000689 }
690#endif
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000691 const GrDrawState& drawState = this->getDrawState();
692 if (NULL == drawState.getRenderTarget()) {
bsalomon@google.com0ba52fc2011-11-10 22:16:06 +0000693 return false;
694 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000695 if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) {
696 if (kOne_BlendCoeff != drawState.getSrcBlendCoeff() ||
697 kZero_BlendCoeff != drawState.getDstBlendCoeff()) {
bsalomon@google.com0ba52fc2011-11-10 22:16:06 +0000698 return false;
699 }
700 }
bsalomon@google.comc4364992011-11-07 15:54:49 +0000701 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com74b98712011-11-11 19:46:16 +0000702 // We don't support using unpremultiplied textures with filters (other
703 // than nearest). Alpha-premulling is not distributive WRT to filtering.
704 // We'd have to filter each texel before filtering. We could do this for
705 // our custom filters but we would also have to disable bilerp and do
706 // a custom bilerp in the shader. Until Skia itself supports unpremul
707 // configs there is no pressure to implement this.
bsalomon@google.comc4364992011-11-07 15:54:49 +0000708 if (this->isStageEnabled(s) &&
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000709 GrPixelConfigIsUnpremultiplied(drawState.getTexture(s)->config()) &&
710 GrSamplerState::kNearest_Filter !=
711 drawState.getSampler(s).getFilter()) {
bsalomon@google.comc4364992011-11-07 15:54:49 +0000712 return false;
713 }
714 }
bsalomon@google.come8262622011-11-07 02:30:51 +0000715 return true;
716}
717
718void GrDrawTarget::drawIndexed(GrPrimitiveType type, int startVertex,
719 int startIndex, int vertexCount,
720 int indexCount) {
721 if (indexCount > 0 &&
722 this->checkDraw(type, startVertex, startIndex,
723 vertexCount, indexCount)) {
bsalomon@google.com82145872011-08-23 14:32:40 +0000724 this->onDrawIndexed(type, startVertex, startIndex,
725 vertexCount, indexCount);
726 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000727}
728
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000729void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
730 int startVertex,
731 int vertexCount) {
bsalomon@google.come8262622011-11-07 02:30:51 +0000732 if (vertexCount > 0 &&
733 this->checkDraw(type, startVertex, -1, vertexCount, -1)) {
bsalomon@google.com82145872011-08-23 14:32:40 +0000734 this->onDrawNonIndexed(type, startVertex, vertexCount);
735 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000736}
737
738////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000739
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000740// Some blend modes allow folding a partial coverage value into the color's
741// alpha channel, while others will blend incorrectly.
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000742bool GrDrawTarget::canTweakAlphaForCoverage() const {
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000743 /**
744 * The fractional coverage is f
745 * The src and dst coeffs are Cs and Cd
746 * The dst and src colors are S and D
747 * We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D
748 * By tweaking the source color's alpha we're replacing S with S'=fS. It's
749 * obvious that that first term will always be ok. The second term can be
750 * rearranged as [1-(1-Cd)f]D. By substituing in the various possbilities
751 * for Cd we find that only 1, ISA, and ISC produce the correct depth
752 * coeffecient in terms of S' and D.
753 */
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000754 GrBlendCoeff dstCoeff = this->getDrawState().getDstBlendCoeff();
755 return kOne_BlendCoeff == dstCoeff ||
756 kISA_BlendCoeff == dstCoeff ||
757 kISC_BlendCoeff == dstCoeff;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000758}
759
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000760
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000761bool GrDrawTarget::srcAlphaWillBeOne() const {
762 const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000763 const GrDrawState& drawState = this->getDrawState();
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000764
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000765 // Check if per-vertex or constant color may have partial alpha
bsalomon@google.com471d4712011-08-23 15:45:25 +0000766 if ((layout & kColor_VertexLayoutBit) ||
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000767 0xff != GrColorUnpackA(drawState.getColor())) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000768 return false;
769 }
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000770 // Check if color filter could introduce an alpha
771 // (TODO: Consider being more aggressive with regards to detecting 0xff
772 // final alpha from color filter).
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000773 if (SkXfermode::kDst_Mode != drawState.getColorFilterMode()) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000774 return false;
775 }
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000776 // Check if a color stage could create a partial alpha
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000777 for (int s = 0; s < drawState.getFirstCoverageStage(); ++s) {
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000778 if (StageWillBeUsed(s, layout, fCurrDrawState)) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000779 GrAssert(NULL != drawState.getTexture(s));
780 GrPixelConfig config = drawState.getTexture(s)->config();
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000781 if (!GrPixelConfigIsOpaque(config)) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000782 return false;
783 }
784 }
785 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000786 return true;
787}
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000788
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000789GrDrawTarget::BlendOptFlags
790GrDrawTarget::getBlendOpts(bool forceCoverage,
791 GrBlendCoeff* srcCoeff,
792 GrBlendCoeff* dstCoeff) const {
793
794 const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000795 const GrDrawState& drawState = this->getDrawState();
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000796
797 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
798 if (NULL == srcCoeff) {
799 srcCoeff = &bogusSrcCoeff;
800 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000801 *srcCoeff = drawState.getSrcBlendCoeff();
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000802
803 if (NULL == dstCoeff) {
804 dstCoeff = &bogusDstCoeff;
805 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000806 *dstCoeff = drawState.getDstBlendCoeff();
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000807
808 // We don't ever expect source coeffecients to reference the source
809 GrAssert(kSA_BlendCoeff != *srcCoeff &&
810 kISA_BlendCoeff != *srcCoeff &&
811 kSC_BlendCoeff != *srcCoeff &&
812 kISC_BlendCoeff != *srcCoeff);
813 // same for dst
814 GrAssert(kDA_BlendCoeff != *dstCoeff &&
815 kIDA_BlendCoeff != *dstCoeff &&
816 kDC_BlendCoeff != *dstCoeff &&
817 kIDC_BlendCoeff != *dstCoeff);
818
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000819 if (drawState.isColorWriteDisabled()) {
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000820 *srcCoeff = kZero_BlendCoeff;
821 *dstCoeff = kOne_BlendCoeff;
822 }
823
824 bool srcAIsOne = this->srcAlphaWillBeOne();
825 bool dstCoeffIsOne = kOne_BlendCoeff == *dstCoeff ||
826 (kSA_BlendCoeff == *dstCoeff && srcAIsOne);
827 bool dstCoeffIsZero = kZero_BlendCoeff == *dstCoeff ||
828 (kISA_BlendCoeff == *dstCoeff && srcAIsOne);
829
830
831 // When coeffs are (0,1) there is no reason to draw at all, unless
832 // stenciling is enabled. Having color writes disabled is effectively
833 // (0,1).
834 if ((kZero_BlendCoeff == *srcCoeff && dstCoeffIsOne)) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000835 if (drawState.getStencil().doesWrite()) {
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000836 if (fCaps.fShaderSupport) {
837 return kDisableBlend_BlendOptFlag |
838 kEmitTransBlack_BlendOptFlag;
839 } else {
840 return kDisableBlend_BlendOptFlag;
841 }
842 } else {
843 return kSkipDraw_BlendOptFlag;
844 }
845 }
846
847 // check for coverage due to edge aa or coverage texture stage
848 bool hasCoverage = forceCoverage ||
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000849 drawState.getNumAAEdges() > 0 ||
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000850 (layout & kCoverage_VertexLayoutBit) ||
851 (layout & kEdge_VertexLayoutBit);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000852 for (int s = drawState.getFirstCoverageStage();
tomhudson@google.com93813632011-10-27 20:21:16 +0000853 !hasCoverage && s < GrDrawState::kNumStages;
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000854 ++s) {
855 if (StageWillBeUsed(s, layout, fCurrDrawState)) {
856 hasCoverage = true;
857 }
858 }
859
860 // if we don't have coverage we can check whether the dst
861 // has to read at all. If not, we'll disable blending.
862 if (!hasCoverage) {
863 if (dstCoeffIsZero) {
864 if (kOne_BlendCoeff == *srcCoeff) {
865 // if there is no coverage and coeffs are (1,0) then we
866 // won't need to read the dst at all, it gets replaced by src
867 return kDisableBlend_BlendOptFlag;
868 } else if (kZero_BlendCoeff == *srcCoeff &&
869 fCaps.fShaderSupport) {
870 // if the op is "clear" then we don't need to emit a color
871 // or blend, just write transparent black into the dst.
872 *srcCoeff = kOne_BlendCoeff;
873 *dstCoeff = kZero_BlendCoeff;
874 return kDisableBlend_BlendOptFlag |
875 kEmitTransBlack_BlendOptFlag;
876 }
877 }
878 } else {
879 // check whether coverage can be safely rolled into alpha
880 // of if we can skip color computation and just emit coverage
881 if (this->canTweakAlphaForCoverage()) {
882 return kCoverageAsAlpha_BlendOptFlag;
883 }
884 // We haven't implemented support for these optimizations in the
885 // fixed pipe (which is on its deathbed)
886 if (fCaps.fShaderSupport) {
887 if (dstCoeffIsZero) {
888 if (kZero_BlendCoeff == *srcCoeff) {
889 // the source color is not included in the blend
890 // the dst coeff is effectively zero so blend works out to:
891 // (c)(0)D + (1-c)D = (1-c)D.
892 *dstCoeff = kISA_BlendCoeff;
893 return kEmitCoverage_BlendOptFlag;
894 } else if (srcAIsOne) {
895 // the dst coeff is effectively zero so blend works out to:
896 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
897 // If Sa is 1 then we can replace Sa with c
898 // and set dst coeff to 1-Sa.
899 *dstCoeff = kISA_BlendCoeff;
900 return kCoverageAsAlpha_BlendOptFlag;
901 }
902 } else if (dstCoeffIsOne) {
903 // the dst coeff is effectively one so blend works out to:
904 // cS + (c)(1)D + (1-c)D = cS + D.
905 *dstCoeff = kOne_BlendCoeff;
906 return kCoverageAsAlpha_BlendOptFlag;
907 }
908 }
909 }
910 return kNone_BlendOpt;
911}
912
913bool GrDrawTarget::willUseHWAALines() const {
bsalomon@google.com471d4712011-08-23 15:45:25 +0000914 // there is a conflict between using smooth lines and our use of
915 // premultiplied alpha. Smooth lines tweak the incoming alpha value
916 // but not in a premul-alpha way. So we only use them when our alpha
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000917 // is 0xff and tweaking the color for partial coverage is OK
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000918 if (!fCaps.fHWAALineSupport ||
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000919 !this->getDrawState().isHWAntialiasState()) {
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000920 return false;
921 }
922 BlendOptFlags opts = this->getBlendOpts();
923 return (kDisableBlend_BlendOptFlag & opts) &&
924 (kCoverageAsAlpha_BlendOptFlag & opts);
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000925}
926
927bool GrDrawTarget::canApplyCoverage() const {
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000928 // we can correctly apply coverage if a) we have dual source blending
929 // or b) one of our blend optimizations applies.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000930 return this->getCaps().fDualSourceBlendingSupport ||
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000931 kNone_BlendOpt != this->getBlendOpts(true);
bsalomon@google.com471d4712011-08-23 15:45:25 +0000932}
933
bsalomon@google.com86c1f712011-10-12 14:54:26 +0000934bool GrDrawTarget::drawWillReadDst() const {
935 return SkToBool((kDisableBlend_BlendOptFlag | kSkipDraw_BlendOptFlag) &
936 this->getBlendOpts());
bsalomon@google.com471d4712011-08-23 15:45:25 +0000937}
938
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000939
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000940////////////////////////////////////////////////////////////////////////////////
941
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000942void GrDrawTarget::drawRect(const GrRect& rect,
943 const GrMatrix* matrix,
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +0000944 StageMask stageMask,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000945 const GrRect* srcRects[],
946 const GrMatrix* srcMatrices[]) {
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +0000947 GrVertexLayout layout = GetRectVertexLayout(stageMask, srcRects);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000948
949 AutoReleaseGeometry geo(this, layout, 4, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000950 if (!geo.succeeded()) {
951 GrPrintf("Failed to get space for vertices!\n");
952 return;
953 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000954
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000955 SetRectVertices(rect, matrix, srcRects,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000956 srcMatrices, layout, geo.vertices());
957
958 drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
959}
960
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000961GrVertexLayout GrDrawTarget::GetRectVertexLayout(StageMask stageMask,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000962 const GrRect* srcRects[]) {
963 GrVertexLayout layout = 0;
964
tomhudson@google.com93813632011-10-27 20:21:16 +0000965 for (int i = 0; i < GrDrawState::kNumStages; ++i) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000966 int numTC = 0;
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +0000967 if (stageMask & (1 << i)) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000968 if (NULL != srcRects && NULL != srcRects[i]) {
969 layout |= StageTexCoordVertexLayoutBit(i, numTC);
970 ++numTC;
971 } else {
972 layout |= StagePosAsTexCoordVertexLayoutBit(i);
973 }
974 }
975 }
976 return layout;
977}
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000978
979void GrDrawTarget::clipWillBeSet(const GrClip& clip) {
980}
981
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000982void GrDrawTarget::SetRectVertices(const GrRect& rect,
983 const GrMatrix* matrix,
984 const GrRect* srcRects[],
985 const GrMatrix* srcMatrices[],
986 GrVertexLayout layout,
987 void* vertices) {
988#if GR_DEBUG
989 // check that the layout and srcRects agree
tomhudson@google.com93813632011-10-27 20:21:16 +0000990 for (int i = 0; i < GrDrawState::kNumStages; ++i) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000991 if (VertexTexCoordsForStage(i, layout) >= 0) {
992 GR_DEBUGASSERT(NULL != srcRects && NULL != srcRects[i]);
993 } else {
994 GR_DEBUGASSERT(NULL == srcRects || NULL == srcRects[i]);
995 }
996 }
997#endif
998
tomhudson@google.com93813632011-10-27 20:21:16 +0000999 int stageOffsets[GrDrawState::kNumStages];
bsalomon@google.coma3108262011-10-10 14:08:47 +00001000 int vsize = VertexSizeAndOffsetsByStage(layout, stageOffsets,
1001 NULL, NULL, NULL);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001002
bsalomon@google.coma3108262011-10-10 14:08:47 +00001003 GrTCast<GrPoint*>(vertices)->setRectFan(rect.fLeft, rect.fTop,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001004 rect.fRight, rect.fBottom,
1005 vsize);
1006 if (NULL != matrix) {
1007 matrix->mapPointsWithStride(GrTCast<GrPoint*>(vertices), vsize, 4);
1008 }
1009
tomhudson@google.com93813632011-10-27 20:21:16 +00001010 for (int i = 0; i < GrDrawState::kNumStages; ++i) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001011 if (stageOffsets[i] > 0) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001012 GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(vertices) +
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001013 stageOffsets[i]);
1014 coords->setRectFan(srcRects[i]->fLeft, srcRects[i]->fTop,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001015 srcRects[i]->fRight, srcRects[i]->fBottom,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001016 vsize);
1017 if (NULL != srcMatrices && NULL != srcMatrices[i]) {
1018 srcMatrices[i]->mapPointsWithStride(coords, vsize, 4);
1019 }
1020 }
1021 }
1022}
1023
bsalomon@google.com25fb21f2011-06-21 18:17:25 +00001024////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001025
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001026GrDrawTarget::AutoStateRestore::AutoStateRestore() {
1027 fDrawTarget = NULL;
1028}
reed@google.comac10a2d2010-12-22 21:39:39 +00001029
1030GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target) {
1031 fDrawTarget = target;
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001032 if (NULL != fDrawTarget) {
1033 fDrawTarget->saveCurrentDrawState(&fDrawState);
1034 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001035}
1036
1037GrDrawTarget::AutoStateRestore::~AutoStateRestore() {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001038 if (NULL != fDrawTarget) {
1039 fDrawTarget->restoreDrawState(fDrawState);
1040 }
reed@google.comac10a2d2010-12-22 21:39:39 +00001041}
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +00001042
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001043void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target) {
1044 if (target != fDrawTarget) {
1045 if (NULL != fDrawTarget) {
1046 fDrawTarget->restoreDrawState(fDrawState);
1047 }
1048 if (NULL != target) {
bsalomon@google.comd19aa272011-06-22 01:28:17 +00001049 target->saveCurrentDrawState(&fDrawState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001050 }
1051 fDrawTarget = target;
1052 }
1053}
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001054
bsalomon@google.com25fb21f2011-06-21 18:17:25 +00001055////////////////////////////////////////////////////////////////////////////////
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001056
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001057GrDrawTarget::AutoDeviceCoordDraw::AutoDeviceCoordDraw(
1058 GrDrawTarget* target,
1059 GrDrawState::StageMask stageMask) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001060 GrAssert(NULL != target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001061 GrDrawState* drawState = target->drawState();
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001062
1063 fDrawTarget = target;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001064 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001065 fStageMask = stageMask;
1066 if (fStageMask) {
1067 GrMatrix invVM;
1068 if (fViewMatrix.invert(&invVM)) {
tomhudson@google.com93813632011-10-27 20:21:16 +00001069 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001070 if (fStageMask & (1 << s)) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001071 fSamplerMatrices[s] = drawState->getSampler(s).getMatrix();
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001072 }
1073 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001074 drawState->preConcatSamplerMatrices(fStageMask, invVM);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001075 } else {
1076 // sad trombone sound
1077 fStageMask = 0;
1078 }
1079 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001080 drawState->setViewMatrix(GrMatrix::I());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001081}
1082
1083GrDrawTarget::AutoDeviceCoordDraw::~AutoDeviceCoordDraw() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001084 GrDrawState* drawState = fDrawTarget->drawState();
1085 drawState->setViewMatrix(fViewMatrix);
tomhudson@google.com93813632011-10-27 20:21:16 +00001086 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001087 if (fStageMask & (1 << s)) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001088 drawState->sampler(s)->setMatrix(fSamplerMatrices[s]);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001089 }
1090 }
1091}
1092
bsalomon@google.com25fb21f2011-06-21 18:17:25 +00001093////////////////////////////////////////////////////////////////////////////////
1094
1095GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry(
1096 GrDrawTarget* target,
1097 GrVertexLayout vertexLayout,
1098 int vertexCount,
1099 int indexCount) {
1100 fTarget = NULL;
1101 this->set(target, vertexLayout, vertexCount, indexCount);
1102}
1103
1104GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry() {
1105 fTarget = NULL;
1106}
1107
1108GrDrawTarget::AutoReleaseGeometry::~AutoReleaseGeometry() {
1109 this->reset();
1110}
1111
1112bool GrDrawTarget::AutoReleaseGeometry::set(GrDrawTarget* target,
1113 GrVertexLayout vertexLayout,
1114 int vertexCount,
1115 int indexCount) {
1116 this->reset();
1117 fTarget = target;
1118 bool success = true;
1119 if (NULL != fTarget) {
1120 fTarget = target;
1121 if (vertexCount > 0) {
1122 success = target->reserveVertexSpace(vertexLayout,
1123 vertexCount,
1124 &fVertices);
1125 if (!success) {
1126 this->reset();
1127 }
1128 }
1129 if (success && indexCount > 0) {
1130 success = target->reserveIndexSpace(indexCount, &fIndices);
1131 if (!success) {
1132 this->reset();
1133 }
1134 }
1135 }
1136 GrAssert(success == (NULL != fTarget));
1137 return success;
1138}
1139
1140void GrDrawTarget::AutoReleaseGeometry::reset() {
1141 if (NULL != fTarget) {
1142 if (NULL != fVertices) {
1143 fTarget->resetVertexSource();
1144 }
1145 if (NULL != fIndices) {
1146 fTarget->resetIndexSource();
1147 }
1148 fTarget = NULL;
1149 }
bsalomon@google.comcb0c5ab2011-06-29 17:48:17 +00001150 fVertices = NULL;
1151 fIndices = NULL;
bsalomon@google.com25fb21f2011-06-21 18:17:25 +00001152}
1153
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001154void GrDrawTarget::Caps::print() const {
1155 static const char* gNY[] = {"NO", "YES"};
1156 GrPrintf("8 Bit Palette Support : %s\n", gNY[f8BitPaletteSupport]);
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001157 GrPrintf("NPOT Texture Tile Support : %s\n", gNY[fNPOTTextureTileSupport]);
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001158 GrPrintf("Two Sided Stencil Support : %s\n", gNY[fTwoSidedStencilSupport]);
1159 GrPrintf("Stencil Wrap Ops Support : %s\n", gNY[fStencilWrapOpsSupport]);
1160 GrPrintf("HW AA Lines Support : %s\n", gNY[fHWAALineSupport]);
1161 GrPrintf("Shader Support : %s\n", gNY[fShaderSupport]);
1162 GrPrintf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]);
bsalomon@google.comedfe1aa2011-09-29 14:40:26 +00001163 GrPrintf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]);
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001164 GrPrintf("FSAA Support : %s\n", gNY[fFSAASupport]);
1165 GrPrintf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]);
1166 GrPrintf("Buffer Lock Support : %s\n", gNY[fBufferLockSupport]);
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001167 GrPrintf("Max Texture Size : %d\n", fMaxTextureSize);
1168 GrPrintf("Max Render Target Size : %d\n", fMaxRenderTargetSize);
1169}
1170