blob: a6d31481413b0d29005013b1a975ad3f13a69459 [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
joshualitta30009b2015-04-30 09:05:54 -070038 if (Cmd::kDrawBatch_CmdType == fCmdBuffer.back().type()) {
39 DrawBatch* previous = static_cast<DrawBatch*>(&fCmdBuffer.back());
40 if (previous->fBatch->combineIfPossible(batch)) {
41 return NULL;
42 }
robertphillips193ea932015-03-03 12:40:49 -080043 }
44
joshualitta30009b2015-04-30 09:05:54 -070045 return GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawBatch, (batch, &fBatchTarget));
robertphillips193ea932015-03-03 12:40:49 -080046}
47
48GrTargetCommands::Cmd* GrTargetCommands::recordStencilPath(
49 GrInOrderDrawBuffer* iodb,
50 const GrPipelineBuilder& pipelineBuilder,
51 const GrPathProcessor* pathProc,
52 const GrPath* path,
53 const GrScissorState& scissorState,
54 const GrStencilSettings& stencilSettings) {
robertphillips193ea932015-03-03 12:40:49 -080055 StencilPath* sp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, StencilPath,
56 (path, pipelineBuilder.getRenderTarget()));
57
58 sp->fScissor = scissorState;
59 sp->fUseHWAA = pipelineBuilder.isHWAntialias();
60 sp->fViewMatrix = pathProc->viewMatrix();
61 sp->fStencil = stencilSettings;
62 return sp;
63}
64
65GrTargetCommands::Cmd* GrTargetCommands::recordDrawPath(
66 GrInOrderDrawBuffer* iodb,
67 const GrPathProcessor* pathProc,
68 const GrPath* path,
69 const GrStencilSettings& stencilSettings,
70 const GrDrawTarget::PipelineInfo& pipelineInfo) {
robertphillips193ea932015-03-03 12:40:49 -080071 // TODO: Only compare the subset of GrPipelineBuilder relevant to path covering?
72 if (!this->setupPipelineAndShouldDraw(iodb, pathProc, pipelineInfo)) {
73 return NULL;
74 }
75 DrawPath* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPath, (path));
76 dp->fStencilSettings = stencilSettings;
77 return dp;
78}
79
80GrTargetCommands::Cmd* GrTargetCommands::recordDrawPaths(
81 GrInOrderDrawBuffer* iodb,
82 const GrPathProcessor* pathProc,
83 const GrPathRange* pathRange,
84 const void* indexValues,
85 GrDrawTarget::PathIndexType indexType,
86 const float transformValues[],
87 GrDrawTarget::PathTransformType transformType,
88 int count,
89 const GrStencilSettings& stencilSettings,
90 const GrDrawTarget::PipelineInfo& pipelineInfo) {
91 SkASSERT(pathRange);
92 SkASSERT(indexValues);
93 SkASSERT(transformValues);
robertphillips193ea932015-03-03 12:40:49 -080094
95 if (!this->setupPipelineAndShouldDraw(iodb, pathProc, pipelineInfo)) {
96 return NULL;
97 }
98
99 char* savedIndices;
100 float* savedTransforms;
101
102 iodb->appendIndicesAndTransforms(indexValues, indexType,
103 transformValues, transformType,
104 count, &savedIndices, &savedTransforms);
105
robertphillipsbca3c9f2015-03-05 09:17:17 -0800106 if (Cmd::kDrawPaths_CmdType == fCmdBuffer.back().type()) {
robertphillips193ea932015-03-03 12:40:49 -0800107 // The previous command was also DrawPaths. Try to collapse this call into the one
108 // before. Note that stenciling all the paths at once, then covering, may not be
109 // equivalent to two separate draw calls if there is overlap. Blending won't work,
110 // and the combined calls may also cancel each other's winding numbers in some
111 // places. For now the winding numbers are only an issue if the fill is even/odd,
112 // because DrawPaths is currently only used for glyphs, and glyphs in the same
113 // font tend to all wind in the same direction.
114 DrawPaths* previous = static_cast<DrawPaths*>(&fCmdBuffer.back());
115 if (pathRange == previous->pathRange() &&
116 indexType == previous->fIndexType &&
117 transformType == previous->fTransformType &&
118 stencilSettings == previous->fStencilSettings &&
119 path_fill_type_is_winding(stencilSettings) &&
120 !pipelineInfo.willBlendWithDst(pathProc)) {
121 const int indexBytes = GrPathRange::PathIndexSizeInBytes(indexType);
122 const int xformSize = GrPathRendering::PathTransformSize(transformType);
123 if (&previous->fIndices[previous->fCount*indexBytes] == savedIndices &&
124 (0 == xformSize ||
125 &previous->fTransforms[previous->fCount*xformSize] == savedTransforms)) {
126 // Fold this DrawPaths call into the one previous.
127 previous->fCount += count;
128 return NULL;
129 }
130 }
131 }
132
133 DrawPaths* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPaths, (pathRange));
134 dp->fIndices = savedIndices;
135 dp->fIndexType = indexType;
136 dp->fTransforms = savedTransforms;
137 dp->fTransformType = transformType;
138 dp->fCount = count;
139 dp->fStencilSettings = stencilSettings;
140 return dp;
141}
142
143GrTargetCommands::Cmd* GrTargetCommands::recordClear(GrInOrderDrawBuffer* iodb,
144 const SkIRect* rect,
145 GrColor color,
146 bool canIgnoreRect,
147 GrRenderTarget* renderTarget) {
148 SkASSERT(renderTarget);
robertphillips193ea932015-03-03 12:40:49 -0800149
150 SkIRect r;
151 if (NULL == rect) {
152 // We could do something smart and remove previous draws and clears to
153 // the current render target. If we get that smart we have to make sure
154 // those draws aren't read before this clear (render-to-texture).
155 r.setLTRB(0, 0, renderTarget->width(), renderTarget->height());
156 rect = &r;
157 }
158 Clear* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Clear, (renderTarget));
159 GrColorIsPMAssert(color);
160 clr->fColor = color;
161 clr->fRect = *rect;
162 clr->fCanIgnoreRect = canIgnoreRect;
163 return clr;
164}
165
166GrTargetCommands::Cmd* GrTargetCommands::recordClearStencilClip(GrInOrderDrawBuffer* iodb,
167 const SkIRect& rect,
168 bool insideClip,
169 GrRenderTarget* renderTarget) {
170 SkASSERT(renderTarget);
robertphillips193ea932015-03-03 12:40:49 -0800171
172 ClearStencilClip* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, ClearStencilClip, (renderTarget));
173 clr->fRect = rect;
174 clr->fInsideClip = insideClip;
175 return clr;
176}
177
178GrTargetCommands::Cmd* GrTargetCommands::recordDiscard(GrInOrderDrawBuffer* iodb,
179 GrRenderTarget* renderTarget) {
180 SkASSERT(renderTarget);
robertphillips193ea932015-03-03 12:40:49 -0800181
182 Clear* clr = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, Clear, (renderTarget));
183 clr->fColor = GrColor_ILLEGAL;
184 return clr;
185}
186
187void GrTargetCommands::reset() {
188 fCmdBuffer.reset();
189 fPrevState = NULL;
robertphillips193ea932015-03-03 12:40:49 -0800190}
191
192void GrTargetCommands::flush(GrInOrderDrawBuffer* iodb) {
193 if (fCmdBuffer.empty()) {
194 return;
195 }
196
robertphillipsbca3c9f2015-03-05 09:17:17 -0800197 // Updated every time we find a set state cmd to reflect the current state in the playback
198 // stream.
199 SetState* currentState = NULL;
robertphillips193ea932015-03-03 12:40:49 -0800200
joshualitt385e26e2015-04-27 11:42:30 -0700201 GrGpu* gpu = iodb->getGpu();
202
joshualitt0dcb8e32015-04-27 12:03:05 -0700203 // Loop over all batches and generate geometry
204 CmdBuffer::Iter genIter(fCmdBuffer);
205 while (genIter.next()) {
206 if (Cmd::kDrawBatch_CmdType == genIter->type()) {
207 DrawBatch* db = reinterpret_cast<DrawBatch*>(genIter.get());
208 fBatchTarget.resetNumberOfDraws();
209 db->execute(NULL, currentState);
210 db->fBatch->setNumberOfDraws(fBatchTarget.numberOfDraws());
211 } else if (Cmd::kSetState_CmdType == genIter->type()) {
212 SetState* ss = reinterpret_cast<SetState*>(genIter.get());
213
214 ss->execute(gpu, currentState);
215 currentState = ss;
216 }
217 }
joshualitt0dcb8e32015-04-27 12:03:05 -0700218
219 iodb->getVertexAllocPool()->unmap();
220 iodb->getIndexAllocPool()->unmap();
221 fBatchTarget.preFlush();
222
223 CmdBuffer::Iter iter(fCmdBuffer);
224
robertphillips193ea932015-03-03 12:40:49 -0800225 while (iter.next()) {
robertphillips193ea932015-03-03 12:40:49 -0800226 GrGpuTraceMarker newMarker("", -1);
227 SkString traceString;
228 if (iter->isTraced()) {
robertphillipsbca3c9f2015-03-05 09:17:17 -0800229 traceString = iodb->getCmdString(iter->markerID());
robertphillips193ea932015-03-03 12:40:49 -0800230 newMarker.fMarker = traceString.c_str();
231 gpu->addGpuTraceMarker(&newMarker);
robertphillips193ea932015-03-03 12:40:49 -0800232 }
233
robertphillipsbca3c9f2015-03-05 09:17:17 -0800234 if (Cmd::kDrawBatch_CmdType == iter->type()) {
robertphillips193ea932015-03-03 12:40:49 -0800235 DrawBatch* db = reinterpret_cast<DrawBatch*>(iter.get());
236 fBatchTarget.flushNext(db->fBatch->numberOfDraws());
robertphillipsd14101e2015-03-05 08:55:28 -0800237
238 if (iter->isTraced()) {
239 gpu->removeGpuTraceMarker(&newMarker);
240 }
robertphillips193ea932015-03-03 12:40:49 -0800241 continue;
242 }
243
robertphillipsbca3c9f2015-03-05 09:17:17 -0800244 if (Cmd::kSetState_CmdType == iter->type()) {
joshualitt0dcb8e32015-04-27 12:03:05 -0700245 // TODO this is just until NVPR is in batch
246 SetState* ss = reinterpret_cast<SetState*>(iter.get());
247
248 if (ss->fPrimitiveProcessor) {
249 ss->execute(gpu, currentState);
250 }
251 currentState = ss;
joshualitt0dcb8e32015-04-27 12:03:05 -0700252
robertphillips193ea932015-03-03 12:40:49 -0800253 } else {
254 iter->execute(gpu, currentState);
255 }
256
257 if (iter->isTraced()) {
258 gpu->removeGpuTraceMarker(&newMarker);
259 }
260 }
261
robertphillips193ea932015-03-03 12:40:49 -0800262 fBatchTarget.postFlush();
263}
264
robertphillips193ea932015-03-03 12:40:49 -0800265void GrTargetCommands::StencilPath::execute(GrGpu* gpu, const SetState*) {
266 GrGpu::StencilPathState state;
267 state.fRenderTarget = fRenderTarget.get();
268 state.fScissor = &fScissor;
269 state.fStencil = &fStencil;
270 state.fUseHWAA = fUseHWAA;
271 state.fViewMatrix = &fViewMatrix;
272
273 gpu->stencilPath(this->path(), state);
274}
275
276void GrTargetCommands::DrawPath::execute(GrGpu* gpu, const SetState* state) {
277 SkASSERT(state);
278 DrawArgs args(state->fPrimitiveProcessor.get(), state->getPipeline(), &state->fDesc,
279 &state->fBatchTracker);
280 gpu->drawPath(args, this->path(), fStencilSettings);
281}
282
283void GrTargetCommands::DrawPaths::execute(GrGpu* gpu, const SetState* state) {
284 SkASSERT(state);
285 DrawArgs args(state->fPrimitiveProcessor.get(), state->getPipeline(), &state->fDesc,
286 &state->fBatchTracker);
287 gpu->drawPaths(args, this->pathRange(),
288 fIndices, fIndexType,
289 fTransforms, fTransformType,
290 fCount, fStencilSettings);
291}
292
293void GrTargetCommands::DrawBatch::execute(GrGpu*, const SetState* state) {
294 SkASSERT(state);
295 fBatch->generateGeometry(fBatchTarget, state->getPipeline());
296}
297
robertphillipsbca3c9f2015-03-05 09:17:17 -0800298void GrTargetCommands::SetState::execute(GrGpu* gpu, const SetState*) {
299 // TODO sometimes we have a prim proc, othertimes we have a GrBatch. Eventually we
300 // will only have GrBatch and we can delete this
301 if (fPrimitiveProcessor) {
302 gpu->buildProgramDesc(&fDesc, *fPrimitiveProcessor, *getPipeline(), fBatchTracker);
303 }
304}
robertphillips193ea932015-03-03 12:40:49 -0800305
306void GrTargetCommands::Clear::execute(GrGpu* gpu, const SetState*) {
307 if (GrColor_ILLEGAL == fColor) {
308 gpu->discard(this->renderTarget());
309 } else {
310 gpu->clear(&fRect, fColor, fCanIgnoreRect, this->renderTarget());
311 }
312}
313
314void GrTargetCommands::ClearStencilClip::execute(GrGpu* gpu, const SetState*) {
315 gpu->clearStencilClip(fRect, fInsideClip, this->renderTarget());
316}
317
318void GrTargetCommands::CopySurface::execute(GrGpu* gpu, const SetState*) {
319 gpu->copySurface(this->dst(), this->src(), fSrcRect, fDstPoint);
320}
321
cdalton9954bc32015-04-29 14:17:00 -0700322void GrTargetCommands::XferBarrier::execute(GrGpu* gpu, const SetState* state) {
323 gpu->xferBarrier(fBarrierType);
324}
325
bsalomona73239a2015-04-28 13:35:17 -0700326GrTargetCommands::Cmd* GrTargetCommands::recordCopySurface(GrSurface* dst,
robertphillips193ea932015-03-03 12:40:49 -0800327 GrSurface* src,
328 const SkIRect& srcRect,
329 const SkIPoint& dstPoint) {
bsalomona73239a2015-04-28 13:35:17 -0700330 CopySurface* cs = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, CopySurface, (dst, src));
331 cs->fSrcRect = srcRect;
332 cs->fDstPoint = dstPoint;
333 return cs;
robertphillips193ea932015-03-03 12:40:49 -0800334}
335
336bool GrTargetCommands::setupPipelineAndShouldDraw(GrInOrderDrawBuffer* iodb,
337 const GrPrimitiveProcessor* primProc,
338 const GrDrawTarget::PipelineInfo& pipelineInfo) {
339 SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, (primProc));
340 iodb->setupPipeline(pipelineInfo, ss->pipelineLocation());
341
342 if (ss->getPipeline()->mustSkip()) {
343 fCmdBuffer.pop_back();
344 return false;
345 }
346
347 ss->fPrimitiveProcessor->initBatchTracker(&ss->fBatchTracker,
348 ss->getPipeline()->getInitBatchTracker());
349
350 if (fPrevState && fPrevState->fPrimitiveProcessor.get() &&
351 fPrevState->fPrimitiveProcessor->canMakeEqual(fPrevState->fBatchTracker,
352 *ss->fPrimitiveProcessor,
353 ss->fBatchTracker) &&
354 fPrevState->getPipeline()->isEqual(*ss->getPipeline())) {
355 fCmdBuffer.pop_back();
356 } else {
357 fPrevState = ss;
358 iodb->recordTraceMarkersIfNecessary(ss);
359 }
cdalton9954bc32015-04-29 14:17:00 -0700360
361 this->recordXferBarrierIfNecessary(iodb, pipelineInfo);
robertphillips193ea932015-03-03 12:40:49 -0800362 return true;
363}
364
365bool GrTargetCommands::setupPipelineAndShouldDraw(GrInOrderDrawBuffer* iodb,
366 GrBatch* batch,
367 const GrDrawTarget::PipelineInfo& pipelineInfo) {
368 SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState, ());
369 iodb->setupPipeline(pipelineInfo, ss->pipelineLocation());
370
371 if (ss->getPipeline()->mustSkip()) {
372 fCmdBuffer.pop_back();
373 return false;
374 }
375
376 batch->initBatchTracker(ss->getPipeline()->getInitBatchTracker());
377
378 if (fPrevState && !fPrevState->fPrimitiveProcessor.get() &&
379 fPrevState->getPipeline()->isEqual(*ss->getPipeline())) {
380 fCmdBuffer.pop_back();
381 } else {
robertphillips193ea932015-03-03 12:40:49 -0800382 fPrevState = ss;
383 iodb->recordTraceMarkersIfNecessary(ss);
384 }
cdalton9954bc32015-04-29 14:17:00 -0700385
386 this->recordXferBarrierIfNecessary(iodb, pipelineInfo);
robertphillips193ea932015-03-03 12:40:49 -0800387 return true;
388}
389
cdalton9954bc32015-04-29 14:17:00 -0700390void GrTargetCommands::recordXferBarrierIfNecessary(GrInOrderDrawBuffer* iodb,
391 const GrDrawTarget::PipelineInfo& info) {
392 SkASSERT(fPrevState);
393 const GrXferProcessor& xp = *fPrevState->getXferProcessor();
394 GrRenderTarget* rt = fPrevState->getRenderTarget();
395
396 GrXferBarrierType barrierType;
397 if (!xp.willNeedXferBarrier(rt, *iodb->caps(), &barrierType)) {
398 return;
399 }
400
401 XferBarrier* xb = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, XferBarrier, ());
402 xb->fBarrierType = barrierType;
403
404 iodb->recordTraceMarkersIfNecessary(xb);
405}
406