1Name 2 3 NV_bindless_multi_draw_indirect 4 5Name Strings 6 7 GL_NV_bindless_multi_draw_indirect 8 9Contact 10 11 Christoph Kubisch, NVIDIA (ckubisch 'at' nvidia.com) 12 13Contributors 14 15 Jeff Bolz, NVIDIA 16 Piers Daniell, NVIDIA 17 Markus Tavenrath, NVIDIA 18 Eric Werness, NVIDIA 19 Vincent Zhang, NVIDIA 20 21Status 22 23 Complete 24 25Version 26 27 Last Modified Date: July 3rd, 2015 28 Revision: 3 29 30Number 31 32 OpenGL Extension #432 33 34Dependencies 35 36 NV_vertex_buffer_unified_memory is required. 37 38 OpenGL 4.3 or ARB_multi_draw_indirect is required. 39 40 The extension is written against the OpenGL 4.3 Specification, Core Profile. 41 42Overview 43 44 This extension combines NV_vertex_buffer_unified_memory and 45 ARB_multi_draw_indirect to allow the processing of multiple drawing 46 commands, whose vertex and index data can be sourced from arbitrary 47 buffer locations, by a single function call. 48 49 The NV_vertex_buffer_unified_memory extension provided a mechanism to 50 specify vertex attrib and element array locations using GPU addresses. 51 Prior to this extension, these addresses had to be set through explicit 52 function calls. Now the ability to set the pointer addresses indirectly 53 by extending the GL_ARB_draw_indirect mechanism has been added. 54 55 Combined with other "bindless" extensions, such as NV_bindless_texture and 56 NV_shader_buffer_load, it is now possible for the GPU to create draw 57 commands that source all resource inputs, which are common to change 58 frequently between draw calls from the GPU: vertex and index buffers, 59 samplers, images and other shader input data stored in buffers. 60 61 62New Procedures and Functions 63 64 void MultiDrawArraysIndirectBindlessNV(enum mode, 65 const void *indirect, 66 sizei drawCount, 67 sizei stride, 68 int vertexBufferCount); 69 70 void MultiDrawElementsIndirectBindlessNV(enum mode, 71 enum type, 72 const void *indirect, 73 sizei drawCount, 74 sizei stride, 75 int vertexBufferCount); 76 77New Tokens 78 79 None. 80 81Additions to Chapter 10 of the OpenGL 4.3 (Core) Specification (Vertex 82Specification and Drawing Commands) 83 84 Additions to Section 10.5, "Drawing Commands Using Vertex Arrays" 85 86 After the description of MultiDrawArraysIndirect and before the introduction of 87 DrawElementsOneInstance, insert the following on p.311: 88 89 The command 90 91 void MultiDrawArraysIndirectBindlessNV(enum mode, 92 const void *indirect, 93 sizei drawCount, 94 sizei stride, 95 int vertexBufferCount); 96 97 behaves similar to MultiDrawArraysIndirect, except that <indirect> is 98 treated as an array of <drawCount> DrawArraysIndirectBindlessCommandNV 99 structures. 100 101 It has the same effect as: 102 103 typedef struct { 104 GLuint index; 105 GLuint reserved; 106 GLuint64 address; 107 GLuint64 length; 108 } BindlessPtrNV; 109 110 typedef struct { 111 DrawArraysIndirectCommand cmd; 112 BindlessPtrNV vertexBuffers[]; 113 } DrawArraysIndirectBindlessCommandNV; 114 115 if (<mode> is invalid) 116 generate appropriate error 117 else { 118 GLuint64 vtxAddresses[MAX_VERTEX_ATTRIBS]; 119 GLsizeiptr vtxLengths[MAX_VERTEX_ATTRIBS]; 120 for (i = 0; i < MAX_VERTEX_ATTRIBS) { 121 GetIntegerui64i_vNV(VERTEX_ATTRIB_ARRAY_ADDRESS_NV,i,&vtxAddresses[i]); 122 GetInteger64i_v(VERTEX_ATTRIB_ARRAY_LENGTH_NV ,i,&vtxLengths[i]); 123 } 124 125 const ubyte * ptr = (const ubyte *)indirect; 126 for (i = 0; i < drawCount; i++) { 127 const DrawArraysIndirectBindlessCommandNV* cmdNV = 128 (DrawArraysIndirectBindlessCommandNV*)ptr; 129 130 if ( cmdNV->cmd.instanceCount != 0 ){ 131 for (n = 0; n < vertexBufferCount; n++){ 132 BufferAddressRangeNV(VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 133 cmdNV->vertexBuffers[n].index 134 cmdNV->vertexBuffers[n].address, 135 cmdNV->vertexBuffers[n].length); 136 } 137 138 DrawArraysIndirect(mode, 139 (DrawArraysIndirectCommand*)ptr); 140 } 141 if (stride == 0) 142 { 143 ptr += sizeof(DrawArraysIndirectCommand) + 144 (sizeof(BindlessPtrNV) * vertexBufferCount); 145 } else 146 { 147 ptr += stride; 148 } 149 } 150 151 for (i = 0; i < MAX_VERTEX_ATTRIBS) { 152 BufferAddressRangeNV(VERTEX_ATTRIB_ARRAY_ADDRESS_NV,i,vtxAddresses[i],vtxLengths[i]); 153 } 154 } 155 156 <drawCount> must be positive, otherwise an INVALID_VALUE error will be 157 generated. 158 159 After the description of MultiDrawElementsIndirect and before the introduction 160 of MultiDrawElementsBaseVertex, insert the following on p.316: 161 162 The command 163 164 void MultiDrawElementsIndirectBindlessNV(enum mode, 165 enum type, 166 const void *indirect, 167 sizei drawCount, 168 sizei stride, 169 int vertexBufferCount); 170 171 behaves similar to MultiDrawElementsIndirect, except that <indirect> is 172 treated as an array of <drawCount> DrawElementsIndirectBindlessCommandNV 173 structures. 174 175 It has the same effect as: 176 177 typedef struct { 178 GLuint index; 179 GLuint reserved; 180 GLuint64 address; 181 GLuint64 length; 182 } BindlessPtrNV; 183 184 typedef struct { 185 DrawElementsIndirectCommand cmd; 186 GLuint reserved; 187 BindlessPtrNV indexBuffer; 188 BindlessPtrNV vertexBuffers[]; 189 } DrawElementsIndirectBindlessCommandNV; 190 191 if (<mode> or <type> is invalid) 192 generate appropriate error 193 else { 194 GLuint64 idxAddress; 195 GLsizeiptr idxLength; 196 GetIntegerui64vNV(ELEMENT_ARRAY_ADDRESS_NV,&idxAddress); 197 GetInteger64v(ELEMENT_ARRAY_LENGTH_NV,&idxLength); 198 199 GLuint64 vtxAddresses[MAX_VERTEX_ATTRIBS]; 200 GLsizeiptr vtxLengths[MAX_VERTEX_ATTRIBS]; 201 for (i = 0; i < MAX_VERTEX_ATTRIBS) { 202 GetIntegerui64i_vNV(VERTEX_ATTRIB_ARRAY_ADDRESS_NV,i,&vtxAddresses[i]); 203 GetInteger64i_v(VERTEX_ATTRIB_ARRAY_LENGTH_NV ,i,&vtxLengths[i]); 204 } 205 206 const ubyte * ptr = (const ubyte *)indirect; 207 for (i = 0; i < primcount; i++) { 208 const DrawElementsIndirectBindlessCommandNV* cmdNV = 209 (DrawElementsIndirectBindlessCommandNV*)ptr; 210 211 if ( cmdNV->cmd.instanceCount != 0 ) { 212 BufferAddressRangeNV(ELEMENT_ARRAY_ADDRESS_NV, 213 0, 214 cmdNV->indexBuffer.address, 215 cmdNV->indexBuffer.length); 216 217 for (n = 0; n < vertexBufferCount; n++){ 218 BufferAddressRangeNV(VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 219 cmdNV->vertexBuffers[n].index 220 cmdNV->vertexBuffers[n].address, 221 cmdNV->vertexBuffers[n].length); 222 } 223 224 DrawElementsIndirect(mode, 225 type, 226 (DrawElementsIndirectCommand*)ptr); 227 } 228 229 if (stride == 0) 230 { 231 ptr += sizeof(DrawElementsIndirectCommand) + 232 sizeof(GLuint) + 233 sizeof(BindlessPtrNV) + 234 (sizeof(BindlessPtrNV) * vertexBufferCount); 235 } else 236 { 237 ptr += stride; 238 } 239 } 240 241 BufferAddressRangeNV(ELEMENT_ARRAY_ADDRESS_NV,0,idxAddress,idxLengths); 242 for (i = 0; i < MAX_VERTEX_ATTRIBS) { 243 BufferAddressRangeNV(VERTEX_ATTRIB_ARRAY_ADDRESS_NV,i,vtxAddresses[i],vtxLengths[i]); 244 } 245 } 246 247 Modifications to Section 10.3.10 (p. 305) "Indirect Commands in Buffer Objects" 248 249 Modify both instances of "DrawArraysIndirect, DrawElementsIndirect, 250 MultiDrawArraysIndirect and MultiDrawElementsIndirect" on 251 p. 305 to read "DrawArraysIndirect, DrawElementsIndirect, 252 MultiDrawArraysIndirect, MultiDrawElementsIndirect, 253 MultiDrawArraysIndirectBindlessNV and MultiDrawElementsIndirectBindlessNV". 254 255 256Additions to the AGL/GLX/WGL Specifications 257 258 None. 259 260GLX Protocol 261 262 None. 263 264Errors 265 266 INVALID_VALUE is generated by MultiDrawArraysIndirectBindlessNV or 267 MultiDrawElementsIndirectBindlessNV if <drawCount> is negative. 268 269 INVALID_VALUE is generated by MultiDrawArraysIndirectBindlessNV or 270 MultiDrawElementsIndirectBindlessNV if <stride> is not a multipe of eight. 271 272 INVALID_OPERATION is generated by MultiDrawArraysIndirectBindlessNV or 273 MultiDrawElementsIndirectBindlessNV if the 274 VERTEX_ATTRIB_ARRAY_UNIFIED_NV client state is not enabled. 275 276 INVALID_OPERATION is generated by MultiDrawElementsIndirectBindlessNV 277 if the ELEMENT_ARRAY_UNIFIED_NV client state is not enabled. 278 279New State 280 281 None. 282 283New Implementation Dependent State 284 285 None. 286 287Issues 288 289 1) BufferAddressRangeNV is defined to take GLsizeiptr as length. 290 Should the length parameter inside the indirect structure be cast 291 to GLsizeiptr when passed as argument? 292 293 RESOLVED: When the indirect buffer is stored in host memory, the cast 294 should be performed, otherwise, 64-bit should be assumed. 295 296 2) BufferAddressRangeNV also covered fixed function vertex state, should 297 this be exposed in this extension? 298 299 NO, the named attributes aren't necessary, as it is very likely that 300 shaders are used to also handle the parameters of individual drawcalls. 301 For fixed function shading the interleaving of related state changes 302 with drawcalls would already be efficiently handled by regular 303 MultiDraw or NV_vertex_buffer_unified_memory functionality. 304 305 3) In which state should the vertex/index pointers be left after the 306 execution of the command? 307 308 RESOLVED: All pointers should be reset to what was last 309 specified by the client side using BufferAddressRangeNV. 310 311 4) How does this extension relate to the newer NV_command_list? 312 313 NV_command_list provides a more flexible draw indirect mechnanism. It 314 can be more efficient if there are redundancies in the vertex and index 315 buffer addresses, as it allows specifying addresses and drawcalls with 316 different frequencies in the command stream. 317 318Revision History 319 320 Rev. Date Author Changes 321 ---- -------- -------- ----------------------------------------- 322 1 ckubisch Internal revisions 323 2 1/5/2015 ckubisch bugfix, remove of "reserved" in 324 DrawArraysIndirectBindlessCommandNV 325 added reference to NV_command_list 326 3 7/3/2015 ckubisch bugfix, wrong math used in the "if (stride == 0)" 327 pointer advancing. GLsizeiptr for length instead of 328 GLuint64