1export const description = ` 2indexed draws validation tests. 3`; 4 5import { params, poptions, pbool } from '../../../../../common/framework/params_builder.js'; 6import { makeTestGroup } from '../../../../../common/framework/test_group.js'; 7 8import { ValidationTest } from './../../validation_test.js'; 9 10class F extends ValidationTest { 11 createIndexBuffer(): GPUBuffer { 12 const indexArray = new Uint32Array([0, 1, 2, 3, 1, 2]); 13 14 const indexBuffer = this.device.createBuffer({ 15 mappedAtCreation: true, 16 size: indexArray.byteLength, 17 usage: GPUBufferUsage.INDEX, 18 }); 19 new Uint32Array(indexBuffer.getMappedRange()).set(indexArray); 20 indexBuffer.unmap(); 21 22 return indexBuffer; 23 } 24 25 createRenderPipeline(): GPURenderPipeline { 26 const vertexModule = this.makeShaderModule('vertex', { 27 glsl: ` 28 #version 450 29 void main() { 30 gl_Position = vec4(0.0, 0.0, 0.0, 1.0); 31 } 32 `, 33 }); 34 35 const fragmentModule = this.makeShaderModule('fragment', { 36 glsl: ` 37 #version 450 38 layout(location = 0) out vec4 fragColor; 39 void main() { 40 fragColor = vec4(0.0, 1.0, 0.0, 1.0); 41 } 42 `, 43 }); 44 45 return this.device.createRenderPipeline({ 46 layout: this.device.createPipelineLayout({ bindGroupLayouts: [] }), 47 vertexStage: { module: vertexModule, entryPoint: 'main' }, 48 fragmentStage: { module: fragmentModule, entryPoint: 'main' }, 49 primitiveTopology: 'triangle-strip', 50 colorStates: [{ format: 'rgba8unorm' }], 51 }); 52 } 53 54 beginRenderPass(encoder: GPUCommandEncoder) { 55 const colorAttachment = this.device.createTexture({ 56 format: 'rgba8unorm', 57 size: { width: 1, height: 1, depth: 1 }, 58 usage: GPUTextureUsage.OUTPUT_ATTACHMENT, 59 }); 60 61 return encoder.beginRenderPass({ 62 colorAttachments: [ 63 { 64 attachment: colorAttachment.createView(), 65 loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }, 66 storeOp: 'store', 67 }, 68 ], 69 }); 70 } 71 72 drawIndexed( 73 indexCount: number, 74 instanceCount: number, 75 firstIndex: number, 76 baseVertex: number, 77 firstInstance: number 78 ) { 79 const indexBuffer = this.createIndexBuffer(); 80 81 const pipeline = this.createRenderPipeline(); 82 83 const encoder = this.device.createCommandEncoder(); 84 const pass = this.beginRenderPass(encoder); 85 pass.setPipeline(pipeline); 86 pass.setIndexBuffer(indexBuffer); 87 pass.drawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance); 88 pass.endPass(); 89 90 this.device.defaultQueue.submit([encoder.finish()]); 91 } 92 93 drawIndexedIndirect(bufferArray: Uint32Array, indirectOffset: number) { 94 const indirectBuffer = this.device.createBuffer({ 95 mappedAtCreation: true, 96 size: bufferArray.byteLength, 97 usage: GPUBufferUsage.INDIRECT, 98 }); 99 new Uint32Array(indirectBuffer.getMappedRange()).set(bufferArray); 100 indirectBuffer.unmap(); 101 102 const indexBuffer = this.createIndexBuffer(); 103 104 const pipeline = this.createRenderPipeline(); 105 106 const encoder = this.device.createCommandEncoder(); 107 const pass = this.beginRenderPass(encoder); 108 pass.setPipeline(pipeline); 109 pass.setIndexBuffer(indexBuffer, 0); 110 pass.drawIndexedIndirect(indirectBuffer, indirectOffset); 111 pass.endPass(); 112 113 this.device.defaultQueue.submit([encoder.finish()]); 114 } 115} 116 117export const g = makeTestGroup(F); 118 119g.test('out_of_bounds') 120 .params( 121 params() 122 .combine(pbool('indirect')) // indirect drawIndexed 123 .combine([ 124 { indexCount: 6, firstIndex: 1 }, // indexCount + firstIndex out of bound 125 { indexCount: 6, firstIndex: 6 }, // only firstIndex out of bound 126 { indexCount: 6, firstIndex: 10000 }, // firstIndex much larger than the bound 127 { indexCount: 7, firstIndex: 0 }, // only indexCount out of bound 128 { indexCount: 10000, firstIndex: 0 }, // indexCount much larger than the bound 129 ] as const) 130 .combine(poptions('instanceCount', [1, 10000])) // normal and large instanceCount 131 ) 132 .fn(t => { 133 const { indirect, indexCount, firstIndex, instanceCount } = t.params; 134 135 if (indirect) { 136 t.drawIndexedIndirect(new Uint32Array([indexCount, instanceCount, firstIndex, 0, 0]), 0); 137 } else { 138 t.drawIndexed(indexCount, instanceCount, firstIndex, 0, 0); 139 } 140 }); 141