blob: cd329dec0e49581fd1ff948e539ebe225f18ee9b [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
Michael Ludwig1e632792020-05-21 12:45:31 -040038void GrOpsRenderPass::clear(const GrScissorState& scissor, const SkPMColor4f& 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());
71 // Conservative raster, by default, only supports triangles. Implementations can
72 // optionally indicate that they also support points and lines, but we don't currently
73 // query or track that info.
74 SkASSERT(GrIsPrimTypeTris(programInfo.primitiveType()));
75 }
76 if (programInfo.pipeline().isWireframe()) {
77 SkASSERT(this->gpu()->caps()->wireframeSupport());
78 }
Chris Dalton3d28b6a2020-04-13 11:12:28 -060079 if (this->gpu()->caps()->twoSidedStencilRefsAndMasksMustMatch() &&
80 programInfo.pipeline().isStencilEnabled()) {
81 const GrUserStencilSettings* stencil = programInfo.pipeline().getUserStencil();
82 if (stencil->isTwoSided(programInfo.pipeline().hasStencilClip())) {
83 SkASSERT(stencil->fCCWFace.fRef == stencil->fCWFace.fRef);
84 SkASSERT(stencil->fCCWFace.fTestMask == stencil->fCWFace.fTestMask);
85 SkASSERT(stencil->fCCWFace.fWriteMask == stencil->fCWFace.fWriteMask);
86 }
87 }
Chris Dalton4386ad12020-02-19 16:42:06 -070088 if (GrPrimitiveType::kPatches == programInfo.primitiveType()) {
89 SkASSERT(this->gpu()->caps()->shaderCaps()->tessellationSupport());
90 }
Robert Phillips2d8a95e2019-10-10 12:50:22 -040091 programInfo.checkAllInstantiated();
92 programInfo.checkMSAAAndMIPSAreResolved();
Robert Phillips12c46292019-04-23 07:36:17 -040093#endif
Robert Phillipsa91e0b72017-05-01 13:12:20 -040094
Chris Daltonb60c8a22020-03-31 17:24:22 -060095 this->resetActiveBuffers();
96
Robert Phillips901aff02019-10-08 12:32:56 -040097 if (programInfo.primProc().numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
Chris Dalton4386ad12020-02-19 16:42:06 -070098 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
99 return;
egdaniel9cb63402016-06-23 08:37:05 -0700100 }
Chris Dalton4386ad12020-02-19 16:42:06 -0700101
102 if (!this->onBindPipeline(programInfo, drawBounds)) {
103 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
104 return;
105 }
Robert Phillips901aff02019-10-08 12:32:56 -0400106
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600107#ifdef SK_DEBUG
Robert Phillips901aff02019-10-08 12:32:56 -0400108 GrProcessor::CustomFeatures processorFeatures = programInfo.requestedFeatures();
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600109 if (GrProcessor::CustomFeatures::kSampleLocations & processorFeatures) {
110 // Verify we always have the same sample pattern key, regardless of graphics state.
Brian Salomonf7f54332020-07-28 09:23:35 -0400111 SkASSERT(this->gpu()->findOrAssignSamplePatternKey(fRenderTarget) ==
112 fRenderTarget->getSamplePatternKey());
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600113 }
Chris Dalton2e7ed262020-02-21 15:17:59 -0700114 fScissorStatus = (programInfo.pipeline().isScissorTestEnabled()) ?
115 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
116 bool hasTextures = (programInfo.primProc().numTextureSamplers() > 0);
117 if (!hasTextures) {
Brian Salomon7e67dca2020-07-21 09:27:25 -0400118 programInfo.pipeline().visitProxies([&hasTextures](GrSurfaceProxy*, GrMipmapped) {
Chris Dalton2e7ed262020-02-21 15:17:59 -0700119 hasTextures = true;
120 });
121 }
122 fTextureBindingStatus = (hasTextures) ?
123 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
Chris Daltonded43702020-03-02 11:45:27 -0700124 fHasIndexBuffer = false;
125 fInstanceBufferStatus = (programInfo.primProc().hasInstanceAttributes()) ?
126 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
127 fVertexBufferStatus = (programInfo.primProc().hasVertexAttributes()) ?
128 DynamicStateStatus::kUninitialized : DynamicStateStatus::kDisabled;
Chris Dalton8c4cafd2019-04-15 19:14:36 -0600129#endif
Chris Dalton4386ad12020-02-19 16:42:06 -0700130
131 fDrawPipelineStatus = DrawPipelineStatus::kOk;
Greg Danield358cbe2020-09-11 09:33:54 -0400132 fXferBarrierType = programInfo.pipeline().xferBarrierType(*this->gpu()->caps());
Chris Dalton2e7ed262020-02-21 15:17:59 -0700133}
134
135void GrOpsRenderPass::setScissorRect(const SkIRect& scissor) {
136 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
137 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
138 return;
139 }
140 SkASSERT(DynamicStateStatus::kDisabled != fScissorStatus);
141 this->onSetScissorRect(scissor);
142 SkDEBUGCODE(fScissorStatus = DynamicStateStatus::kConfigured);
143}
144
Chris Daltondb20afc2020-03-05 12:13:53 -0700145void GrOpsRenderPass::bindTextures(const GrPrimitiveProcessor& primProc,
146 const GrSurfaceProxy* const primProcTextures[],
147 const GrPipeline& pipeline) {
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700148#ifdef SK_DEBUG
149 SkASSERT((primProc.numTextureSamplers() > 0) == SkToBool(primProcTextures));
150 for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
Chris Dalton3bf2f3a2020-03-17 11:48:23 -0600151 const auto& sampler = primProc.textureSampler(i);
152 const GrSurfaceProxy* proxy = primProcTextures[i];
153 SkASSERT(proxy);
154 SkASSERT(proxy->backendFormat() == sampler.backendFormat());
155 SkASSERT(proxy->backendFormat().textureType() == sampler.backendFormat().textureType());
156
157 const GrTexture* tex = proxy->peekTexture();
158 SkASSERT(tex);
Brian Salomone69b9ef2020-07-22 11:18:06 -0400159 if (sampler.samplerState().mipmapped() == GrMipmapped::kYes &&
Chris Dalton3bf2f3a2020-03-17 11:48:23 -0600160 (tex->width() != 1 || tex->height() != 1)) {
161 // There are some cases where we might be given a non-mipmapped texture with a mipmap
162 // filter. See skbug.com/7094.
Brian Salomon4cfae3b2020-07-23 10:33:24 -0400163 SkASSERT(tex->mipmapped() != GrMipmapped::kYes || !tex->mipmapsAreDirty());
Chris Dalton3bf2f3a2020-03-17 11:48:23 -0600164 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700165 }
166#endif
167
Chris Dalton2e7ed262020-02-21 15:17:59 -0700168 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
169 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
170 return;
171 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700172
Chris Dalton2e7ed262020-02-21 15:17:59 -0700173 // Don't assert on fTextureBindingStatus. onBindTextures() just turns into a no-op when there
174 // aren't any textures, and it's hard to tell from the GrPipeline whether there are any. For
175 // many clients it is easier to just always call this method.
Chris Daltondb20afc2020-03-05 12:13:53 -0700176 if (!this->onBindTextures(primProc, primProcTextures, pipeline)) {
Chris Dalton2e7ed262020-02-21 15:17:59 -0700177 fDrawPipelineStatus = DrawPipelineStatus::kFailedToBind;
178 return;
179 }
Chris Dalton1b1b0d52020-03-03 12:00:59 -0700180
Chris Dalton2e7ed262020-02-21 15:17:59 -0700181 SkDEBUGCODE(fTextureBindingStatus = DynamicStateStatus::kConfigured);
Chris Dalton4386ad12020-02-19 16:42:06 -0700182}
183
Greg Daniel426274b2020-07-20 11:37:38 -0400184void GrOpsRenderPass::bindBuffers(sk_sp<const GrBuffer> indexBuffer,
185 sk_sp<const GrBuffer> instanceBuffer,
186 sk_sp<const GrBuffer> vertexBuffer,
187 GrPrimitiveRestart primRestart) {
Chris Daltonded43702020-03-02 11:45:27 -0700188 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
189 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
190 return;
191 }
192
193#ifdef SK_DEBUG
194 if (indexBuffer) {
195 fHasIndexBuffer = true;
196 }
197
198 SkASSERT((DynamicStateStatus::kDisabled == fInstanceBufferStatus) != SkToBool(instanceBuffer));
199 if (instanceBuffer) {
200 fInstanceBufferStatus = DynamicStateStatus::kConfigured;
201 }
202
203 SkASSERT((DynamicStateStatus::kDisabled == fVertexBufferStatus) != SkToBool(vertexBuffer));
204 if (vertexBuffer) {
205 fVertexBufferStatus = DynamicStateStatus::kConfigured;
206 }
207
208 if (GrPrimitiveRestart::kYes == primRestart) {
209 SkASSERT(this->gpu()->caps()->usePrimitiveRestart());
210 }
211#endif
212
Greg Daniel426274b2020-07-20 11:37:38 -0400213 this->onBindBuffers(std::move(indexBuffer), std::move(instanceBuffer), std::move(vertexBuffer),
214 primRestart);
Chris Daltonded43702020-03-02 11:45:27 -0700215}
216
Chris Dalton33db9fc2020-02-25 18:52:12 -0700217bool GrOpsRenderPass::prepareToDraw() {
Chris Dalton4386ad12020-02-19 16:42:06 -0700218 if (DrawPipelineStatus::kOk != fDrawPipelineStatus) {
219 SkASSERT(DrawPipelineStatus::kNotConfigured != fDrawPipelineStatus);
220 this->gpu()->stats()->incNumFailedDraws();
Chris Dalton33db9fc2020-02-25 18:52:12 -0700221 return false;
Chris Dalton4386ad12020-02-19 16:42:06 -0700222 }
Chris Dalton2e7ed262020-02-21 15:17:59 -0700223 SkASSERT(DynamicStateStatus::kUninitialized != fScissorStatus);
224 SkASSERT(DynamicStateStatus::kUninitialized != fTextureBindingStatus);
Chris Dalton4386ad12020-02-19 16:42:06 -0700225
Chris Dalton2e7ed262020-02-21 15:17:59 -0700226 if (kNone_GrXferBarrierType != fXferBarrierType) {
227 this->gpu()->xferBarrier(fRenderTarget, fXferBarrierType);
Chris Dalton4386ad12020-02-19 16:42:06 -0700228 }
Chris Dalton33db9fc2020-02-25 18:52:12 -0700229 return true;
230}
231
Chris Daltonded43702020-03-02 11:45:27 -0700232void GrOpsRenderPass::draw(int vertexCount, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700233 if (!this->prepareToDraw()) {
234 return;
235 }
Chris Daltonded43702020-03-02 11:45:27 -0700236 SkASSERT(!fHasIndexBuffer);
237 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
238 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
239 this->onDraw(vertexCount, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700240}
241
Chris Daltonded43702020-03-02 11:45:27 -0700242void GrOpsRenderPass::drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
243 uint16_t maxIndexValue, int baseVertex) {
Chris Dalton33db9fc2020-02-25 18:52:12 -0700244 if (!this->prepareToDraw()) {
245 return;
246 }
Chris Daltonded43702020-03-02 11:45:27 -0700247 SkASSERT(fHasIndexBuffer);
248 SkASSERT(DynamicStateStatus::kConfigured != fInstanceBufferStatus);
249 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
250 this->onDrawIndexed(indexCount, baseIndex, minIndexValue, maxIndexValue, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700251}
252
Chris Daltonded43702020-03-02 11:45:27 -0700253void GrOpsRenderPass::drawInstanced(int instanceCount, int baseInstance, int vertexCount,
Chris Dalton33db9fc2020-02-25 18:52:12 -0700254 int baseVertex) {
Chris Daltona77cdee2020-04-03 14:50:43 -0600255 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
Chris Dalton33db9fc2020-02-25 18:52:12 -0700256 if (!this->prepareToDraw()) {
257 return;
258 }
Chris Daltonded43702020-03-02 11:45:27 -0700259 SkASSERT(!fHasIndexBuffer);
260 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
261 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
262 this->onDrawInstanced(instanceCount, baseInstance, vertexCount, baseVertex);
Chris Dalton33db9fc2020-02-25 18:52:12 -0700263}
264
Chris Daltonded43702020-03-02 11:45:27 -0700265void GrOpsRenderPass::drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
266 int baseInstance, int baseVertex) {
Chris Daltona77cdee2020-04-03 14:50:43 -0600267 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
Chris Dalton33db9fc2020-02-25 18:52:12 -0700268 if (!this->prepareToDraw()) {
269 return;
270 }
Chris Daltonded43702020-03-02 11:45:27 -0700271 SkASSERT(fHasIndexBuffer);
272 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
273 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
274 this->onDrawIndexedInstanced(indexCount, baseIndex, instanceCount, baseInstance, baseVertex);
egdaniel9cb63402016-06-23 08:37:05 -0700275}
Chris Daltonbb768422020-03-12 12:13:29 -0600276
Chris Dalton03fdf6a2020-04-07 12:31:59 -0600277void GrOpsRenderPass::drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
278 int drawCount) {
279 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
280 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
281 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
282 if (!this->prepareToDraw()) {
283 return;
284 }
285 SkASSERT(!fHasIndexBuffer);
286 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
287 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
288 if (!this->gpu()->caps()->nativeDrawIndirectSupport()) {
289 // Polyfill indirect draws with looping instanced calls.
290 SkASSERT(drawIndirectBuffer->isCpuBuffer());
291 auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
292 auto cmd = reinterpret_cast<const GrDrawIndirectCommand*>(
293 cpuIndirectBuffer->data() + bufferOffset);
294 auto end = cmd + drawCount;
295 for (; cmd != end; ++cmd) {
296 this->onDrawInstanced(cmd->fInstanceCount, cmd->fBaseInstance, cmd->fVertexCount,
297 cmd->fBaseVertex);
298 }
299 return;
300 }
301 this->onDrawIndirect(drawIndirectBuffer, bufferOffset, drawCount);
302}
303
304void GrOpsRenderPass::drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
305 int drawCount) {
306 SkASSERT(this->gpu()->caps()->drawInstancedSupport());
307 SkASSERT(drawIndirectBuffer->isCpuBuffer() ||
308 !static_cast<const GrGpuBuffer*>(drawIndirectBuffer)->isMapped());
309 if (!this->prepareToDraw()) {
310 return;
311 }
312 SkASSERT(fHasIndexBuffer);
313 SkASSERT(DynamicStateStatus::kUninitialized != fInstanceBufferStatus);
314 SkASSERT(DynamicStateStatus::kUninitialized != fVertexBufferStatus);
315 if (!this->gpu()->caps()->nativeDrawIndirectSupport() ||
316 this->gpu()->caps()->nativeDrawIndexedIndirectIsBroken()) {
317 // Polyfill indexedIndirect draws with looping indexedInstanced calls.
318 SkASSERT(drawIndirectBuffer->isCpuBuffer());
319 auto cpuIndirectBuffer = static_cast<const GrCpuBuffer*>(drawIndirectBuffer);
320 auto cmd = reinterpret_cast<const GrDrawIndexedIndirectCommand*>(
321 cpuIndirectBuffer->data() + bufferOffset);
322 auto end = cmd + drawCount;
323 for (; cmd != end; ++cmd) {
324 this->onDrawIndexedInstanced(cmd->fIndexCount, cmd->fBaseIndex, cmd->fInstanceCount,
325 cmd->fBaseInstance, cmd->fBaseVertex);
326 }
327 return;
328 }
329 this->onDrawIndexedIndirect(drawIndirectBuffer, bufferOffset, drawCount);
330}
331
Chris Daltonbb768422020-03-12 12:13:29 -0600332void GrOpsRenderPass::drawIndexPattern(int patternIndexCount, int patternRepeatCount,
333 int maxPatternRepetitionsInIndexBuffer,
334 int patternVertexCount, int baseVertex) {
335 int baseRepetition = 0;
336 while (baseRepetition < patternRepeatCount) {
337 int repeatCount = std::min(patternRepeatCount - baseRepetition,
338 maxPatternRepetitionsInIndexBuffer);
339 int drawIndexCount = repeatCount * patternIndexCount;
340 // A patterned index buffer must contain indices in the range [0..vertexCount].
341 int minIndexValue = 0;
342 int maxIndexValue = patternVertexCount * repeatCount - 1;
343 this->drawIndexed(drawIndexCount, 0, minIndexValue, maxIndexValue,
344 patternVertexCount * baseRepetition + baseVertex);
345 baseRepetition += repeatCount;
346 }
347}