blob: c448db95b64a1bd56da6eb53b7cacc6e09782dbc [file] [log] [blame]
robertphillips193ea932015-03-03 12:40:49 -08001/*
2 * Copyright 2015 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#include "GrTargetCommands.h"
9
10#include "GrColor.h"
11#include "GrDefaultGeoProcFactory.h"
12#include "GrInOrderDrawBuffer.h"
13#include "GrTemplates.h"
14#include "SkPoint.h"
15
robertphillips193ea932015-03-03 12:40:49 -080016static bool path_fill_type_is_winding(const GrStencilSettings& pathStencilSettings) {
17 static const GrStencilSettings::Face pathFace = GrStencilSettings::kFront_Face;
18 bool isWinding = kInvert_StencilOp != pathStencilSettings.passOp(pathFace);
19 if (isWinding) {
20 // Double check that it is in fact winding.
21 SkASSERT(kIncClamp_StencilOp == pathStencilSettings.passOp(pathFace));
22 SkASSERT(kIncClamp_StencilOp == pathStencilSettings.failOp(pathFace));
23 SkASSERT(0x1 != pathStencilSettings.writeMask(pathFace));
24 SkASSERT(!pathStencilSettings.isTwoSided());
25 }
26 return isWinding;
27}
28
robertphillips193ea932015-03-03 12:40:49 -080029GrTargetCommands::Cmd* GrTargetCommands::recordDrawBatch(
30 GrInOrderDrawBuffer* iodb,
31 GrBatch* batch,
32 const GrDrawTarget::PipelineInfo& pipelineInfo) {
33 if (!this->setupPipelineAndShouldDraw(iodb, batch, pipelineInfo)) {
34 return NULL;
35 }
36
37 // Check if there is a Batch Draw we can batch with
robertphillipsbca3c9f2015-03-05 09:17:17 -080038 if (Cmd::kDrawBatch_CmdType != fCmdBuffer.back().type() || !fDrawBatch) {
robertphillips193ea932015-03-03 12:40:49 -080039 fDrawBatch = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawBatch, (batch, &fBatchTarget));
40 return fDrawBatch;
41 }
42
43 SkASSERT(&fCmdBuffer.back() == fDrawBatch);
44 if (!fDrawBatch->fBatch->combineIfPossible(batch)) {
robertphillips193ea932015-03-03 12:40:49 -080045 fDrawBatch = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawBatch, (batch, &fBatchTarget));
46 }
47
48 return fDrawBatch;
49}
50
51GrTargetCommands::Cmd* GrTargetCommands::recordStencilPath(
52 GrInOrderDrawBuffer* iodb,
53 const GrPipelineBuilder& pipelineBuilder,
54 const GrPathProcessor* pathProc,
55 const GrPath* path,
56 const GrScissorState& scissorState,
57 const GrStencilSettings& stencilSettings) {
robertphillips193ea932015-03-03 12:40:49 -080058 StencilPath* sp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, StencilPath,
59 (path, pipelineBuilder.getRenderTarget()));
60
61 sp->fScissor = scissorState;
62 sp->fUseHWAA = pipelineBuilder.isHWAntialias();
63 sp->fViewMatrix = pathProc->viewMatrix();
64 sp->fStencil = stencilSettings;
65 return sp;
66}
67
68GrTargetCommands::Cmd* GrTargetCommands::recordDrawPath(
69 GrInOrderDrawBuffer* iodb,
70 const GrPathProcessor* pathProc,
71 const GrPath* path,
72 const GrStencilSettings& stencilSettings,
73 const GrDrawTarget::PipelineInfo& pipelineInfo) {
robertphillips193ea932015-03-03 12:40:49 -080074 // TODO: Only compare the subset of GrPipelineBuilder relevant to path covering?
75 if (!this->setupPipelineAndShouldDraw(iodb, pathProc, pipelineInfo)) {
76 return NULL;
77 }
78 DrawPath* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPath, (path));
79 dp->fStencilSettings = stencilSettings;
80 return dp;
81}
82
83GrTargetCommands::Cmd* GrTargetCommands::recordDrawPaths(
84 GrInOrderDrawBuffer* iodb,
85 const GrPathProcessor* pathProc,
86 const GrPathRange* pathRange,
87 const void* indexValues,
88 GrDrawTarget::PathIndexType indexType,
89 const float transformValues[],
90 GrDrawTarget::PathTransformType transformType,
91 int count,
92 const GrStencilSettings& stencilSettings,
93 const GrDrawTarget::PipelineInfo& pipelineInfo) {
94 SkASSERT(pathRange);
95 SkASSERT(indexValues);
96 SkASSERT(transformValues);
robertphillips193ea932015-03-03 12:40:49 -080097
98 if (!this->setupPipelineAndShouldDraw(iodb, pathProc, pipelineInfo)) {
99 return NULL;
100 }
101
102 char* savedIndices;
103 float* savedTransforms;
104
105 iodb->appendIndicesAndTransforms(indexValues, indexType,
106 transformValues, transformType,
107 count, &savedIndices, &savedTransforms);
108
robertphillipsbca3c9f2015-03-05 09:17:17 -0800109 if (Cmd::kDrawPaths_CmdType == fCmdBuffer.back().type()) {
robertphillips193ea932015-03-03 12:40:49 -0800110 // The previous command was also DrawPaths. Try to collapse this call into the one
111 // before. Note that stenciling all the paths at once, then covering, may not be
112 // equivalent to two separate draw calls if there is overlap. Blending won't work,
113 // and the combined calls may also cancel each other's winding numbers in some
114 // places. For now the winding numbers are only an issue if the fill is even/odd,
115 // because DrawPaths is currently only used for glyphs, and glyphs in the same
116 // font tend to all wind in the same direction.
117 DrawPaths* previous = static_cast<DrawPaths*>(&fCmdBuffer.back());
118 if (pathRange == previous->pathRange() &&
119 indexType == previous->fIndexType &&
120 transformType == previous->fTransformType &&
121 stencilSettings == previous->fStencilSettings &&
122 path_fill_type_is_winding(stencilSettings) &&
123 !pipelineInfo.willBlendWithDst(pathProc)) {
124 const int indexBytes = GrPathRange::PathIndexSizeInBytes(indexType);
125 const int xformSize = GrPathRendering::PathTransformSize(transformType);
126 if (&previous->fIndices[previous->fCount*indexBytes] == savedIndices &&
127 (0 == xformSize ||
128 &previous->fTransforms[previous->fCount*xformSize] == savedTransforms)) {
129 // Fold this DrawPaths call into the one previous.
130 previous->fCount += count;
131 return NULL;
132 }
133 }
134 }
135
136 DrawPaths* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPaths, (pathRange));
137 dp->fIndices = savedIndices;
138 dp->fIndexType = indexType;
139 dp->fTransforms = savedTransforms;
140 dp->fTransformType = transformType;
141 dp->fCount = count;
142 dp->fStencilSettings = stencilSettings;
143 return dp;
144}
145
146GrTargetCommands::Cmd* GrTargetCommands::recordClear(GrInOrderDrawBuffer* iodb,
147 const SkIRect* rect,
148 GrColor color,
149 bool canIgnoreRect,
150 GrRenderTarget* renderTarget) {
151 SkASSERT(renderTarget);
robertphillips193ea932015-03-03 12:40:49 -0800152
153 SkIRect r;
154 if (NULL == rect) {
155 // We could do something smart and remove previous draws and clears to
156 // the current render target. If we get that smart we have to make sure
157 // those draws aren't read before this clear (render-to-texture).
158 r.setLTRB(0, 0, renderTarget->width(), renderTarget->height());
159 rect = &r;
160 }
161 Clear* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Clear, (renderTarget));
162 GrColorIsPMAssert(color);
163 clr->fColor = color;
164 clr->fRect = *rect;
165 clr->fCanIgnoreRect = canIgnoreRect;
166 return clr;
167}
168
169GrTargetCommands::Cmd* GrTargetCommands::recordClearStencilClip(GrInOrderDrawBuffer* iodb,
170 const SkIRect& rect,
171 bool insideClip,
172 GrRenderTarget* renderTarget) {
173 SkASSERT(renderTarget);
robertphillips193ea932015-03-03 12:40:49 -0800174
175 ClearStencilClip* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, ClearStencilClip, (renderTarget));
176 clr->fRect = rect;
177 clr->fInsideClip = insideClip;
178 return clr;
179}
180
181GrTargetCommands::Cmd* GrTargetCommands::recordDiscard(GrInOrderDrawBuffer* iodb,
182 GrRenderTarget* renderTarget) {
183 SkASSERT(renderTarget);
robertphillips193ea932015-03-03 12:40:49 -0800184
185 Clear* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Clear, (renderTarget));
186 clr->fColor = GrColor_ILLEGAL;
187 return clr;
188}
189
190void GrTargetCommands::reset() {
191 fCmdBuffer.reset();
192 fPrevState = NULL;
193 fDrawBatch = NULL;
194}
195
196void GrTargetCommands::flush(GrInOrderDrawBuffer* iodb) {
197 if (fCmdBuffer.empty()) {
198 return;
199 }
200
robertphillipsbca3c9f2015-03-05 09:17:17 -0800201 // Updated every time we find a set state cmd to reflect the current state in the playback
202 // stream.
203 SetState* currentState = NULL;
robertphillips193ea932015-03-03 12:40:49 -0800204
joshualitt385e26e2015-04-27 11:42:30 -0700205 GrGpu* gpu = iodb->getGpu();
206
joshualitt0dcb8e32015-04-27 12:03:05 -0700207#ifdef USE_BITMAP_TEXTBLOBS
208 // Loop over all batches and generate geometry
209 CmdBuffer::Iter genIter(fCmdBuffer);
210 while (genIter.next()) {
211 if (Cmd::kDrawBatch_CmdType == genIter->type()) {
212 DrawBatch* db = reinterpret_cast<DrawBatch*>(genIter.get());
213 fBatchTarget.resetNumberOfDraws();
214 db->execute(NULL, currentState);
215 db->fBatch->setNumberOfDraws(fBatchTarget.numberOfDraws());
216 } else if (Cmd::kSetState_CmdType == genIter->type()) {
217 SetState* ss = reinterpret_cast<SetState*>(genIter.get());
218
219 ss->execute(gpu, currentState);
220 currentState = ss;
221 }
222 }
223#endif
224
225 iodb->getVertexAllocPool()->unmap();
226 iodb->getIndexAllocPool()->unmap();
227 fBatchTarget.preFlush();
228
229 CmdBuffer::Iter iter(fCmdBuffer);
230
robertphillips193ea932015-03-03 12:40:49 -0800231 while (iter.next()) {
robertphillips193ea932015-03-03 12:40:49 -0800232 GrGpuTraceMarker newMarker("", -1);
233 SkString traceString;
234 if (iter->isTraced()) {
robertphillipsbca3c9f2015-03-05 09:17:17 -0800235 traceString = iodb->getCmdString(iter->markerID());
robertphillips193ea932015-03-03 12:40:49 -0800236 newMarker.fMarker = traceString.c_str();
237 gpu->addGpuTraceMarker(&newMarker);
robertphillips193ea932015-03-03 12:40:49 -0800238 }
239
240 // TODO temporary hack
robertphillipsbca3c9f2015-03-05 09:17:17 -0800241 if (Cmd::kDrawBatch_CmdType == iter->type()) {
robertphillips193ea932015-03-03 12:40:49 -0800242 DrawBatch* db = reinterpret_cast<DrawBatch*>(iter.get());
243 fBatchTarget.flushNext(db->fBatch->numberOfDraws());
robertphillipsd14101e2015-03-05 08:55:28 -0800244
245 if (iter->isTraced()) {
246 gpu->removeGpuTraceMarker(&newMarker);
247 }
robertphillips193ea932015-03-03 12:40:49 -0800248 continue;
249 }
250
robertphillipsbca3c9f2015-03-05 09:17:17 -0800251 if (Cmd::kSetState_CmdType == iter->type()) {
joshualitt0dcb8e32015-04-27 12:03:05 -0700252#ifndef USE_BITMAP_TEXTBLOBS
robertphillips193ea932015-03-03 12:40:49 -0800253 SetState* ss = reinterpret_cast<SetState*>(iter.get());
254
robertphillipsbca3c9f2015-03-05 09:17:17 -0800255 ss->execute(gpu, currentState);
robertphillips193ea932015-03-03 12:40:49 -0800256 currentState = ss;
joshualitt0dcb8e32015-04-27 12:03:05 -0700257#else
258 // TODO this is just until NVPR is in batch
259 SetState* ss = reinterpret_cast<SetState*>(iter.get());
260
261 if (ss->fPrimitiveProcessor) {
262 ss->execute(gpu, currentState);
263 }
264 currentState = ss;
265#endif
266
robertphillips193ea932015-03-03 12:40:49 -0800267 } else {
268 iter->execute(gpu, currentState);
269 }
270
271 if (iter->isTraced()) {
272 gpu->removeGpuTraceMarker(&newMarker);
273 }
274 }
275
276 // TODO see copious notes about hack
277 fBatchTarget.postFlush();
278}
279
280void GrTargetCommands::Draw::execute(GrGpu* gpu, const SetState* state) {
281 SkASSERT(state);
282 DrawArgs args(state->fPrimitiveProcessor.get(), state->getPipeline(), &state->fDesc,
283 &state->fBatchTracker);
284 gpu->draw(args, fInfo);
285}
286
287void GrTargetCommands::StencilPath::execute(GrGpu* gpu, const SetState*) {
288 GrGpu::StencilPathState state;
289 state.fRenderTarget = fRenderTarget.get();
290 state.fScissor = &fScissor;
291 state.fStencil = &fStencil;
292 state.fUseHWAA = fUseHWAA;
293 state.fViewMatrix = &fViewMatrix;
294
295 gpu->stencilPath(this->path(), state);
296}
297
298void GrTargetCommands::DrawPath::execute(GrGpu* gpu, const SetState* state) {
299 SkASSERT(state);
300 DrawArgs args(state->fPrimitiveProcessor.get(), state->getPipeline(), &state->fDesc,
301 &state->fBatchTracker);
302 gpu->drawPath(args, this->path(), fStencilSettings);
303}
304
305void GrTargetCommands::DrawPaths::execute(GrGpu* gpu, const SetState* state) {
306 SkASSERT(state);
307 DrawArgs args(state->fPrimitiveProcessor.get(), state->getPipeline(), &state->fDesc,
308 &state->fBatchTracker);
309 gpu->drawPaths(args, this->pathRange(),
310 fIndices, fIndexType,
311 fTransforms, fTransformType,
312 fCount, fStencilSettings);
313}
314
315void GrTargetCommands::DrawBatch::execute(GrGpu*, const SetState* state) {
316 SkASSERT(state);
317 fBatch->generateGeometry(fBatchTarget, state->getPipeline());
318}
319
robertphillipsbca3c9f2015-03-05 09:17:17 -0800320void GrTargetCommands::SetState::execute(GrGpu* gpu, const SetState*) {
321 // TODO sometimes we have a prim proc, othertimes we have a GrBatch. Eventually we
322 // will only have GrBatch and we can delete this
323 if (fPrimitiveProcessor) {
324 gpu->buildProgramDesc(&fDesc, *fPrimitiveProcessor, *getPipeline(), fBatchTracker);
325 }
326}
robertphillips193ea932015-03-03 12:40:49 -0800327
328void GrTargetCommands::Clear::execute(GrGpu* gpu, const SetState*) {
329 if (GrColor_ILLEGAL == fColor) {
330 gpu->discard(this->renderTarget());
331 } else {
332 gpu->clear(&fRect, fColor, fCanIgnoreRect, this->renderTarget());
333 }
334}
335
336void GrTargetCommands::ClearStencilClip::execute(GrGpu* gpu, const SetState*) {
337 gpu->clearStencilClip(fRect, fInsideClip, this->renderTarget());
338}
339
340void GrTargetCommands::CopySurface::execute(GrGpu* gpu, const SetState*) {
341 gpu->copySurface(this->dst(), this->src(), fSrcRect, fDstPoint);
342}
343
bsalomona73239a2015-04-28 13:35:17 -0700344GrTargetCommands::Cmd* GrTargetCommands::recordCopySurface(GrSurface* dst,
robertphillips193ea932015-03-03 12:40:49 -0800345 GrSurface* src,
346 const SkIRect& srcRect,
347 const SkIPoint& dstPoint) {
bsalomona73239a2015-04-28 13:35:17 -0700348 CopySurface* cs = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, CopySurface, (dst, src));
349 cs->fSrcRect = srcRect;
350 cs->fDstPoint = dstPoint;
351 return cs;
robertphillips193ea932015-03-03 12:40:49 -0800352}
353
354bool GrTargetCommands::setupPipelineAndShouldDraw(GrInOrderDrawBuffer* iodb,
355 const GrPrimitiveProcessor* primProc,
356 const GrDrawTarget::PipelineInfo& pipelineInfo) {
357 SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (primProc));
358 iodb->setupPipeline(pipelineInfo, ss->pipelineLocation());
359
360 if (ss->getPipeline()->mustSkip()) {
361 fCmdBuffer.pop_back();
362 return false;
363 }
364
365 ss->fPrimitiveProcessor->initBatchTracker(&ss->fBatchTracker,
366 ss->getPipeline()->getInitBatchTracker());
367
368 if (fPrevState && fPrevState->fPrimitiveProcessor.get() &&
369 fPrevState->fPrimitiveProcessor->canMakeEqual(fPrevState->fBatchTracker,
370 *ss->fPrimitiveProcessor,
371 ss->fBatchTracker) &&
372 fPrevState->getPipeline()->isEqual(*ss->getPipeline())) {
373 fCmdBuffer.pop_back();
374 } else {
375 fPrevState = ss;
376 iodb->recordTraceMarkersIfNecessary(ss);
377 }
378 return true;
379}
380
381bool GrTargetCommands::setupPipelineAndShouldDraw(GrInOrderDrawBuffer* iodb,
382 GrBatch* batch,
383 const GrDrawTarget::PipelineInfo& pipelineInfo) {
384 SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, ());
385 iodb->setupPipeline(pipelineInfo, ss->pipelineLocation());
386
387 if (ss->getPipeline()->mustSkip()) {
388 fCmdBuffer.pop_back();
389 return false;
390 }
391
392 batch->initBatchTracker(ss->getPipeline()->getInitBatchTracker());
393
394 if (fPrevState && !fPrevState->fPrimitiveProcessor.get() &&
395 fPrevState->getPipeline()->isEqual(*ss->getPipeline())) {
396 fCmdBuffer.pop_back();
397 } else {
robertphillips193ea932015-03-03 12:40:49 -0800398 fPrevState = ss;
399 iodb->recordTraceMarkersIfNecessary(ss);
400 }
401 return true;
402}
403