blob: e48c14cdd5a1cb384266b6389f0603678eabc2b6 [file] [log] [blame]
egdaniel9cb63402016-06-23 08:37:05 -07001/*
2* Copyright 2016 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
Greg Daniel2d41d0d2019-08-26 11:08:51 -04008#include "src/gpu/GrOpsRenderPass.h"
egdaniel9cb63402016-06-23 08:37:05 -07009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkRect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/gpu/GrCaps.h"
Michael Ludwig1e632792020-05-21 12:45:31 -040012#include "src/gpu/GrCpuBuffer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrGpu.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/gpu/GrPrimitiveProcessor.h"
Robert Phillips901aff02019-10-08 12:32:56 -040015#include "src/gpu/GrProgramInfo.h"
Brian Salomon201cdbb2019-08-14 17:00:30 -040016#include "src/gpu/GrRenderTarget.h"
Michael Ludwig1e632792020-05-21 12:45:31 -040017#include "src/gpu/GrScissorState.h"
Chris Daltoneb694b72020-03-16 09:25:50 -060018#include "src/gpu/GrSimpleMesh.h"
Brian Salomon4cfae3b2020-07-23 10:33:24 -040019#include "src/gpu/GrTexture.h"
egdaniel9cb63402016-06-23 08:37:05 -070020
Chris Dalton2c3e1692020-03-20 12:32:55 -060021void GrOpsRenderPass::begin() {
22 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
23#ifdef SK_DEBUG
24 fScissorStatus = DynamicStateStatus::kDisabled;
25 fTextureBindingStatus = DynamicStateStatus::kDisabled;
26 fHasIndexBuffer = false;
27 fInstanceBufferStatus = DynamicStateStatus::kDisabled;
28 fVertexBufferStatus = DynamicStateStatus::kDisabled;
29#endif
30 this->onBegin();
31}
32
33void GrOpsRenderPass::end() {
34 this->onEnd();
Chris Daltonb60c8a22020-03-31 17:24:22 -060035 this->resetActiveBuffers();
Chris Dalton2c3e1692020-03-20 12:32:55 -060036}
37
Brian Salomon07bc9a22020-12-02 13:37:16 -050038void GrOpsRenderPass::clear(const GrScissorState& scissor, std::array<float, 4> color) {
Robert Phillips4912d902018-04-27 12:09:35 -040039 SkASSERT(fRenderTarget);
Michael Ludwigc39d0c82019-01-15 10:03:43 -050040 // A clear at this level will always be a true clear, so make sure clears were not supposed to
41 // be redirected to draws instead
42 SkASSERT(!this->gpu()->caps()->performColorClearsAsDraws());
Michael Ludwig1e632792020-05-21 12:45:31 -040043 SkASSERT(!scissor.enabled() || !this->gpu()->caps()->performPartialClearsAsDraws());
Chris Dalton4386ad12020-02-19 16:42:06 -070044 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
Michael Ludwig1e632792020-05-21 12:45:31 -040045 this->onClear(scissor, color);
egdaniel9cb63402016-06-23 08:37:05 -070046}
47
Michael Ludwig1e632792020-05-21 12:45:31 -040048void GrOpsRenderPass::clearStencilClip(const GrScissorState& scissor, bool insideStencilMask) {
Michael Ludwigc39d0c82019-01-15 10:03:43 -050049 // As above, make sure the stencil clear wasn't supposed to be a draw rect with stencil settings
50 SkASSERT(!this->gpu()->caps()->performStencilClearsAsDraws());
Michael Ludwig1e632792020-05-21 12:45:31 -040051 SkASSERT(!scissor.enabled() || !this->gpu()->caps()->performPartialClearsAsDraws());
Chris Dalton4386ad12020-02-19 16:42:06 -070052 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
Michael Ludwig1e632792020-05-21 12:45:31 -040053 this->onClearStencilClip(scissor, insideStencilMask);
egdaniel9cb63402016-06-23 08:37:05 -070054}
55
Chris Dalton4386ad12020-02-19 16:42:06 -070056void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
57 fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
58 this->onExecuteDrawable(std::move(drawable));
59}
Robert Phillips901aff02019-10-08 12:32:56 -040060
Chris Daltonaa0e45c2020-03-16 10:05:11 -060061void GrOpsRenderPass::bindPipeline(const GrProgramInfo& programInfo, const SkRect& drawBounds) {
Chris Daltonbca46e22017-05-15 11:03:26 -060062#ifdef SK_DEBUG
Chris Dalton56c09f02020-03-13 17:30:03 -060063 // Both the 'programInfo' and this renderPass have an origin. Since they come from the same
64 // place (i.e., the target renderTargetProxy) they had best agree.
65 SkASSERT(programInfo.origin() == fOrigin);
Chris Dalton4386ad12020-02-19 16:42:06 -070066 if (programInfo.primProc().hasInstanceAttributes()) {
Chris Daltona77cdee2020-04-03 14:50:43 -060067 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
Chris Dalton4386ad12020-02-19 16:42:06 -070068 }
69 if (programInfo.pipeline().usesConservativeRaster()) {
70 SkASSERT(this->gpu()->caps()->conservativeRasterSupport());
Chris Dalton4386ad12020-02-19 16:42:06 -070071 }
72 if (programInfo.pipeline().isWireframe()) {
73 SkASSERT(this->gpu()->caps()->wireframeSupport());
74 }
Chris Dalton3d28b6a2020-04-13 11:12:28 -060075 if (this->gpu()->caps()->twoSidedStencilRefsAndMasksMustMatch() &&
Chris Dalton1b6a43c2020-09-25 12:21:18 -060076 programInfo.isStencilEnabled()) {
77 const GrUserStencilSettings* stencil = programInfo.userStencilSettings();
Chris Dalton3d28b6a2020-04-13 11:12:28 -060078 if (stencil->isTwoSided(programInfo.pipeline().hasStencilClip())) {
79 SkASSERT(stencil->fCCWFace.fRef == stencil->fCWFace.fRef);
80 SkASSERT(stencil->fCCWFace.fTestMask == stencil->fCWFace.fTestMask);
81 SkASSERT(stencil->fCCWFace.fWriteMask == stencil->fCWFace.fWriteMask);
82 }
83 }
Chris Dalton4386ad12020-02-19 16:42:06 -070084 if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
85 SkASSERT(this->gpu()->caps()->shaderCaps()->tessellationSupport());
86 }
Robert Phillips2d8a95e2019-10-10 12:50:22 -040087 programInfo.checkAllInstantiated();
88 programInfo.checkMSAAAndMIPSAreResolved();
Robert Phillips12c46292019-04-23 07:36:17 -040089#endif
Robert Phillipsa91e0b72017-05-01 13:12:20 -040090
Chris Daltonb60c8a22020-03-31 17:24:22 -060091 this->resetActiveBuffers();
92
Robert Phillips901aff02019-10-08 12:32:56 -040093 if (programInfo.primProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
Chris Dalton4386ad12020-02-19 16:42:06 -070094 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
95 return;
egdaniel9cb63402016-06-23 08:37:05 -070096 }
Chris Dalton4386ad12020-02-19 16:42:06 -070097
98 if (!this->onBindPipeline(programInfo, drawBounds)) {
99 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
100 return;
101 }
Robert Phillips901aff02019-10-08 12:32:56 -0400102
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600103#ifdef SK_DEBUG
Robert Phillips901aff02019-10-08 12:32:56 -0400104 GrProcessor::CustomFeatures processorFeatures = programInfo.requestedFeatures();
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600105 if (GrProcessor::CustomFeatures::kSampleLocations & processorFeatures) {
106 // Verify we always have the same sample pattern key, regardless of graphics state.
Brian Salomonf7f54332020-07-28 09:23:35 -0400107 SkASSERT(this->gpu()->findOrAssignSamplePatternKey(fRenderTarget) ==
108 fRenderTarget->getSamplePatternKey());
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600109 }
Chris Dalton2e7ed262020-02-21 15:17:59 -0700110 fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
111 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
112 bool hasTextures = (programInfo.primProc().numTextureSamplers() > 0);
113 if (!hasTextures) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400114 programInfo.pipeline().visitProxies([&hasTextures](GrSurfaceProxy*, GrMipmapped) {
Chris Dalton2e7ed262020-02-21 15:17:59 -0700115 hasTextures = true;
116 });
117 }
118 fTextureBindingStatus = (hasTextures) ?
119 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
Chris Daltonded43702020-03-02 11:45:27 -0700120 fHasIndexBuffer = false;
121 fInstanceBufferStatus = (programInfo.primProc().hasInstanceAttributes()) ?
122 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
123 fVertexBufferStatus = (programInfo.primProc().hasVertexAttributes()) ?
124 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600125#endif
Chris Dalton4386ad12020-02-19 16:42:06 -0700126
127 fDrawPipelineStatus = DrawPipelineStatus::kOk;
Greg Danield358cbe2020-09-11 09:33:54 -0400128 fXferBarrierType = programInfo.pipeline().xferBarrierType(*this->gpu()->caps());
Chris Dalton2e7ed262020-02-21 15:17:59 -0700129}
130
131void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) {
132 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
133 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
134 return;
135 }
136 SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus);
137 this->onSetScissorRect(scissor);
138 SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured);
139}
140
Chris Daltondb20afc2020-03-05 12:13:53 -0700141void GrOpsRenderPass::bindTextures(const GrPrimitiveProcessor& primProc,
142 const GrSurfaceProxy* const primProcTextures[],
143 const GrPipeline& pipeline) {
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700144#ifdef SK_DEBUG
145 SkASSERT((primProc.numTextureSamplers() > 0) == SkToBool(primProcTextures));
146 for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
Chris Dalton3bf2f3a2020-03-17 11:48:23 -0600147 const auto& sampler = primProc.textureSampler(i);
148 const GrSurfaceProxy* proxy = primProcTextures[i];
149 SkASSERT(proxy);
150 SkASSERT(proxy->backendFormat() == sampler.backendFormat());
151 SkASSERT(proxy->backendFormat().textureType() == sampler.backendFormat().textureType());
152
153 const GrTexture* tex = proxy->peekTexture();
154 SkASSERT(tex);
Brian Salomone69b9ef2020-07-22 11:18:06 -0400155 if (sampler.samplerState().mipmapped() == GrMipmapped::kYes &&
Chris Dalton3bf2f3a2020-03-17 11:48:23 -0600156 (tex->width() != 1 || tex->height() != 1)) {
157 // There are some cases where we might be given a non-mipmapped texture with a mipmap
158 // filter. See skbug.com/7094.
Brian Salomon4cfae3b2020-07-23 10:33:24 -0400159 SkASSERT(tex->mipmapped() != GrMipmapped::kYes || !tex->mipmapsAreDirty());
Chris Dalton3bf2f3a2020-03-17 11:48:23 -0600160 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700161 }
162#endif
163
Chris Dalton2e7ed262020-02-21 15:17:59 -0700164 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
165 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
166 return;
167 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700168
Chris Dalton2e7ed262020-02-21 15:17:59 -0700169 // Don't assert on fTextureBindingStatus. onBindTextures() just turns into a no-op when there
170 // aren't any textures, and it's hard to tell from the GrPipeline whether there are any. For
171 // many clients it is easier to just always call this method.
Chris Daltondb20afc2020-03-05 12:13:53 -0700172 if (!this->onBindTextures(primProc, primProcTextures, pipeline)) {
Chris Dalton2e7ed262020-02-21 15:17:59 -0700173 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
174 return;
175 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700176
Chris Dalton2e7ed262020-02-21 15:17:59 -0700177 SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured);
Chris Dalton4386ad12020-02-19 16:42:06 -0700178}
179
Greg Daniel426274b2020-07-20 11:37:38 -0400180void GrOpsRenderPass::bindBuffers(sk_sp<const GrBuffer> indexBuffer,
181 sk_sp<const GrBuffer> instanceBuffer,
182 sk_sp<const GrBuffer> vertexBuffer,
183 GrPrimitiveRestart primRestart) {
Chris Daltonded43702020-03-02 11:45:27 -0700184 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
185 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
186 return;
187 }
188
189#ifdef SK_DEBUG
190 if (indexBuffer) {
191 fHasIndexBuffer = true;
192 }
193
194 SkASSERT((DynamicStateStatus::kDisabled == fInstanceBufferStatus) != SkToBool(instanceBuffer));
195 if (instanceBuffer) {
196 fInstanceBufferStatus = DynamicStateStatus::kConfigured;
197 }
198
199 SkASSERT((DynamicStateStatus::kDisabled == fVertexBufferStatus) != SkToBool(vertexBuffer));
200 if (vertexBuffer) {
201 fVertexBufferStatus = DynamicStateStatus::kConfigured;
202 }
203
204 if (GrPrimitiveRestart::kYes == primRestart) {
205 SkASSERT(this->gpu()->caps()->usePrimitiveRestart());
206 }
207#endif
208
Greg Daniel426274b2020-07-20 11:37:38 -0400209 this->onBindBuffers(std::move(indexBuffer), std::move(instanceBuffer), std::move(vertexBuffer),
210 primRestart);
Chris Daltonded43702020-03-02 11:45:27 -0700211}
212
Chris Dalton33db9fc2020-02-25 18:52:12 -0700213bool GrOpsRenderPass::prepareToDraw() {
Chris Dalton4386ad12020-02-19 16:42:06 -0700214 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
215 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
216 this->gpu()->stats()->incNumFailedDraws();
Chris Dalton33db9fc2020-02-25 18:52:12 -0700217 return false;
Chris Dalton4386ad12020-02-19 16:42:06 -0700218 }
Chris Dalton2e7ed262020-02-21 15:17:59 -0700219 SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus);
220 SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus);
Chris Dalton4386ad12020-02-19 16:42:06 -0700221
Chris Dalton2e7ed262020-02-21 15:17:59 -0700222 if (kNone_GrXferBarrierType != fXferBarrierType) {
223 this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType);
Chris Dalton4386ad12020-02-19 16:42:06 -0700224 }
Chris Dalton33db9fc2020-02-25 18:52:12 -0700225 return true;
226}
227
Chris Daltonded43702020-03-02 11:45:27 -0700228void GrOpsRenderPass::draw(int vertexCount, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700229 if (!this->prepareToDraw()) {
230 return;
231 }
Chris Daltonded43702020-03-02 11:45:27 -0700232 SkASSERT(!fHasIndexBuffer);
233 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
234 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
235 this->onDraw(vertexCount, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700236}
237
Chris Daltonded43702020-03-02 11:45:27 -0700238void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
239 uint16_t maxIndexValue, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700240 if (!this->prepareToDraw()) {
241 return;
242 }
Chris Daltonded43702020-03-02 11:45:27 -0700243 SkASSERT(fHasIndexBuffer);
244 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
245 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
246 this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700247}
248
Chris Daltonded43702020-03-02 11:45:27 -0700249void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount,
Chris Dalton33db9fc2020-02-25 18:52:12 -0700250 int baseVertex) {
Chris Daltona77cdee2020-04-03 14:50:43 -0600251 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
Chris Dalton33db9fc2020-02-25 18:52:12 -0700252 if (!this->prepareToDraw()) {
253 return;
254 }
Chris Daltonded43702020-03-02 11:45:27 -0700255 SkASSERT(!fHasIndexBuffer);
256 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
257 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
258 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700259}
260
Chris Daltonded43702020-03-02 11:45:27 -0700261void GrOpsRenderPass::drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
262 int baseInstance, int baseVertex) {
Chris Daltona77cdee2020-04-03 14:50:43 -0600263 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
Chris Dalton33db9fc2020-02-25 18:52:12 -0700264 if (!this->prepareToDraw()) {
265 return;
266 }
Chris Daltonded43702020-03-02 11:45:27 -0700267 SkASSERT(fHasIndexBuffer);
268 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
269 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
270 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
egdaniel9cb63402016-06-23 08:37:05 -0700271}
Chris Daltonbb768422020-03-12 12:13:29 -0600272
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600273void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
274 int drawCount) {
275 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
276 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
277 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
278 if (!this->prepareToDraw()) {
279 return;
280 }
281 SkASSERT(!fHasIndexBuffer);
282 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
283 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
284 if (!this->gpu()->caps()->nativeDrawIndirectSupport()) {
285 // Polyfill indirect draws with looping instanced calls.
286 SkASSERT(drawIndirectBuffer->isCpuBuffer());
287 auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
288 auto cmd = reinterpret_cast<const GrDrawIndirectCommand*>(
289 cpuIndirectBuffer->data() + bufferOffset);
290 auto end = cmd + drawCount;
291 for (; cmd != end; ++cmd) {
292 this->onDrawInstanced(cmd->fInstanceCount, cmd->fBaseInstance, cmd->fVertexCount,
293 cmd->fBaseVertex);
294 }
295 return;
296 }
297 this->onDrawIndirect(drawIndirectBuffer, bufferOffset, drawCount);
298}
299
300void GrOpsRenderPass::drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
301 int drawCount) {
302 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
303 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
304 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
305 if (!this->prepareToDraw()) {
306 return;
307 }
308 SkASSERT(fHasIndexBuffer);
309 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
310 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
311 if (!this->gpu()->caps()->nativeDrawIndirectSupport() ||
312 this->gpu()->caps()->nativeDrawIndexedIndirectIsBroken()) {
313 // Polyfill indexedIndirect draws with looping indexedInstanced calls.
314 SkASSERT(drawIndirectBuffer->isCpuBuffer());
315 auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
316 auto cmd = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
317 cpuIndirectBuffer->data() + bufferOffset);
318 auto end = cmd + drawCount;
319 for (; cmd != end; ++cmd) {
320 this->onDrawIndexedInstanced(cmd->fIndexCount, cmd->fBaseIndex, cmd->fInstanceCount,
321 cmd->fBaseInstance, cmd->fBaseVertex);
322 }
323 return;
324 }
325 this->onDrawIndexedIndirect(drawIndirectBuffer, bufferOffset, drawCount);
326}
327
Chris Daltonbb768422020-03-12 12:13:29 -0600328void GrOpsRenderPass::drawIndexPattern(int patternIndexCount, int patternRepeatCount,
329 int maxPatternRepetitionsInIndexBuffer,
330 int patternVertexCount, int baseVertex) {
331 int baseRepetition = 0;
332 while (baseRepetition < patternRepeatCount) {
333 int repeatCount = std::min(patternRepeatCount - baseRepetition,
334 maxPatternRepetitionsInIndexBuffer);
335 int drawIndexCount = repeatCount * patternIndexCount;
336 // A patterned index buffer must contain indices in the range [0..vertexCount].
337 int minIndexValue = 0;
338 int maxIndexValue = patternVertexCount * repeatCount - 1;
339 this->drawIndexed(drawIndexCount, 0, minIndexValue, maxIndexValue,
340 patternVertexCount * baseRepetition + baseVertex);
341 baseRepetition += repeatCount;
342 }
343}