Prechádzať zdrojové kódy

Add support for indirect draw with indirect count (#2925)

* Add indirect draw with indirect count (BGFX_CAPS_DRAW_INDIRECT_COUNT)

* Update bindings

* VK: Add support for BGFX_CAPS_DRAW_INDIRECT_COUNT

* D3D12: Add support for BGFX_CAPS_DRAW_INDIRECT_COUNT

* GL: Add support for BGFX_CAPS_DRAW_INDIRECT_COUNT

* 48-drawindirect: Use BGFX_CAPS_DRAW_INDIRECT_COUNT if available

* 48-drawindirect: Update shaders
pezcode 3 rokov pred
rodič
commit
ba467be036

+ 47 - 2
bindings/bf/bgfx.bf

@@ -1152,6 +1152,11 @@ public static class bgfx
 		/// </summary>
 		ViewportLayerArray     = 0x0000000010000000,
 	
+		/// <summary>
+		/// Draw indirect with indirect count is supported.
+		/// </summary>
+		DrawIndirectCount      = 0x0000000020000000,
+	
 		/// <summary>
 		/// All texture compare modes are supported.
 		/// </summary>
@@ -3901,19 +3906,39 @@ public static class bgfx
 	/// <summary>
 	/// Submit primitive for rendering with index and instance data info from
 	/// indirect buffer.
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 	/// </summary>
 	///
 	/// <param name="_id">View id.</param>
 	/// <param name="_program">Program.</param>
 	/// <param name="_indirectHandle">Indirect buffer.</param>
 	/// <param name="_start">First element in indirect buffer.</param>
-	/// <param name="_num">Number of dispatches.</param>
+	/// <param name="_num">Number of draws.</param>
 	/// <param name="_depth">Depth for sorting.</param>
 	/// <param name="_flags">Discard or preserve states. See `BGFX_DISCARD_*`.</param>
 	///
 	[LinkName("bgfx_encoder_submit_indirect")]
 	public static extern void encoder_submit_indirect(Encoder* _this, ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16 _start, uint16 _num, uint32 _depth, uint8 _flags);
 	
+	/// <summary>
+	/// Submit primitive for rendering with index and instance data info and
+	/// draw count from indirect buffers.
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+	/// </summary>
+	///
+	/// <param name="_id">View id.</param>
+	/// <param name="_program">Program.</param>
+	/// <param name="_indirectHandle">Indirect buffer.</param>
+	/// <param name="_start">First element in indirect buffer.</param>
+	/// <param name="_numHandle">Buffer for number of draws. Must be   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.</param>
+	/// <param name="_numIndex">Element in number buffer.</param>
+	/// <param name="_numMax">Max number of draws.</param>
+	/// <param name="_depth">Depth for sorting.</param>
+	/// <param name="_flags">Discard or preserve states. See `BGFX_DISCARD_*`.</param>
+	///
+	[LinkName("bgfx_encoder_submit_indirect_count")]
+	public static extern void encoder_submit_indirect_count(Encoder* _this, ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16 _start, IndexBufferHandle _numHandle, uint32 _numIndex, uint16 _numMax, uint32 _depth, uint8 _flags);
+	
 	/// <summary>
 	/// Set compute index buffer.
 	/// </summary>
@@ -4457,19 +4482,39 @@ public static class bgfx
 	/// <summary>
 	/// Submit primitive for rendering with index and instance data info from
 	/// indirect buffer.
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 	/// </summary>
 	///
 	/// <param name="_id">View id.</param>
 	/// <param name="_program">Program.</param>
 	/// <param name="_indirectHandle">Indirect buffer.</param>
 	/// <param name="_start">First element in indirect buffer.</param>
-	/// <param name="_num">Number of dispatches.</param>
+	/// <param name="_num">Number of draws.</param>
 	/// <param name="_depth">Depth for sorting.</param>
 	/// <param name="_flags">Which states to discard for next draw. See `BGFX_DISCARD_*`.</param>
 	///
 	[LinkName("bgfx_submit_indirect")]
 	public static extern void submit_indirect(ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16 _start, uint16 _num, uint32 _depth, uint8 _flags);
 	
+	/// <summary>
+	/// Submit primitive for rendering with index and instance data info and
+	/// draw count from indirect buffers.
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+	/// </summary>
+	///
+	/// <param name="_id">View id.</param>
+	/// <param name="_program">Program.</param>
+	/// <param name="_indirectHandle">Indirect buffer.</param>
+	/// <param name="_start">First element in indirect buffer.</param>
+	/// <param name="_numHandle">Buffer for number of draws. Must be   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.</param>
+	/// <param name="_numIndex">Element in number buffer.</param>
+	/// <param name="_numMax">Max number of draws.</param>
+	/// <param name="_depth">Depth for sorting.</param>
+	/// <param name="_flags">Which states to discard for next draw. See `BGFX_DISCARD_*`.</param>
+	///
+	[LinkName("bgfx_submit_indirect_count")]
+	public static extern void submit_indirect_count(ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16 _start, IndexBufferHandle _numHandle, uint32 _numIndex, uint16 _numMax, uint32 _depth, uint8 _flags);
+	
 	/// <summary>
 	/// Set compute index buffer.
 	/// </summary>

+ 47 - 2
bindings/cs/bgfx.cs

@@ -1151,6 +1151,11 @@ public static partial class bgfx
 		/// </summary>
 		ViewportLayerArray     = 0x0000000010000000,
 	
+		/// <summary>
+		/// Draw indirect with indirect count is supported.
+		/// </summary>
+		DrawIndirectCount      = 0x0000000020000000,
+	
 		/// <summary>
 		/// All texture compare modes are supported.
 		/// </summary>
@@ -3858,19 +3863,39 @@ public static partial class bgfx
 	/// <summary>
 	/// Submit primitive for rendering with index and instance data info from
 	/// indirect buffer.
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 	/// </summary>
 	///
 	/// <param name="_id">View id.</param>
 	/// <param name="_program">Program.</param>
 	/// <param name="_indirectHandle">Indirect buffer.</param>
 	/// <param name="_start">First element in indirect buffer.</param>
-	/// <param name="_num">Number of dispatches.</param>
+	/// <param name="_num">Number of draws.</param>
 	/// <param name="_depth">Depth for sorting.</param>
 	/// <param name="_flags">Discard or preserve states. See `BGFX_DISCARD_*`.</param>
 	///
 	[DllImport(DllName, EntryPoint="bgfx_encoder_submit_indirect", CallingConvention = CallingConvention.Cdecl)]
 	public static extern unsafe void encoder_submit_indirect(Encoder* _this, ushort _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, ushort _start, ushort _num, uint _depth, byte _flags);
 	
+	/// <summary>
+	/// Submit primitive for rendering with index and instance data info and
+	/// draw count from indirect buffers.
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+	/// </summary>
+	///
+	/// <param name="_id">View id.</param>
+	/// <param name="_program">Program.</param>
+	/// <param name="_indirectHandle">Indirect buffer.</param>
+	/// <param name="_start">First element in indirect buffer.</param>
+	/// <param name="_numHandle">Buffer for number of draws. Must be   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.</param>
+	/// <param name="_numIndex">Element in number buffer.</param>
+	/// <param name="_numMax">Max number of draws.</param>
+	/// <param name="_depth">Depth for sorting.</param>
+	/// <param name="_flags">Discard or preserve states. See `BGFX_DISCARD_*`.</param>
+	///
+	[DllImport(DllName, EntryPoint="bgfx_encoder_submit_indirect_count", CallingConvention = CallingConvention.Cdecl)]
+	public static extern unsafe void encoder_submit_indirect_count(Encoder* _this, ushort _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, ushort _start, IndexBufferHandle _numHandle, uint _numIndex, ushort _numMax, uint _depth, byte _flags);
+	
 	/// <summary>
 	/// Set compute index buffer.
 	/// </summary>
@@ -4414,19 +4439,39 @@ public static partial class bgfx
 	/// <summary>
 	/// Submit primitive for rendering with index and instance data info from
 	/// indirect buffer.
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 	/// </summary>
 	///
 	/// <param name="_id">View id.</param>
 	/// <param name="_program">Program.</param>
 	/// <param name="_indirectHandle">Indirect buffer.</param>
 	/// <param name="_start">First element in indirect buffer.</param>
-	/// <param name="_num">Number of dispatches.</param>
+	/// <param name="_num">Number of draws.</param>
 	/// <param name="_depth">Depth for sorting.</param>
 	/// <param name="_flags">Which states to discard for next draw. See `BGFX_DISCARD_*`.</param>
 	///
 	[DllImport(DllName, EntryPoint="bgfx_submit_indirect", CallingConvention = CallingConvention.Cdecl)]
 	public static extern unsafe void submit_indirect(ushort _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, ushort _start, ushort _num, uint _depth, byte _flags);
 	
+	/// <summary>
+	/// Submit primitive for rendering with index and instance data info and
+	/// draw count from indirect buffers.
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+	/// </summary>
+	///
+	/// <param name="_id">View id.</param>
+	/// <param name="_program">Program.</param>
+	/// <param name="_indirectHandle">Indirect buffer.</param>
+	/// <param name="_start">First element in indirect buffer.</param>
+	/// <param name="_numHandle">Buffer for number of draws. Must be   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.</param>
+	/// <param name="_numIndex">Element in number buffer.</param>
+	/// <param name="_numMax">Max number of draws.</param>
+	/// <param name="_depth">Depth for sorting.</param>
+	/// <param name="_flags">Which states to discard for next draw. See `BGFX_DISCARD_*`.</param>
+	///
+	[DllImport(DllName, EntryPoint="bgfx_submit_indirect_count", CallingConvention = CallingConvention.Cdecl)]
+	public static extern unsafe void submit_indirect_count(ushort _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, ushort _start, IndexBufferHandle _numHandle, uint _numIndex, ushort _numMax, uint _depth, byte _flags);
+	
 	/// <summary>
 	/// Set compute index buffer.
 	/// </summary>

+ 82 - 4
bindings/d/funcs.d

@@ -1526,17 +1526,36 @@ version(BindBgfx_Static)
 	/**
 	 * Submit primitive for rendering with index and instance data info from
 	 * indirect buffer.
+	 * Attention: Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 	 * Params:
 	 * _id = View id.
 	 * _program = Program.
 	 * _indirectHandle = Indirect buffer.
 	 * _start = First element in indirect buffer.
-	 * _num = Number of dispatches.
+	 * _num = Number of draws.
 	 * _depth = Depth for sorting.
 	 * _flags = Discard or preserve states. See `BGFX_DISCARD_*`.
 	 */
 	void bgfx_encoder_submit_indirect(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, ushort _start, ushort _num, uint _depth, ubyte _flags);
 	
+	/**
+	 * Submit primitive for rendering with index and instance data info and
+	 * draw count from indirect buffers.
+	 * Attention: Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+	 * Params:
+	 * _id = View id.
+	 * _program = Program.
+	 * _indirectHandle = Indirect buffer.
+	 * _start = First element in indirect buffer.
+	 * _numHandle = Buffer for number of draws. Must be
+	 *   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+	 * _numIndex = Element in number buffer.
+	 * _numMax = Max number of draws.
+	 * _depth = Depth for sorting.
+	 * _flags = Discard or preserve states. See `BGFX_DISCARD_*`.
+	 */
+	void bgfx_encoder_submit_indirect_count(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, ushort _start, bgfx_index_buffer_handle_t _numHandle, uint _numIndex, ushort _numMax, uint _depth, ubyte _flags);
+	
 	/**
 	 * Set compute index buffer.
 	 * Params:
@@ -2026,17 +2045,36 @@ version(BindBgfx_Static)
 	/**
 	 * Submit primitive for rendering with index and instance data info from
 	 * indirect buffer.
+	 * Attention: Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 	 * Params:
 	 * _id = View id.
 	 * _program = Program.
 	 * _indirectHandle = Indirect buffer.
 	 * _start = First element in indirect buffer.
-	 * _num = Number of dispatches.
+	 * _num = Number of draws.
 	 * _depth = Depth for sorting.
 	 * _flags = Which states to discard for next draw. See `BGFX_DISCARD_*`.
 	 */
 	void bgfx_submit_indirect(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, ushort _start, ushort _num, uint _depth, ubyte _flags);
 	
+	/**
+	 * Submit primitive for rendering with index and instance data info and
+	 * draw count from indirect buffers.
+	 * Attention: Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+	 * Params:
+	 * _id = View id.
+	 * _program = Program.
+	 * _indirectHandle = Indirect buffer.
+	 * _start = First element in indirect buffer.
+	 * _numHandle = Buffer for number of draws. Must be
+	 *   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+	 * _numIndex = Element in number buffer.
+	 * _numMax = Max number of draws.
+	 * _depth = Depth for sorting.
+	 * _flags = Which states to discard for next draw. See `BGFX_DISCARD_*`.
+	 */
+	void bgfx_submit_indirect_count(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, ushort _start, bgfx_index_buffer_handle_t _numHandle, uint _numIndex, ushort _numMax, uint _depth, ubyte _flags);
+	
 	/**
 	 * Set compute index buffer.
 	 * Params:
@@ -3806,18 +3844,38 @@ else
 		/**
 		 * Submit primitive for rendering with index and instance data info from
 		 * indirect buffer.
+		 * Attention: Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 		 * Params:
 		 * _id = View id.
 		 * _program = Program.
 		 * _indirectHandle = Indirect buffer.
 		 * _start = First element in indirect buffer.
-		 * _num = Number of dispatches.
+		 * _num = Number of draws.
 		 * _depth = Depth for sorting.
 		 * _flags = Discard or preserve states. See `BGFX_DISCARD_*`.
 		 */
 		alias da_bgfx_encoder_submit_indirect = void function(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, ushort _start, ushort _num, uint _depth, ubyte _flags);
 		da_bgfx_encoder_submit_indirect bgfx_encoder_submit_indirect;
 		
+		/**
+		 * Submit primitive for rendering with index and instance data info and
+		 * draw count from indirect buffers.
+		 * Attention: Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+		 * Params:
+		 * _id = View id.
+		 * _program = Program.
+		 * _indirectHandle = Indirect buffer.
+		 * _start = First element in indirect buffer.
+		 * _numHandle = Buffer for number of draws. Must be
+		 *   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+		 * _numIndex = Element in number buffer.
+		 * _numMax = Max number of draws.
+		 * _depth = Depth for sorting.
+		 * _flags = Discard or preserve states. See `BGFX_DISCARD_*`.
+		 */
+		alias da_bgfx_encoder_submit_indirect_count = void function(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, ushort _start, bgfx_index_buffer_handle_t _numHandle, uint _numIndex, ushort _numMax, uint _depth, ubyte _flags);
+		da_bgfx_encoder_submit_indirect_count bgfx_encoder_submit_indirect_count;
+		
 		/**
 		 * Set compute index buffer.
 		 * Params:
@@ -4351,18 +4409,38 @@ else
 		/**
 		 * Submit primitive for rendering with index and instance data info from
 		 * indirect buffer.
+		 * Attention: Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 		 * Params:
 		 * _id = View id.
 		 * _program = Program.
 		 * _indirectHandle = Indirect buffer.
 		 * _start = First element in indirect buffer.
-		 * _num = Number of dispatches.
+		 * _num = Number of draws.
 		 * _depth = Depth for sorting.
 		 * _flags = Which states to discard for next draw. See `BGFX_DISCARD_*`.
 		 */
 		alias da_bgfx_submit_indirect = void function(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, ushort _start, ushort _num, uint _depth, ubyte _flags);
 		da_bgfx_submit_indirect bgfx_submit_indirect;
 		
+		/**
+		 * Submit primitive for rendering with index and instance data info and
+		 * draw count from indirect buffers.
+		 * Attention: Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+		 * Params:
+		 * _id = View id.
+		 * _program = Program.
+		 * _indirectHandle = Indirect buffer.
+		 * _start = First element in indirect buffer.
+		 * _numHandle = Buffer for number of draws. Must be
+		 *   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+		 * _numIndex = Element in number buffer.
+		 * _numMax = Max number of draws.
+		 * _depth = Depth for sorting.
+		 * _flags = Which states to discard for next draw. See `BGFX_DISCARD_*`.
+		 */
+		alias da_bgfx_submit_indirect_count = void function(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, ushort _start, bgfx_index_buffer_handle_t _numHandle, uint _numIndex, ushort _numMax, uint _depth, ubyte _flags);
+		da_bgfx_submit_indirect_count bgfx_submit_indirect_count;
+		
 		/**
 		 * Set compute index buffer.
 		 * Params:

+ 1 - 0
bindings/d/types.d

@@ -410,6 +410,7 @@ enum ulong BGFX_CAPS_VERTEX_ATTRIB_HALF = 0x0000000002000000; /// Vertex attribu
 enum ulong BGFX_CAPS_VERTEX_ATTRIB_UINT10 = 0x0000000004000000; /// Vertex attribute 10_10_10_2 is supported.
 enum ulong BGFX_CAPS_VERTEX_ID = 0x0000000008000000; /// Rendering with VertexID only is supported.
 enum ulong BGFX_CAPS_VIEWPORT_LAYER_ARRAY = 0x0000000010000000; /// Viewport layer is available in vertex shader.
+enum ulong BGFX_CAPS_DRAW_INDIRECT_COUNT = 0x0000000020000000; /// Draw indirect with indirect count is supported.
 enum ulong BGFX_CAPS_TEXTURE_COMPARE_ALL = 0x0000000000300000; /// All texture compare modes are supported.
 
 enum uint BGFX_CAPS_FORMAT_TEXTURE_NONE = 0x00000000; /// Texture format is not supported.

+ 55 - 3
bindings/zig/bgfx.zig

@@ -711,6 +711,9 @@ pub const CapsFlags_VertexId: CapsFlags               = 0x0000000008000000;
 /// Viewport layer is available in vertex shader.
 pub const CapsFlags_ViewportLayerArray: CapsFlags     = 0x0000000010000000;
 
+/// Draw indirect with indirect count is supported.
+pub const CapsFlags_DrawIndirectCount: CapsFlags      = 0x0000000020000000;
+
 /// All texture compare modes are supported.
 pub const CapsFlags_TextureCompareAll: CapsFlags      = 0x0000000000300000;
 
@@ -1724,16 +1727,32 @@ pub const Init = extern struct {
         }
         /// Submit primitive for rendering with index and instance data info from
         /// indirect buffer.
+        /// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
         /// <param name="_id">View id.</param>
         /// <param name="_program">Program.</param>
         /// <param name="_indirectHandle">Indirect buffer.</param>
         /// <param name="_start">First element in indirect buffer.</param>
-        /// <param name="_num">Number of dispatches.</param>
+        /// <param name="_num">Number of draws.</param>
         /// <param name="_depth">Depth for sorting.</param>
         /// <param name="_flags">Discard or preserve states. See `BGFX_DISCARD_*`.</param>
         pub inline fn submitIndirect(self: ?*Encoder, _id: ViewId, _program: ProgramHandle, _indirectHandle: IndirectBufferHandle, _start: u16, _num: u16, _depth: u32, _flags: u8) void {
             return bgfx_encoder_submit_indirect(self, _id, _program, _indirectHandle, _start, _num, _depth, _flags);
         }
+        /// Submit primitive for rendering with index and instance data info and
+        /// draw count from indirect buffers.
+        /// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+        /// <param name="_id">View id.</param>
+        /// <param name="_program">Program.</param>
+        /// <param name="_indirectHandle">Indirect buffer.</param>
+        /// <param name="_start">First element in indirect buffer.</param>
+        /// <param name="_numHandle">Buffer for number of draws. Must be   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.</param>
+        /// <param name="_numIndex">Element in number buffer.</param>
+        /// <param name="_numMax">Max number of draws.</param>
+        /// <param name="_depth">Depth for sorting.</param>
+        /// <param name="_flags">Discard or preserve states. See `BGFX_DISCARD_*`.</param>
+        pub inline fn submitIndirectCount(self: ?*Encoder, _id: ViewId, _program: ProgramHandle, _indirectHandle: IndirectBufferHandle, _start: u16, _numHandle: IndexBufferHandle, _numIndex: u32, _numMax: u16, _depth: u32, _flags: u8) void {
+            return bgfx_encoder_submit_indirect_count(self, _id, _program, _indirectHandle, _start, _numHandle, _numIndex, _numMax, _depth, _flags);
+        }
         /// Set compute index buffer.
         /// <param name="_stage">Compute stage.</param>
         /// <param name="_handle">Index buffer handle.</param>
@@ -3068,15 +3087,30 @@ extern fn bgfx_encoder_submit_occlusion_query(self: ?*Encoder, _id: ViewId, _pro
 
 /// Submit primitive for rendering with index and instance data info from
 /// indirect buffer.
+/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 /// <param name="_id">View id.</param>
 /// <param name="_program">Program.</param>
 /// <param name="_indirectHandle">Indirect buffer.</param>
 /// <param name="_start">First element in indirect buffer.</param>
-/// <param name="_num">Number of dispatches.</param>
+/// <param name="_num">Number of draws.</param>
 /// <param name="_depth">Depth for sorting.</param>
 /// <param name="_flags">Discard or preserve states. See `BGFX_DISCARD_*`.</param>
 extern fn bgfx_encoder_submit_indirect(self: ?*Encoder, _id: ViewId, _program: ProgramHandle, _indirectHandle: IndirectBufferHandle, _start: u16, _num: u16, _depth: u32, _flags: u8) void;
 
+/// Submit primitive for rendering with index and instance data info and
+/// draw count from indirect buffers.
+/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+/// <param name="_id">View id.</param>
+/// <param name="_program">Program.</param>
+/// <param name="_indirectHandle">Indirect buffer.</param>
+/// <param name="_start">First element in indirect buffer.</param>
+/// <param name="_numHandle">Buffer for number of draws. Must be   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.</param>
+/// <param name="_numIndex">Element in number buffer.</param>
+/// <param name="_numMax">Max number of draws.</param>
+/// <param name="_depth">Depth for sorting.</param>
+/// <param name="_flags">Discard or preserve states. See `BGFX_DISCARD_*`.</param>
+extern fn bgfx_encoder_submit_indirect_count(self: ?*Encoder, _id: ViewId, _program: ProgramHandle, _indirectHandle: IndirectBufferHandle, _start: u16, _numHandle: IndexBufferHandle, _numIndex: u32, _numMax: u16, _depth: u32, _flags: u8) void;
+
 /// Set compute index buffer.
 /// <param name="_stage">Compute stage.</param>
 /// <param name="_handle">Index buffer handle.</param>
@@ -3503,11 +3537,12 @@ extern fn bgfx_submit_occlusion_query(_id: ViewId, _program: ProgramHandle, _occ
 
 /// Submit primitive for rendering with index and instance data info from
 /// indirect buffer.
+/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 /// <param name="_id">View id.</param>
 /// <param name="_program">Program.</param>
 /// <param name="_indirectHandle">Indirect buffer.</param>
 /// <param name="_start">First element in indirect buffer.</param>
-/// <param name="_num">Number of dispatches.</param>
+/// <param name="_num">Number of draws.</param>
 /// <param name="_depth">Depth for sorting.</param>
 /// <param name="_flags">Which states to discard for next draw. See `BGFX_DISCARD_*`.</param>
 pub inline fn submitIndirect(_id: ViewId, _program: ProgramHandle, _indirectHandle: IndirectBufferHandle, _start: u16, _num: u16, _depth: u32, _flags: u8) void {
@@ -3515,6 +3550,23 @@ pub inline fn submitIndirect(_id: ViewId, _program: ProgramHandle, _indirectHand
 }
 extern fn bgfx_submit_indirect(_id: ViewId, _program: ProgramHandle, _indirectHandle: IndirectBufferHandle, _start: u16, _num: u16, _depth: u32, _flags: u8) void;
 
+/// Submit primitive for rendering with index and instance data info and
+/// draw count from indirect buffers.
+/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+/// <param name="_id">View id.</param>
+/// <param name="_program">Program.</param>
+/// <param name="_indirectHandle">Indirect buffer.</param>
+/// <param name="_start">First element in indirect buffer.</param>
+/// <param name="_numHandle">Buffer for number of draws. Must be   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.</param>
+/// <param name="_numIndex">Element in number buffer.</param>
+/// <param name="_numMax">Max number of draws.</param>
+/// <param name="_depth">Depth for sorting.</param>
+/// <param name="_flags">Which states to discard for next draw. See `BGFX_DISCARD_*`.</param>
+pub inline fn submitIndirectCount(_id: ViewId, _program: ProgramHandle, _indirectHandle: IndirectBufferHandle, _start: u16, _numHandle: IndexBufferHandle, _numIndex: u32, _numMax: u16, _depth: u32, _flags: u8) void {
+    return bgfx_submit_indirect_count(_id, _program, _indirectHandle, _start, _numHandle, _numIndex, _numMax, _depth, _flags);
+}
+extern fn bgfx_submit_indirect_count(_id: ViewId, _program: ProgramHandle, _indirectHandle: IndirectBufferHandle, _start: u16, _numHandle: IndexBufferHandle, _numIndex: u32, _numMax: u16, _depth: u32, _flags: u8) void;
+
 /// Set compute index buffer.
 /// <param name="_stage">Compute stage.</param>
 /// <param name="_handle">Index buffer handle.</param>

+ 1 - 0
docs/bgfx.rst

@@ -121,6 +121,7 @@ Available Caps
 .. doxygendefine:: BGFX_CAPS_COMPUTE
 .. doxygendefine:: BGFX_CAPS_CONSERVATIVE_RASTER
 .. doxygendefine:: BGFX_CAPS_DRAW_INDIRECT
+.. doxygendefine:: BGFX_CAPS_DRAW_INDIRECT_COUNT
 .. doxygendefine:: BGFX_CAPS_FRAGMENT_DEPTH
 .. doxygendefine:: BGFX_CAPS_FRAGMENT_ORDERING
 .. doxygendefine:: BGFX_CAPS_GRAPHICS_DEBUGGER

+ 21 - 13
examples/48-drawindirect/cs_drawindirect.sc

@@ -11,6 +11,9 @@ BUFFER_RO(instanceDataIn, vec4, 0);
 // Output
 BUFFER_WR(indirectBuffer, uvec4, 1);
 BUFFER_WR(instanceBufferOut, vec4, 2);
+#ifdef INDIRECT_COUNT
+BUFFER_WR(indirectCountBuffer, int, 3);
+#endif
 
 uniform vec4 u_drawParams;
 
@@ -23,15 +26,15 @@ void main()
 	int numDrawItems = int(u_drawParams.x);
 	int sideSize = int(u_drawParams.y);
 	float time = u_drawParams.z;
-	
+
 	// Work out the amount of work we're going to do here
 	int maxToDraw = min(sideSize*sideSize, numDrawItems);
-	
+
 	int numToDrawPerThread = maxToDraw/64 + 1;
-	
+
 	int idxStart = tId*numToDrawPerThread;
 	int idxMax = min(maxToDraw, (tId+1)*numToDrawPerThread);
-	
+
 	// Prepare draw mtx
 	for (int k = idxStart; k < idxMax; k++) {
 		int yy = k / sideSize;
@@ -47,24 +50,24 @@ void main()
 		vec4 a = vec4(    cy,  0,     sy, 0);
 		vec4 b = vec4( sx*sy, cx, -sx*cy, 0);
 		vec4 c = vec4(-cx*sy, sx,  cx*cy, 0);
-		
+
 		vec4 d = vec4(-15.0f - (sideSize-11)*1.2f + float(xx) * 3.0f, -15.0f - (sideSize-11)*1.4f + float(yy) * 3.0f, max(0.0f, (sideSize-11.0f)*3.0f), 1.0f);
-		
+
 		vec4 color;
 		color.x = sin(time + float(xx) / 11.0f) * 0.5f + 0.5f;
 		color.y = cos(time + float(yy) / 11.0f) * 0.5f + 0.5f;
 		color.z = sin(time * 3.0f) * 0.5f + 0.5f;
 		color.w = 1.0f;
-		
+
 		instanceBufferOut[k*5+0] = a;
 		instanceBufferOut[k*5+1] = b;
 		instanceBufferOut[k*5+2] = c;
 		instanceBufferOut[k*5+3] = d;
 		instanceBufferOut[k*5+4] = color;
 		}
-	
+
 	// Fill indirect buffer
-	
+
 	for (int k = idxStart; k < idxMax; k++) {
 		drawIndexedIndirect(
 						// Target location params:
@@ -77,9 +80,14 @@ void main()
 			instanceDataIn[k].x,	// offset in the vertex buffer. Note that you can use this to "reindex" submeshses - all indicies in this draw will be decremented by this amount
 			k						// offset in the instance buffer. If you are drawing more than 1 instance per call see gpudrivenrendering for how to handle
 			);
-		}
+	}
 
+	#ifdef INDIRECT_COUNT
+	if (tId == 0)
+	{
+		// If BGFX_CAPS_DRAW_INDIRECT_COUNT is supported, you can limit the
+		// number of draw calls dynamically without a CPU round trip
+		indirectCountBuffer[0] = maxToDraw;
+	}
+	#endif
 }
-
-
-

+ 2 - 0
examples/48-drawindirect/cs_drawindirect_count.sc

@@ -0,0 +1,2 @@
+#define INDIRECT_COUNT
+#include "cs_drawindirect.sc"

+ 94 - 43
examples/48-drawindirect/drawindirect.cpp

@@ -42,7 +42,7 @@ struct ObjectInstance {
 	float m_vertexCount;
 	float m_indexOffset;
 	float m_indexCount;
-	
+
 	static void init()
 	{
 		ms_layout
@@ -50,7 +50,7 @@ struct ObjectInstance {
 			.add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Float)
 			.end();
 	};
-	
+
 	static bgfx::VertexLayout ms_layout;
 	};
 
@@ -59,7 +59,7 @@ bgfx::VertexLayout ObjectInstance::ms_layout;
 struct RenderInstance {
 	float m_mtx[16];
 	float m_color[4];
-	
+
 	static void init()
 	{
 		ms_layout
@@ -71,10 +71,10 @@ struct RenderInstance {
 			.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Float)
 			.end();
 	};
-	
+
 	static bgfx::VertexLayout ms_layout;
 	};
-	
+
 bgfx::VertexLayout RenderInstance::ms_layout;
 
 static PosColorVertex s_multiMeshVertices[12] =
@@ -88,7 +88,7 @@ static PosColorVertex s_multiMeshVertices[12] =
 	{ 1.0f,  1.0f, -1.0f, 0xffff00ff },
 	{-1.0f, -1.0f, -1.0f, 0xffffff00 },
 	{ 1.0f, -1.0f, -1.0f, 0xffffffff },
-	
+
 	// Tetrahedron Model (offset = 8)
 	{ 1.0f,  1.0f,  1.0f, 0xff0000ff },
 	{ 1.0f, -1.0f, -1.0f, 0xff000000 },
@@ -111,7 +111,7 @@ static const uint16_t s_multiMeshIndices[48] =
 	4, 5, 1,
 	2, 3, 6, // 10
 	6, 3, 7,
-	
+
 	// Tetrahedron Indices (offset = 36)
 	0, 2, 1,
 	1, 2, 3,
@@ -137,8 +137,9 @@ public:
 		m_height = _height;
 		m_debug  = BGFX_DEBUG_TEXT;
 		m_reset  = BGFX_RESET_VSYNC;
-		m_sideSize         = 11;
+		m_sideSize = 11;
 		m_nDrawElements = s_maxSideSize*s_maxSideSize;
+		m_useIndirectCount = false;
 
 		bgfx::Init init;
 		init.type     = args.m_type;
@@ -179,26 +180,40 @@ public:
 
 		// Create program from shaders.
 		m_program = loadProgram("vs_instancing", "fs_instancing"); // These are reused from 05-instancing
-		
+
 		m_indirect_program = BGFX_INVALID_HANDLE;
+		m_indirect_count_program = BGFX_INVALID_HANDLE;
 		m_indirect_buffer_handle = BGFX_INVALID_HANDLE;
+		m_indirect_count_buffer_handle = BGFX_INVALID_HANDLE;
 		m_object_list_buffer = BGFX_INVALID_HANDLE;
-		
+
 		u_drawParams = bgfx::createUniform("u_drawParams", bgfx::UniformType::Vec4);
-		
-		const bool computeSupported = !!(BGFX_CAPS_DRAW_INDIRECT & bgfx::getCaps()->supported);
+
+		const bool computeSupported = !!(BGFX_CAPS_COMPUTE & bgfx::getCaps()->supported);
+		const bool indirectSupported = !!(BGFX_CAPS_DRAW_INDIRECT & bgfx::getCaps()->supported);
 		const bool instancingSupported = !!(BGFX_CAPS_INSTANCING & bgfx::getCaps()->supported);
-		
-		if (computeSupported && instancingSupported)
+
+		if (computeSupported && indirectSupported && instancingSupported)
 		{
 			// Set up indirect program
 			// This is a barebones program that populates the indirect buffer handle with draw requests
 			m_indirect_program = bgfx::createProgram(loadShader("cs_drawindirect"), true);
 			m_indirect_buffer_handle = bgfx::createIndirectBuffer(m_nDrawElements);
-			
+
+			const bool indirectCountSupported = !!(BGFX_CAPS_DRAW_INDIRECT_COUNT & bgfx::getCaps()->supported);
+			if (indirectCountSupported)
+			{
+				m_useIndirectCount = true;
+				m_indirect_count_program = bgfx::createProgram(loadShader("cs_drawindirect_count"), true);
+
+				const bgfx::Memory * mem = bgfx::alloc(sizeof(uint32_t));
+				*(uint32_t *)mem->data = 0;
+				m_indirect_count_buffer_handle = bgfx::createIndexBuffer(mem, BGFX_BUFFER_INDEX32 | BGFX_BUFFER_COMPUTE_WRITE | BGFX_BUFFER_DRAW_INDIRECT);
+			}
+
 			const bgfx::Memory * mem = bgfx::alloc(sizeof(ObjectInstance) * m_nDrawElements);
 			ObjectInstance* objs = (ObjectInstance*) mem->data;
-			
+
 			for (uint32_t ii = 0; ii < m_nDrawElements; ++ii)
 			{
 				if (ii % 2)
@@ -218,15 +233,15 @@ public:
 					objs[ii].m_indexCount = 36;
 				}
 			}
-			
+
 			// This is a list of objects to be rendered via the indirect program
 			m_object_list_buffer = bgfx::createVertexBuffer(mem, ObjectInstance::ms_layout, BGFX_BUFFER_COMPUTE_READ);
-			
-			// This is the instance buffer used for rendering. 
+
+			// This is the instance buffer used for rendering.
 			// You could instead use a dynamic instance buffer when rendering (use bgfx::allocInstanceDataBuffer in draw loop)
 			m_instance_buffer = bgfx::createDynamicVertexBuffer(m_nDrawElements, RenderInstance::ms_layout, BGFX_BUFFER_COMPUTE_WRITE);
 		}
-			
+
 		m_timeOffset = bx::getHPCounter();
 
 		imguiCreate();
@@ -245,10 +260,18 @@ public:
 		{
 			bgfx::destroy(m_indirect_program);
 		}
+		if (bgfx::isValid(m_indirect_count_program))
+		{
+			bgfx::destroy(m_indirect_count_program);
+		}
 		if (bgfx::isValid(m_indirect_buffer_handle))
 		{
 			bgfx::destroy(m_indirect_buffer_handle);
 		}
+		if (bgfx::isValid(m_indirect_count_buffer_handle))
+		{
+			bgfx::destroy(m_indirect_count_buffer_handle);
+		}
 		if (bgfx::isValid(m_object_list_buffer))
 		{
 			bgfx::destroy(m_object_list_buffer);
@@ -258,7 +281,7 @@ public:
 			bgfx::destroy(m_instance_buffer);
 		}
 		bgfx::destroy(u_drawParams);
-		
+
 		// Shutdown bgfx.
 		bgfx::shutdown();
 
@@ -269,6 +292,12 @@ public:
 	{
 		if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
 		{
+			// Get renderer capabilities info.
+			const bool computeSupported = !!(BGFX_CAPS_COMPUTE & bgfx::getCaps()->supported);
+			const bool indirectSupported = !!(BGFX_CAPS_DRAW_INDIRECT & bgfx::getCaps()->supported);
+			const bool indirectCountSupported = !!(BGFX_CAPS_DRAW_INDIRECT_COUNT & bgfx::getCaps()->supported);
+			const bool instancingSupported = !!(BGFX_CAPS_INSTANCING & bgfx::getCaps()->supported);
+
 			imguiBeginFrame(m_mouseState.m_mx
 				,  m_mouseState.m_my
 				, (m_mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT   : 0)
@@ -300,10 +329,18 @@ public:
 			ImGui::Text("Grid Side Size:");
 			ImGui::SliderInt("##size", (int*)&m_sideSize, 1, s_maxSideSize);
 
+			ImGui::BeginDisabled(!indirectCountSupported);
+			ImGui::Checkbox("Indirect Count", &m_useIndirectCount);
+			ImGui::EndDisabled();
+			if (!indirectCountSupported && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) )
+			{
+				ImGui::SetTooltip("Indirect Count is not supported by GPU.");
+			}
+
 			ImGui::End();
-			
+
 			imguiEndFrame();
-			
+
 
 			// Set view 0 default viewport.
 			bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
@@ -327,55 +364,66 @@ public:
 				// Set view 0 default viewport.
 				bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
 			}
-			
+
 			float time = (float)( (bx::getHPCounter() - m_timeOffset)/double(bx::getHPFrequency() ) );
 
-			// Get renderer capabilities info.
-			const bool computeSupported = !!(BGFX_CAPS_DRAW_INDIRECT & bgfx::getCaps()->supported);
-			const bool instancingSupported = !!(BGFX_CAPS_INSTANCING & bgfx::getCaps()->supported);
-			
-			if (computeSupported && instancingSupported)
+			if (computeSupported && indirectSupported && instancingSupported)
 			{
 				// Build indirect buffer & prepare instance buffer
 				// NOTE: IF you are rendering static data then
 				// this could be done once on startup and results stored
 				// This is done here for demonstration purposes
-				
+
 				// The model matrix for each instance is also set on compute
-				// you could modify this to, eg, do frustrum culling on the GPU		
+				// you could modify this to, eg, do frustrum culling on the GPU
 				float ud[4] = { float(m_nDrawElements), float(m_sideSize), float(time), 0 };
 				uint32_t numToDraw = (m_sideSize*m_sideSize);
-				
+
 				bgfx::setUniform(u_drawParams, ud);
-						
+
 				bgfx::setBuffer(0, m_object_list_buffer, bgfx::Access::Read);
 				bgfx::setBuffer(1, m_indirect_buffer_handle, bgfx::Access::Write);
 				bgfx::setBuffer(2, m_instance_buffer, bgfx::Access::Write);
-				
+
 				// Dispatch the call. We are using 64 local threads on the GPU to process the object list
 				// So lets dispatch ceil(numToDraw/64) workgroups of 64 local threads
-				bgfx::dispatch(0, m_indirect_program, uint32_t(numToDraw/64 + 1), 1, 1);
-				
+				if (m_useIndirectCount)
+				{
+					bgfx::setBuffer(3, m_indirect_count_buffer_handle, bgfx::Access::Write);
+					bgfx::dispatch(0, m_indirect_count_program, uint32_t(numToDraw/64 + 1), 1, 1);
+				}
+				else
+				{
+					bgfx::dispatch(0, m_indirect_program, uint32_t(numToDraw/64 + 1), 1, 1);
+				}
+
 				// Submit our 1 draw call
 				// Set vertex and index buffer.
 				bgfx::setIndexBuffer(m_ibh);
 				bgfx::setVertexBuffer(0, m_vbh);
 				bgfx::setInstanceDataBuffer(m_instance_buffer, 0, numToDraw);
-				
+
 				// Set render states.
 				bgfx::setState(BGFX_STATE_DEFAULT);
 
 				// Submit primitive for rendering to view 0.
-				// note that this submission requires the draw count
-				bgfx::submit(0, m_program, m_indirect_buffer_handle, 0, uint16_t(numToDraw));
+				if (m_useIndirectCount)
+				{
+					// With indirect count, the number of draws is read from a buffer
+					bgfx::submit(0, m_program, m_indirect_buffer_handle, 0, m_indirect_count_buffer_handle);
+				}
+				else
+				{
+					bgfx::submit(0, m_program, m_indirect_buffer_handle, 0, uint16_t(numToDraw));
+				}
 			}
 			else
 			{
-				// Compute/Instancing is not supported
+				// Compute/Indirect/Instancing is not supported
 				bool blink = uint32_t(time*3.0f)&1;
-				bgfx::dbgTextPrintf(0, 0, blink ? 0x4f : 0x04, " Compute/Instancing is not supported by GPU. ");
+				bgfx::dbgTextPrintf(0, 0, blink ? 0x4f : 0x04, " Compute/Indirect/Instancing is not supported by GPU. ");
 			}
-			
+
 			// Advance to next frame. Rendering thread will be kicked to
 			// process submitted rendering primitives.
 			bgfx::frame();
@@ -394,12 +442,15 @@ public:
 	uint32_t m_reset;
 	uint32_t m_sideSize;
 	uint32_t m_nDrawElements;
+	bool m_useIndirectCount;
 
 	bgfx::VertexBufferHandle m_vbh;
 	bgfx::IndexBufferHandle  m_ibh;
 	bgfx::ProgramHandle m_program;
-	bgfx::IndirectBufferHandle  m_indirect_buffer_handle;
+	bgfx::IndirectBufferHandle m_indirect_buffer_handle;
+	bgfx::IndexBufferHandle m_indirect_count_buffer_handle;
 	bgfx::ProgramHandle m_indirect_program;
+	bgfx::ProgramHandle m_indirect_count_program;
 	bgfx::VertexBufferHandle m_object_list_buffer;
 	bgfx::DynamicVertexBufferHandle m_instance_buffer;
 	bgfx::UniformHandle u_drawParams;

BIN
examples/runtime/shaders/dx11/cs_drawindirect_count.bin


BIN
examples/runtime/shaders/glsl/cs_drawindirect_count.bin


BIN
examples/runtime/shaders/spirv/cs_drawindirect.bin


BIN
examples/runtime/shaders/spirv/cs_drawindirect_count.bin


+ 62 - 2
include/bgfx/bgfx.h

@@ -1480,10 +1480,11 @@ namespace bgfx
 		/// @param[in] _program Program.
 		/// @param[in] _indirectHandle Indirect buffer.
 		/// @param[in] _start First element in indirect buffer.
-		/// @param[in] _num Number of dispatches.
+		/// @param[in] _num Number of draws.
 		/// @param[in] _depth Depth for sorting.
 		/// @param[in] _flags Discard or preserve states. See `BGFX_DISCARD_*`.
 		///
+		/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 		/// @attention C99's equivalent binding is `bgfx_encoder_submit_indirect`.
 		///
 		void submit(
@@ -1496,6 +1497,35 @@ namespace bgfx
 			, uint8_t _flags = BGFX_DISCARD_ALL
 			);
 
+		/// Submit primitive for rendering with index and instance data info and
+		/// draw count from indirect buffers.
+		///
+		/// @param[in] _id View id.
+		/// @param[in] _program Program.
+		/// @param[in] _indirectHandle Indirect buffer.
+		/// @param[in] _start First element in indirect buffer.
+		/// @param[in] _numHandle Buffer for number of draws. Must be created
+		///   with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+		/// @param[in] _numIndex Element in number buffer.
+		/// @param[in] _numMax Max number of draws.
+		/// @param[in] _depth Depth for sorting.
+		/// @param[in] _flags Discard or preserve states. See `BGFX_DISCARD_*`.
+		///
+		/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+		/// @attention C99's equivalent binding is `bgfx_encoder_submit_indirect_count`.
+		///
+		void submit(
+			  ViewId _id
+			, ProgramHandle _program
+			, IndirectBufferHandle _indirectHandle
+			, uint16_t _start
+			, IndexBufferHandle _numHandle
+			, uint32_t _numIndex = 0
+			, uint16_t _numMax = UINT16_MAX
+			, uint32_t _depth = 0
+			, uint8_t _flags = BGFX_DISCARD_ALL
+			);
+
 		/// Set compute index buffer.
 		///
 		/// @param[in] _stage Compute stage.
@@ -3924,10 +3954,11 @@ namespace bgfx
 	/// @param[in] _program Program.
 	/// @param[in] _indirectHandle Indirect buffer.
 	/// @param[in] _start First element in indirect buffer.
-	/// @param[in] _num Number of dispatches.
+	/// @param[in] _num Number of draws.
 	/// @param[in] _depth Depth for sorting.
 	/// @param[in] _flags Discard or preserve states. See `BGFX_DISCARD_*`.
 	///
+	/// @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
 	/// @attention C99's equivalent binding is `bgfx_submit_indirect`.
 	///
 	void submit(
@@ -3940,6 +3971,35 @@ namespace bgfx
 		, uint8_t _flags  = BGFX_DISCARD_ALL
 		);
 
+	/// Submit primitive for rendering with index and instance data info and
+	/// draw count from indirect buffers.
+	///
+	/// @param[in] _id View id.
+	/// @param[in] _program Program.
+	/// @param[in] _indirectHandle Indirect buffer.
+	/// @param[in] _start First element in indirect buffer.
+	/// @param[in] _numHandle Buffer for number of draws. Must be created
+	///   with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+	/// @param[in] _numIndex Element in number buffer.
+	/// @param[in] _numMax Max number of draws.
+	/// @param[in] _depth Depth for sorting.
+	/// @param[in] _flags Discard or preserve states. See `BGFX_DISCARD_*`.
+	///
+	/// @attention Availability depends on:`BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+	/// @attention C99's equivalent binding is `bgfx_submit_indirect_count`.
+	///
+	void submit(
+		  ViewId _id
+		, ProgramHandle _program
+		, IndirectBufferHandle _indirectHandle
+		, uint16_t _start
+		, IndexBufferHandle _numHandle
+		, uint32_t _numIndex = 0
+		, uint16_t _numMax = UINT16_MAX
+		, uint32_t _depth = 0
+		, uint8_t _flags = BGFX_DISCARD_ALL
+		);
+
 	/// Set compute index buffer.
 	///
 	/// @param[in] _stage Compute stage.

+ 46 - 2
include/bgfx/c99/bgfx.h

@@ -2665,18 +2665,38 @@ BGFX_C_API void bgfx_encoder_submit_occlusion_query(bgfx_encoder_t* _this, bgfx_
 /**
  * Submit primitive for rendering with index and instance data info from
  * indirect buffer.
+ * @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
  *
  * @param[in] _id View id.
  * @param[in] _program Program.
  * @param[in] _indirectHandle Indirect buffer.
  * @param[in] _start First element in indirect buffer.
- * @param[in] _num Number of dispatches.
+ * @param[in] _num Number of draws.
  * @param[in] _depth Depth for sorting.
  * @param[in] _flags Discard or preserve states. See `BGFX_DISCARD_*`.
  *
  */
 BGFX_C_API void bgfx_encoder_submit_indirect(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, uint16_t _num, uint32_t _depth, uint8_t _flags);
 
+/**
+ * Submit primitive for rendering with index and instance data info and
+ * draw count from indirect buffers.
+ * @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+ *
+ * @param[in] _id View id.
+ * @param[in] _program Program.
+ * @param[in] _indirectHandle Indirect buffer.
+ * @param[in] _start First element in indirect buffer.
+ * @param[in] _numHandle Buffer for number of draws. Must be
+ *    created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+ * @param[in] _numIndex Element in number buffer.
+ * @param[in] _numMax Max number of draws.
+ * @param[in] _depth Depth for sorting.
+ * @param[in] _flags Discard or preserve states. See `BGFX_DISCARD_*`.
+ *
+ */
+BGFX_C_API void bgfx_encoder_submit_indirect_count(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, bgfx_index_buffer_handle_t _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags);
+
 /**
  * Set compute index buffer.
  *
@@ -3227,18 +3247,38 @@ BGFX_C_API void bgfx_submit_occlusion_query(bgfx_view_id_t _id, bgfx_program_han
 /**
  * Submit primitive for rendering with index and instance data info from
  * indirect buffer.
+ * @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
  *
  * @param[in] _id View id.
  * @param[in] _program Program.
  * @param[in] _indirectHandle Indirect buffer.
  * @param[in] _start First element in indirect buffer.
- * @param[in] _num Number of dispatches.
+ * @param[in] _num Number of draws.
  * @param[in] _depth Depth for sorting.
  * @param[in] _flags Which states to discard for next draw. See `BGFX_DISCARD_*`.
  *
  */
 BGFX_C_API void bgfx_submit_indirect(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, uint16_t _num, uint32_t _depth, uint8_t _flags);
 
+/**
+ * Submit primitive for rendering with index and instance data info and
+ * draw count from indirect buffers.
+ * @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+ *
+ * @param[in] _id View id.
+ * @param[in] _program Program.
+ * @param[in] _indirectHandle Indirect buffer.
+ * @param[in] _start First element in indirect buffer.
+ * @param[in] _numHandle Buffer for number of draws. Must be
+ *    created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+ * @param[in] _numIndex Element in number buffer.
+ * @param[in] _numMax Max number of draws.
+ * @param[in] _depth Depth for sorting.
+ * @param[in] _flags Which states to discard for next draw. See `BGFX_DISCARD_*`.
+ *
+ */
+BGFX_C_API void bgfx_submit_indirect_count(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, bgfx_index_buffer_handle_t _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags);
+
 /**
  * Set compute index buffer.
  *
@@ -3503,6 +3543,7 @@ typedef enum bgfx_function_id
     BGFX_FUNCTION_ID_ENCODER_SUBMIT,
     BGFX_FUNCTION_ID_ENCODER_SUBMIT_OCCLUSION_QUERY,
     BGFX_FUNCTION_ID_ENCODER_SUBMIT_INDIRECT,
+    BGFX_FUNCTION_ID_ENCODER_SUBMIT_INDIRECT_COUNT,
     BGFX_FUNCTION_ID_ENCODER_SET_COMPUTE_INDEX_BUFFER,
     BGFX_FUNCTION_ID_ENCODER_SET_COMPUTE_VERTEX_BUFFER,
     BGFX_FUNCTION_ID_ENCODER_SET_COMPUTE_DYNAMIC_INDEX_BUFFER,
@@ -3548,6 +3589,7 @@ typedef enum bgfx_function_id
     BGFX_FUNCTION_ID_SUBMIT,
     BGFX_FUNCTION_ID_SUBMIT_OCCLUSION_QUERY,
     BGFX_FUNCTION_ID_SUBMIT_INDIRECT,
+    BGFX_FUNCTION_ID_SUBMIT_INDIRECT_COUNT,
     BGFX_FUNCTION_ID_SET_COMPUTE_INDEX_BUFFER,
     BGFX_FUNCTION_ID_SET_COMPUTE_VERTEX_BUFFER,
     BGFX_FUNCTION_ID_SET_COMPUTE_DYNAMIC_INDEX_BUFFER,
@@ -3703,6 +3745,7 @@ struct bgfx_interface_vtbl
     void (*encoder_submit)(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, uint32_t _depth, uint8_t _flags);
     void (*encoder_submit_occlusion_query)(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_occlusion_query_handle_t _occlusionQuery, uint32_t _depth, uint8_t _flags);
     void (*encoder_submit_indirect)(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, uint16_t _num, uint32_t _depth, uint8_t _flags);
+    void (*encoder_submit_indirect_count)(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, bgfx_index_buffer_handle_t _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags);
     void (*encoder_set_compute_index_buffer)(bgfx_encoder_t* _this, uint8_t _stage, bgfx_index_buffer_handle_t _handle, bgfx_access_t _access);
     void (*encoder_set_compute_vertex_buffer)(bgfx_encoder_t* _this, uint8_t _stage, bgfx_vertex_buffer_handle_t _handle, bgfx_access_t _access);
     void (*encoder_set_compute_dynamic_index_buffer)(bgfx_encoder_t* _this, uint8_t _stage, bgfx_dynamic_index_buffer_handle_t _handle, bgfx_access_t _access);
@@ -3748,6 +3791,7 @@ struct bgfx_interface_vtbl
     void (*submit)(bgfx_view_id_t _id, bgfx_program_handle_t _program, uint32_t _depth, uint8_t _flags);
     void (*submit_occlusion_query)(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_occlusion_query_handle_t _occlusionQuery, uint32_t _depth, uint8_t _flags);
     void (*submit_indirect)(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, uint16_t _num, uint32_t _depth, uint8_t _flags);
+    void (*submit_indirect_count)(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, bgfx_index_buffer_handle_t _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags);
     void (*set_compute_index_buffer)(uint8_t _stage, bgfx_index_buffer_handle_t _handle, bgfx_access_t _access);
     void (*set_compute_vertex_buffer)(uint8_t _stage, bgfx_vertex_buffer_handle_t _handle, bgfx_access_t _access);
     void (*set_compute_dynamic_index_buffer)(uint8_t _stage, bgfx_dynamic_index_buffer_handle_t _handle, bgfx_access_t _access);

+ 1 - 0
include/bgfx/defines.h

@@ -491,6 +491,7 @@
 #define BGFX_CAPS_VERTEX_ATTRIB_UINT10            UINT64_C(0x0000000004000000) //!< Vertex attribute 10_10_10_2 is supported.
 #define BGFX_CAPS_VERTEX_ID                       UINT64_C(0x0000000008000000) //!< Rendering with VertexID only is supported.
 #define BGFX_CAPS_VIEWPORT_LAYER_ARRAY            UINT64_C(0x0000000010000000) //!< Viewport layer is available in vertex shader.
+#define BGFX_CAPS_DRAW_INDIRECT_COUNT             UINT64_C(0x0000000020000000) //!< Draw indirect with indirect count is supported.
 /// All texture compare modes are supported.
 #define BGFX_CAPS_TEXTURE_COMPARE_ALL (0 \
 	| BGFX_CAPS_TEXTURE_COMPARE_RESERVED \

+ 54 - 3
scripts/bgfx.idl

@@ -394,6 +394,7 @@ flag.Caps { bits = 64, base = 1, name = "Caps" }
 	.VertexAttribUint10     --- Vertex attribute 10_10_10_2 is supported.
 	.VertexId               --- Rendering with VertexID only is supported.
 	.ViewportLayerArray     --- Viewport layer is available in vertex shader.
+	.DrawIndirectCount      --- Draw indirect with indirect count is supported.
 	.TextureCompareAll      --- All texture compare modes are supported.
 	 { "TextureCompareReserved", "TextureCompareLequal" }
 	()
@@ -2444,6 +2445,9 @@ func.Encoder.submit { cname = "submit_occlusion_query" }
 
 --- Submit primitive for rendering with index and instance data info from
 --- indirect buffer.
+---
+--- @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
+---
 func.Encoder.submit { cname = "submit_indirect" }
 	"void"
 	.id             "ViewId"               --- View id.
@@ -2451,13 +2455,35 @@ func.Encoder.submit { cname = "submit_indirect" }
 	.indirectHandle "IndirectBufferHandle" --- Indirect buffer.
 	.start          "uint16_t"             --- First element in indirect buffer.
 	 { default = 0 }
-	.num            "uint16_t"             --- Number of dispatches.
+	.num            "uint16_t"             --- Number of draws.
 	 { default = 1 }
 	.depth          "uint32_t"             --- Depth for sorting.
 	 { default = 0 }
 	.flags          "uint8_t"              --- Discard or preserve states. See `BGFX_DISCARD_*`.
 	 { default = "BGFX_DISCARD_ALL" }
 
+--- Submit primitive for rendering with index and instance data info and
+--- draw count from indirect buffers.
+---
+--- @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+---
+func.Encoder.submit { cname = "submit_indirect_count" }
+	"void"
+	.id             "ViewId"               --- View id.
+	.program        "ProgramHandle"        --- Program.
+	.indirectHandle "IndirectBufferHandle" --- Indirect buffer.
+	.start          "uint16_t"             --- First element in indirect buffer.
+	.numHandle      "IndexBufferHandle"    --- Buffer for number of draws. Must be
+	                                       ---   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+	.numIndex       "uint32_t"             --- Element in number buffer.
+	{ default = 0 }
+	.numMax         "uint16_t"             --- Max number of draws.
+	{ default = UINT16_MAX }
+	.depth          "uint32_t"             --- Depth for sorting.
+	{ default = 0 }
+	.flags          "uint8_t"              --- Discard or preserve states. See `BGFX_DISCARD_*`.
+	{ default = "BGFX_DISCARD_ALL" }
+
 --- Set compute index buffer.
 func.Encoder.setBuffer { cname = "set_compute_index_buffer" }
 	"void"
@@ -2997,6 +3023,9 @@ func.submit { cname = "submit_occlusion_query" }
 
 --- Submit primitive for rendering with index and instance data info from
 --- indirect buffer.
+---
+--- @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT`.
+---
 func.submit { cname = "submit_indirect" }
 	"void"
 	.id             "ViewId"               --- View id.
@@ -3004,11 +3033,33 @@ func.submit { cname = "submit_indirect" }
 	.indirectHandle "IndirectBufferHandle" --- Indirect buffer.
 	.start          "uint16_t"             --- First element in indirect buffer.
 	{ default = 0 }
-	.num            "uint16_t"             --- Number of dispatches.
+	.num            "uint16_t"             --- Number of draws.
 	{ default = 1 }
 	.depth          "uint32_t"             --- Depth for sorting.
 	{ default = 0 }
-	.flags "uint8_t"                       --- Which states to discard for next draw. See `BGFX_DISCARD_*`.
+	.flags          "uint8_t"              --- Which states to discard for next draw. See `BGFX_DISCARD_*`.
+	{ default = "BGFX_DISCARD_ALL" }
+
+--- Submit primitive for rendering with index and instance data info and
+--- draw count from indirect buffers.
+---
+--- @attention Availability depends on: `BGFX_CAPS_DRAW_INDIRECT_COUNT`.
+---
+func.submit { cname = "submit_indirect_count" }
+	"void"
+	.id             "ViewId"               --- View id.
+	.program        "ProgramHandle"        --- Program.
+	.indirectHandle "IndirectBufferHandle" --- Indirect buffer.
+	.start          "uint16_t"             --- First element in indirect buffer.
+	.numHandle      "IndexBufferHandle"    --- Buffer for number of draws. Must be
+	                                       ---   created with `BGFX_BUFFER_INDEX32` and `BGFX_BUFFER_DRAW_INDIRECT`.
+	.numIndex       "uint32_t"             --- Element in number buffer.
+	{ default = 0 }
+	.numMax         "uint16_t"             --- Max number of draws.
+	{ default = UINT16_MAX }
+	.depth          "uint32_t"             --- Depth for sorting.
+	{ default = 0 }
+	.flags          "uint8_t"              --- Which states to discard for next draw. See `BGFX_DISCARD_*`.
 	{ default = "BGFX_DISCARD_ALL" }
 
 --- Set compute index buffer.

+ 20 - 0
src/bgfx.cpp

@@ -3860,6 +3860,16 @@ namespace bgfx
 		BGFX_ENCODER(submit(_id, _program, _indirectHandle, _start, _num, _depth, _flags) );
 	}
 
+	void Encoder::submit(ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16_t _start, IndexBufferHandle _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags)
+	{
+		BGFX_CHECK_HANDLE_INVALID_OK("submit", s_ctx->m_programHandle, _program);
+		BGFX_CHECK_HANDLE("submit", s_ctx->m_vertexBufferHandle, _indirectHandle);
+		BGFX_CHECK_HANDLE("submit", s_ctx->m_indexBufferHandle, _numHandle);
+		BGFX_CHECK_CAPS(BGFX_CAPS_DRAW_INDIRECT, "Draw indirect is not supported!");
+		BGFX_CHECK_CAPS(BGFX_CAPS_DRAW_INDIRECT_COUNT, "Draw indirect count is not supported!");
+		BGFX_ENCODER(submit(_id, _program, _indirectHandle, _start, _numHandle, _numIndex, _numMax, _depth, _flags) );
+	}
+
 	void Encoder::setBuffer(uint8_t _stage, IndexBufferHandle _handle, Access::Enum _access)
 	{
 		BX_ASSERT(_stage < g_caps.limits.maxComputeBindings, "Invalid stage %d (max %d).", _stage, g_caps.limits.maxComputeBindings);
@@ -5456,6 +5466,12 @@ namespace bgfx
 		s_ctx->m_encoder0->submit(_id, _program, _indirectHandle, _start, _num, _depth, _flags);
 	}
 
+	void submit(ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16_t _start, IndexBufferHandle _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags)
+	{
+		BGFX_CHECK_ENCODER0();
+		s_ctx->m_encoder0->submit(_id, _program, _indirectHandle, _start, _numHandle, _numIndex, _numMax, _depth, _flags);
+	}
+
 	void setBuffer(uint8_t _stage, IndexBufferHandle _handle, Access::Enum _access)
 	{
 		BGFX_CHECK_ENCODER0();
@@ -5732,6 +5748,8 @@ BX_STATIC_ASSERT( (0
 	| BGFX_CAPS_VERTEX_ATTRIB_HALF
 	| BGFX_CAPS_VERTEX_ATTRIB_UINT10
 	| BGFX_CAPS_VERTEX_ID
+	| BGFX_CAPS_VIEWPORT_LAYER_ARRAY
+	| BGFX_CAPS_DRAW_INDIRECT_COUNT
 	) == (0
 	^ BGFX_CAPS_ALPHA_TO_COVERAGE
 	^ BGFX_CAPS_BLEND_INDEPENDENT
@@ -5757,6 +5775,8 @@ BX_STATIC_ASSERT( (0
 	^ BGFX_CAPS_VERTEX_ATTRIB_HALF
 	^ BGFX_CAPS_VERTEX_ATTRIB_UINT10
 	^ BGFX_CAPS_VERTEX_ID
+	^ BGFX_CAPS_VIEWPORT_LAYER_ARRAY
+	^ BGFX_CAPS_DRAW_INDIRECT_COUNT
 	) );
 
 #undef FLAGS_MASK_TEST

+ 19 - 0
src/bgfx.idl.inl

@@ -885,6 +885,15 @@ BGFX_C_API void bgfx_encoder_submit_indirect(bgfx_encoder_t* _this, bgfx_view_id
 	This->submit((bgfx::ViewId)_id, program.cpp, indirectHandle.cpp, _start, _num, _depth, _flags);
 }
 
+BGFX_C_API void bgfx_encoder_submit_indirect_count(bgfx_encoder_t* _this, bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, bgfx_index_buffer_handle_t _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags)
+{
+	bgfx::Encoder* This = (bgfx::Encoder*)_this;
+	union { bgfx_program_handle_t c; bgfx::ProgramHandle cpp; } program = { _program };
+	union { bgfx_indirect_buffer_handle_t c; bgfx::IndirectBufferHandle cpp; } indirectHandle = { _indirectHandle };
+	union { bgfx_index_buffer_handle_t c; bgfx::IndexBufferHandle cpp; } numHandle = { _numHandle };
+	This->submit((bgfx::ViewId)_id, program.cpp, indirectHandle.cpp, _start, numHandle.cpp, _numIndex, _numMax, _depth, _flags);
+}
+
 BGFX_C_API void bgfx_encoder_set_compute_index_buffer(bgfx_encoder_t* _this, uint8_t _stage, bgfx_index_buffer_handle_t _handle, bgfx_access_t _access)
 {
 	bgfx::Encoder* This = (bgfx::Encoder*)_this;
@@ -1155,6 +1164,14 @@ BGFX_C_API void bgfx_submit_indirect(bgfx_view_id_t _id, bgfx_program_handle_t _
 	bgfx::submit((bgfx::ViewId)_id, program.cpp, indirectHandle.cpp, _start, _num, _depth, _flags);
 }
 
+BGFX_C_API void bgfx_submit_indirect_count(bgfx_view_id_t _id, bgfx_program_handle_t _program, bgfx_indirect_buffer_handle_t _indirectHandle, uint16_t _start, bgfx_index_buffer_handle_t _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags)
+{
+	union { bgfx_program_handle_t c; bgfx::ProgramHandle cpp; } program = { _program };
+	union { bgfx_indirect_buffer_handle_t c; bgfx::IndirectBufferHandle cpp; } indirectHandle = { _indirectHandle };
+	union { bgfx_index_buffer_handle_t c; bgfx::IndexBufferHandle cpp; } numHandle = { _numHandle };
+	bgfx::submit((bgfx::ViewId)_id, program.cpp, indirectHandle.cpp, _start, numHandle.cpp, _numIndex, _numMax, _depth, _flags);
+}
+
 BGFX_C_API void bgfx_set_compute_index_buffer(uint8_t _stage, bgfx_index_buffer_handle_t _handle, bgfx_access_t _access)
 {
 	union { bgfx_index_buffer_handle_t c; bgfx::IndexBufferHandle cpp; } handle = { _handle };
@@ -1393,6 +1410,7 @@ BGFX_C_API bgfx_interface_vtbl_t* bgfx_get_interface(uint32_t _version)
 			bgfx_encoder_submit,
 			bgfx_encoder_submit_occlusion_query,
 			bgfx_encoder_submit_indirect,
+			bgfx_encoder_submit_indirect_count,
 			bgfx_encoder_set_compute_index_buffer,
 			bgfx_encoder_set_compute_vertex_buffer,
 			bgfx_encoder_set_compute_dynamic_index_buffer,
@@ -1438,6 +1456,7 @@ BGFX_C_API bgfx_interface_vtbl_t* bgfx_get_interface(uint32_t _version)
 			bgfx_submit,
 			bgfx_submit_occlusion_query,
 			bgfx_submit_indirect,
+			bgfx_submit_indirect_count,
 			bgfx_set_compute_index_buffer,
 			bgfx_set_compute_vertex_buffer,
 			bgfx_set_compute_dynamic_index_buffer,

+ 12 - 1
src/bgfx_p.h

@@ -1676,8 +1676,10 @@ namespace bgfx
 			}
 
 			m_startIndirect = 0;
-			m_numIndirect   = UINT16_MAX;
+			m_numIndirect = UINT16_MAX;
+			m_numIndirectIndex = 0;
 			m_indirectBuffer.idx = kInvalidHandle;
+			m_numIndirectBuffer.idx = kInvalidHandle;
 			m_occlusionQuery.idx = kInvalidHandle;
 		}
 
@@ -1710,6 +1712,7 @@ namespace bgfx
 		uint16_t m_instanceDataStride;
 		uint16_t m_startIndirect;
 		uint16_t m_numIndirect;
+		uint32_t m_numIndirectIndex;
 		uint16_t m_numMatrices;
 		uint16_t m_scissor;
 		uint8_t  m_submitFlags;
@@ -1719,6 +1722,7 @@ namespace bgfx
 		IndexBufferHandle    m_indexBuffer;
 		VertexBufferHandle   m_instanceDataBuffer;
 		IndirectBufferHandle m_indirectBuffer;
+		IndexBufferHandle    m_numIndirectBuffer;
 		OcclusionQueryHandle m_occlusionQuery;
 	};
 
@@ -2698,6 +2702,13 @@ namespace bgfx
 			submit(_id, _program, handle, _depth, _flags);
 		}
 
+		void submit(ViewId _id, ProgramHandle _program, IndirectBufferHandle _indirectHandle, uint16_t _start, IndexBufferHandle _numHandle, uint32_t _numIndex, uint16_t _numMax, uint32_t _depth, uint8_t _flags)
+		{
+			m_draw.m_numIndirectIndex = _numIndex;
+			m_draw.m_numIndirectBuffer = _numHandle;
+			submit(_id, _program, _indirectHandle, _start, _numMax, _depth, _flags);
+		}
+
 		void dispatch(ViewId _id, ProgramHandle _handle, uint32_t _ngx, uint32_t _ngy, uint32_t _ngz, uint8_t _flags);
 
 		void dispatch(ViewId _id, ProgramHandle _handle, IndirectBufferHandle _indirectHandle, uint16_t _start, uint16_t _num, uint8_t _flags)

+ 5 - 0
src/glimports.h

@@ -368,6 +368,8 @@ GL_IMPORT______(false, PFNGLLINKPROGRAMPROC,                       glLinkProgram
 GL_IMPORT______(true,  PFNGLMEMORYBARRIERPROC,                     glMemoryBarrier);
 GL_IMPORT______(true,  PFNGLMULTIDRAWARRAYSINDIRECTPROC,           glMultiDrawArraysIndirect);
 GL_IMPORT______(true,  PFNGLMULTIDRAWELEMENTSINDIRECTPROC,         glMultiDrawElementsIndirect);
+GL_IMPORT______(true,  PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC,      glMultiDrawArraysIndirectCount);
+GL_IMPORT______(true,  PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC,    glMultiDrawElementsIndirectCount);
 GL_IMPORT______(true,  PFNGLOBJECTLABELPROC,                       glObjectLabel);
 GL_IMPORT______(true,  PFNGLOBJECTPTRLABELPROC,                    glObjectPtrLabel);
 GL_IMPORT______(false, PFNGLPIXELSTOREIPROC,                       glPixelStorei);
@@ -458,6 +460,9 @@ GL_IMPORT_ARB__(true,  PFNGLINVALIDATEFRAMEBUFFERPROC,             glInvalidateF
 GL_IMPORT_ARB__(true,  PFNGLMULTIDRAWARRAYSINDIRECTPROC,           glMultiDrawArraysIndirect);
 GL_IMPORT_ARB__(true,  PFNGLMULTIDRAWELEMENTSINDIRECTPROC,         glMultiDrawElementsIndirect);
 
+GL_IMPORT_ARB__(true,  PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC,      glMultiDrawArraysIndirectCount);
+GL_IMPORT_ARB__(true,  PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC,    glMultiDrawElementsIndirectCount);
+
 GL_IMPORT_EXT__(true,  PFNGLBINDFRAMEBUFFERPROC,                   glBindFramebuffer);
 GL_IMPORT_EXT__(true,  PFNGLGENFRAMEBUFFERSPROC,                   glGenFramebuffers);
 GL_IMPORT_EXT__(true,  PFNGLDELETEFRAMEBUFFERSPROC,                glDeleteFramebuffers);

+ 14 - 6
src/renderer_d3d12.cpp

@@ -1205,6 +1205,7 @@ namespace bgfx { namespace d3d12
 					| BGFX_CAPS_TEXTURE_CUBE_ARRAY
 					| BGFX_CAPS_IMAGE_RW
 					| BGFX_CAPS_VIEWPORT_LAYER_ARRAY
+					| BGFX_CAPS_DRAW_INDIRECT_COUNT
 					);
 				g_caps.limits.maxTextureSize     = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
 				g_caps.limits.maxTextureLayers   = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
@@ -4134,6 +4135,13 @@ namespace bgfx { namespace d3d12
 				? indirect.m_size/BGFX_CONFIG_DRAW_INDIRECT_STRIDE
 				: _draw.m_numIndirect
 				;
+			ID3D12Resource* numIndirect = NULL;
+			uint32_t numOffsetIndirect = 0;
+			if (isValid(_draw.m_numIndirectBuffer) )
+			{
+				numIndirect = s_renderD3D12->m_indexBuffers[_draw.m_numIndirectBuffer.idx].m_ptr;
+				numOffsetIndirect = _draw.m_numIndirectIndex * sizeof(uint32_t);
+			}
 
 			uint32_t numIndices = 0;
 
@@ -4165,8 +4173,8 @@ namespace bgfx { namespace d3d12
 					, numDrawIndirect
 					, indirect.m_ptr
 					, _draw.m_startIndirect * BGFX_CONFIG_DRAW_INDIRECT_STRIDE
-					, NULL
-					, 0
+					, numIndirect
+					, numOffsetIndirect
 					);
 			}
 			else
@@ -4176,8 +4184,8 @@ namespace bgfx { namespace d3d12
 					, numDrawIndirect
 					, indirect.m_ptr
 					, _draw.m_startIndirect * BGFX_CONFIG_DRAW_INDIRECT_STRIDE
-					, NULL
-					, 0
+					, numIndirect
+					, numOffsetIndirect
 					);
 			}
 
@@ -4441,8 +4449,8 @@ namespace bgfx { namespace d3d12
 #if BX_PLATFORM_XBOXONE
 			flags |= D3D12XBOX_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER;
 #endif // BX_PLATFORM_XBOXONE
-			format = DXGI_FORMAT_R32G32B32A32_UINT;
-			stride = 16;
+			format = _vertex ? DXGI_FORMAT_R32G32B32A32_UINT : DXGI_FORMAT_R32_UINT;
+			stride = _vertex ? 16 : 4;
 		}
 		else
 		{

+ 62 - 10
src/renderer_gl.cpp

@@ -539,6 +539,7 @@ namespace bgfx { namespace gl
 			ARB_get_program_binary,
 			ARB_half_float_pixel,
 			ARB_half_float_vertex,
+			ARB_indirect_parameters,
 			ARB_instanced_arrays,
 			ARB_internalformat_query,
 			ARB_internalformat_query2,
@@ -756,6 +757,7 @@ namespace bgfx { namespace gl
 		{ "ARB_get_program_binary",                   BGFX_CONFIG_RENDERER_OPENGL >= 41, true  },
 		{ "ARB_half_float_pixel",                     BGFX_CONFIG_RENDERER_OPENGL >= 30, true  },
 		{ "ARB_half_float_vertex",                    BGFX_CONFIG_RENDERER_OPENGL >= 30, true  },
+		{ "ARB_indirect_parameters",                  BGFX_CONFIG_RENDERER_OPENGL >= 46, true  },
 		{ "ARB_instanced_arrays",                     BGFX_CONFIG_RENDERER_OPENGL >= 33, true  },
 		{ "ARB_internalformat_query",                 BGFX_CONFIG_RENDERER_OPENGL >= 42, true  },
 		{ "ARB_internalformat_query2",                BGFX_CONFIG_RENDERER_OPENGL >= 43, true  },
@@ -2829,6 +2831,11 @@ namespace bgfx { namespace gl
 					: 0
 					;
 
+				g_caps.supported |= s_extension[Extension::ARB_indirect_parameters].m_supported
+					? BGFX_CAPS_DRAW_INDIRECT_COUNT
+					: 0
+					;
+
 				if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN)
 				||  NULL == glPolygonMode)
 				{
@@ -8412,6 +8419,19 @@ namespace bgfx { namespace gl
 								GL_CHECK(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vb.m_id) );
 							}
 
+							uint32_t numOffsetIndirect = 0;
+							if (isValid(draw.m_numIndirectBuffer) )
+							{
+								if (currentState.m_numIndirectBuffer.idx != draw.m_numIndirectBuffer.idx)
+								{
+									const IndexBufferGL& nb = m_indexBuffers[draw.m_numIndirectBuffer.idx];
+									currentState.m_numIndirectBuffer = draw.m_numIndirectBuffer;
+									GL_CHECK(glBindBuffer(GL_PARAMETER_BUFFER_ARB, nb.m_id) );
+								}
+
+								numOffsetIndirect = draw.m_numIndirectIndex * sizeof(uint32_t);
+							}
+
 							if (isValid(draw.m_indexBuffer) )
 							{
 								const IndexBufferGL& ib = m_indexBuffers[draw.m_indexBuffer.idx];
@@ -8427,11 +8447,24 @@ namespace bgfx { namespace gl
 									;
 
 								uintptr_t args = draw.m_startIndirect * BGFX_CONFIG_DRAW_INDIRECT_STRIDE;
-								GL_CHECK(glMultiDrawElementsIndirect(prim.m_type, indexFormat
-									, (void*)args
-									, numDrawIndirect
-									, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
-									) );
+
+								if (isValid(draw.m_numIndirectBuffer) )
+								{
+									GL_CHECK(glMultiDrawElementsIndirectCount(prim.m_type, indexFormat
+										, (void*)args
+										, numOffsetIndirect
+										, numDrawIndirect
+										, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+										) );
+								}
+								else
+								{
+									GL_CHECK(glMultiDrawElementsIndirect(prim.m_type, indexFormat
+										, (void*)args
+										, numDrawIndirect
+										, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+										) );
+								}
 							}
 							else
 							{
@@ -8441,11 +8474,24 @@ namespace bgfx { namespace gl
 									;
 
 								uintptr_t args = draw.m_startIndirect * BGFX_CONFIG_DRAW_INDIRECT_STRIDE;
-								GL_CHECK(glMultiDrawArraysIndirect(prim.m_type
-									, (void*)args
-									, numDrawIndirect
-									, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
-									) );
+
+								if (isValid(draw.m_numIndirectBuffer) )
+								{
+									GL_CHECK(glMultiDrawArraysIndirectCount(prim.m_type
+										, (void*)args
+										, numOffsetIndirect
+										, numDrawIndirect
+										, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+										) );
+								}
+								else
+								{
+									GL_CHECK(glMultiDrawArraysIndirect(prim.m_type
+										, (void*)args
+										, numDrawIndirect
+										, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+										) );
+								}
 							}
 						}
 						else
@@ -8454,6 +8500,12 @@ namespace bgfx { namespace gl
 							{
 								currentState.m_indirectBuffer.idx = kInvalidHandle;
 								GL_CHECK(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0) );
+
+								if (isValid(currentState.m_numIndirectBuffer) )
+								{
+									currentState.m_numIndirectBuffer.idx = kInvalidHandle;
+									GL_CHECK(glBindBuffer(GL_PARAMETER_BUFFER_ARB, 0) );
+								}
 							}
 
 							if (isValid(draw.m_indexBuffer) )

+ 56 - 14
src/renderer_vk.cpp

@@ -329,6 +329,7 @@ VK_IMPORT_DEVICE
 			EXT_line_rasterization,
 			EXT_shader_viewport_index_layer,
 			EXT_custom_border_color,
+			KHR_draw_indirect_count,
 
 			Count
 		};
@@ -353,6 +354,7 @@ VK_IMPORT_DEVICE
 		{ "VK_EXT_line_rasterization",              1, false, false, true                                                         , Layer::Count },
 		{ "VK_EXT_shader_viewport_index_layer",     1, false, false, true                                                         , Layer::Count },
 		{ "VK_EXT_custom_border_color",             1, false, false, true                                                         , Layer::Count },
+		{ "VK_KHR_draw_indirect_count",             1, false, false, true                                                         , Layer::Count },
 	};
 	BX_STATIC_ASSERT(Extension::Count == BX_COUNTOF(s_extension) );
 
@@ -1178,6 +1180,7 @@ VK_IMPORT
 
 				s_extension[Extension::EXT_shader_viewport_index_layer].m_initialize = !!(_init.capabilities & BGFX_CAPS_VIEWPORT_LAYER_ARRAY);
 				s_extension[Extension::EXT_conservative_rasterization ].m_initialize = !!(_init.capabilities & BGFX_CAPS_CONSERVATIVE_RASTER );
+				s_extension[Extension::KHR_draw_indirect_count        ].m_initialize = !!(_init.capabilities & BGFX_CAPS_DRAW_INDIRECT_COUNT );
 
 				dumpExtensions(VK_NULL_HANDLE, s_extension);
 
@@ -1570,6 +1573,7 @@ VK_IMPORT_INSTANCE
 				g_caps.supported |= 0
 					| (s_extension[Extension::EXT_conservative_rasterization ].m_supported ? BGFX_CAPS_CONSERVATIVE_RASTER  : 0)
 					| (s_extension[Extension::EXT_shader_viewport_index_layer].m_supported ? BGFX_CAPS_VIEWPORT_LAYER_ARRAY : 0)
+					| (s_extension[Extension::KHR_draw_indirect_count        ].m_supported && indirectDrawSupport ? BGFX_CAPS_DRAW_INDIRECT_COUNT : 0)
 					;
 
 				const uint32_t maxAttachments = bx::min<uint32_t>(m_deviceProperties.limits.maxFragmentOutputAttachments, m_deviceProperties.limits.maxColorAttachments);
@@ -8683,8 +8687,10 @@ VK_DESTROY
 					}
 
 					VkBuffer bufferIndirect = VK_NULL_HANDLE;
+					VkBuffer bufferNumIndirect = VK_NULL_HANDLE;
 					uint32_t numDrawIndirect = 0;
 					uint32_t bufferOffsetIndirect = 0;
+					uint32_t bufferNumOffsetIndirect = 0;
 					if (isValid(draw.m_indirectBuffer) )
 					{
 						const VertexBufferVK& vb = m_vertexBuffers[draw.m_indirectBuffer.idx];
@@ -8694,6 +8700,12 @@ VK_DESTROY
 							: draw.m_numIndirect
 							;
 						bufferOffsetIndirect = draw.m_startIndirect * BGFX_CONFIG_DRAW_INDIRECT_STRIDE;
+
+						if (isValid(draw.m_numIndirectBuffer) )
+						{
+							bufferNumIndirect = m_indexBuffers[draw.m_numIndirectBuffer.idx].m_buffer;
+							bufferNumOffsetIndirect = draw.m_numIndirectIndex * sizeof(uint32_t);
+						}
 					}
 
 					if (hasOcclusionQuery)
@@ -8713,13 +8725,28 @@ VK_DESTROY
 
 						if (isValid(draw.m_indirectBuffer) )
 						{
-							vkCmdDrawIndirect(
-								  m_commandBuffer
-								, bufferIndirect
-								, bufferOffsetIndirect
-								, numDrawIndirect
-								, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
-								);
+							if (isValid(draw.m_numIndirectBuffer) )
+							{
+								vkCmdDrawIndirectCountKHR(
+									  m_commandBuffer
+									, bufferIndirect
+									, bufferOffsetIndirect
+									, bufferNumIndirect
+									, bufferNumOffsetIndirect
+									, numDrawIndirect
+									, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+									);
+							}
+							else
+							{
+								vkCmdDrawIndirect(
+									  m_commandBuffer
+									, bufferIndirect
+									, bufferOffsetIndirect
+									, numDrawIndirect
+									, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+									);
+							}
 						}
 						else
 						{
@@ -8762,13 +8789,28 @@ VK_DESTROY
 
 						if (isValid(draw.m_indirectBuffer) )
 						{
-							vkCmdDrawIndexedIndirect(
-								  m_commandBuffer
-								, bufferIndirect
-								, bufferOffsetIndirect
-								, numDrawIndirect
-								, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
-								);
+							if (isValid(draw.m_numIndirectBuffer) )
+							{
+								vkCmdDrawIndexedIndirectCountKHR(
+									  m_commandBuffer
+									, bufferIndirect
+									, bufferOffsetIndirect
+									, bufferNumIndirect
+									, bufferNumOffsetIndirect
+									, numDrawIndirect
+									, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+									);
+							}
+							else
+							{
+								vkCmdDrawIndexedIndirect(
+									  m_commandBuffer
+									, bufferIndirect
+									, bufferOffsetIndirect
+									, numDrawIndirect
+									, BGFX_CONFIG_DRAW_INDIRECT_STRIDE
+									);
+							}
 						}
 						else
 						{

+ 107 - 104
src/renderer_vk.h

@@ -96,110 +96,113 @@
 			VK_IMPORT_INSTANCE_FUNC(true,  vkDestroyDebugReportCallbackEXT);           \
 			VK_IMPORT_INSTANCE_PLATFORM
 
-#define VK_IMPORT_DEVICE                                                   \
-			VK_IMPORT_DEVICE_FUNC(false, vkGetDeviceQueue);                \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateFence);                   \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyFence);                  \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateSemaphore);               \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroySemaphore);              \
-			VK_IMPORT_DEVICE_FUNC(false, vkResetFences);                   \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateCommandPool);             \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyCommandPool);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkResetCommandPool);              \
-			VK_IMPORT_DEVICE_FUNC(false, vkAllocateCommandBuffers);        \
-			VK_IMPORT_DEVICE_FUNC(false, vkFreeCommandBuffers);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkGetBufferMemoryRequirements);   \
-			VK_IMPORT_DEVICE_FUNC(false, vkGetImageMemoryRequirements);    \
-			VK_IMPORT_DEVICE_FUNC(false, vkGetImageSubresourceLayout);     \
-			VK_IMPORT_DEVICE_FUNC(false, vkAllocateMemory);                \
-			VK_IMPORT_DEVICE_FUNC(false, vkFreeMemory);                    \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateImage);                   \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyImage);                  \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateImageView);               \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyImageView);              \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateBuffer);                  \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyBuffer);                 \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateFramebuffer);             \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyFramebuffer);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateRenderPass);              \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyRenderPass);             \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateShaderModule);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyShaderModule);           \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreatePipelineCache);           \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyPipelineCache);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkGetPipelineCacheData);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkMergePipelineCaches);           \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateGraphicsPipelines);       \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateComputePipelines);        \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyPipeline);               \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreatePipelineLayout);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyPipelineLayout);         \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateSampler);                 \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroySampler);                \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateDescriptorSetLayout);     \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyDescriptorSetLayout);    \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateDescriptorPool);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyDescriptorPool);         \
-			VK_IMPORT_DEVICE_FUNC(false, vkResetDescriptorPool);           \
-			VK_IMPORT_DEVICE_FUNC(false, vkAllocateDescriptorSets);        \
-			VK_IMPORT_DEVICE_FUNC(false, vkFreeDescriptorSets);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkUpdateDescriptorSets);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkCreateQueryPool);               \
-			VK_IMPORT_DEVICE_FUNC(false, vkDestroyQueryPool);              \
-			VK_IMPORT_DEVICE_FUNC(false, vkQueueSubmit);                   \
-			VK_IMPORT_DEVICE_FUNC(false, vkQueueWaitIdle);                 \
-			VK_IMPORT_DEVICE_FUNC(false, vkDeviceWaitIdle);                \
-			VK_IMPORT_DEVICE_FUNC(false, vkWaitForFences);                 \
-			VK_IMPORT_DEVICE_FUNC(false, vkBeginCommandBuffer);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkEndCommandBuffer);              \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdPipelineBarrier);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdBeginRenderPass);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdEndRenderPass);              \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdSetViewport);                \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdDraw);                       \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdDrawIndexed);                \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdDrawIndirect);               \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdDrawIndexedIndirect);        \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdDispatch);                   \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdDispatchIndirect);           \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdBindPipeline);               \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdSetStencilReference);        \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdSetBlendConstants);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdSetScissor);                 \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdBindDescriptorSets);         \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdBindIndexBuffer);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdBindVertexBuffers);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdClearColorImage);            \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdClearDepthStencilImage);     \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdClearAttachments);           \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdResolveImage);               \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyBuffer);                 \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyBufferToImage);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyImage);                  \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyImageToBuffer);          \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdBlitImage);                  \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdResetQueryPool);             \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdWriteTimestamp);             \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdBeginQuery);                 \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdEndQuery);                   \
-			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyQueryPoolResults);       \
-			VK_IMPORT_DEVICE_FUNC(false, vkMapMemory);                     \
-			VK_IMPORT_DEVICE_FUNC(false, vkUnmapMemory);                   \
-			VK_IMPORT_DEVICE_FUNC(false, vkFlushMappedMemoryRanges);       \
-			VK_IMPORT_DEVICE_FUNC(false, vkInvalidateMappedMemoryRanges);  \
-			VK_IMPORT_DEVICE_FUNC(false, vkBindBufferMemory);              \
-			VK_IMPORT_DEVICE_FUNC(false, vkBindImageMemory);               \
-			/* VK_KHR_swapchain */                                         \
-			VK_IMPORT_DEVICE_FUNC(true,  vkCreateSwapchainKHR);            \
-			VK_IMPORT_DEVICE_FUNC(true,  vkDestroySwapchainKHR);           \
-			VK_IMPORT_DEVICE_FUNC(true,  vkGetSwapchainImagesKHR);         \
-			VK_IMPORT_DEVICE_FUNC(true,  vkAcquireNextImageKHR);           \
-			VK_IMPORT_DEVICE_FUNC(true,  vkQueuePresentKHR);               \
-			/* VK_EXT_debug_utils */                                       \
-			VK_IMPORT_DEVICE_FUNC(true,  vkSetDebugUtilsObjectNameEXT);    \
-			VK_IMPORT_DEVICE_FUNC(true,  vkCmdBeginDebugUtilsLabelEXT);    \
-			VK_IMPORT_DEVICE_FUNC(true,  vkCmdEndDebugUtilsLabelEXT);      \
-			VK_IMPORT_DEVICE_FUNC(true,  vkCmdInsertDebugUtilsLabelEXT);   \
+#define VK_IMPORT_DEVICE                                                    \
+			VK_IMPORT_DEVICE_FUNC(false, vkGetDeviceQueue);                 \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateFence);                    \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyFence);                   \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateSemaphore);                \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroySemaphore);               \
+			VK_IMPORT_DEVICE_FUNC(false, vkResetFences);                    \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateCommandPool);              \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyCommandPool);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkResetCommandPool);               \
+			VK_IMPORT_DEVICE_FUNC(false, vkAllocateCommandBuffers);         \
+			VK_IMPORT_DEVICE_FUNC(false, vkFreeCommandBuffers);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkGetBufferMemoryRequirements);    \
+			VK_IMPORT_DEVICE_FUNC(false, vkGetImageMemoryRequirements);     \
+			VK_IMPORT_DEVICE_FUNC(false, vkGetImageSubresourceLayout);      \
+			VK_IMPORT_DEVICE_FUNC(false, vkAllocateMemory);                 \
+			VK_IMPORT_DEVICE_FUNC(false, vkFreeMemory);                     \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateImage);                    \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyImage);                   \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateImageView);                \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyImageView);               \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateBuffer);                   \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyBuffer);                  \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateFramebuffer);              \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyFramebuffer);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateRenderPass);               \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyRenderPass);              \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateShaderModule);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyShaderModule);            \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreatePipelineCache);            \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyPipelineCache);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkGetPipelineCacheData);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkMergePipelineCaches);            \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateGraphicsPipelines);        \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateComputePipelines);         \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyPipeline);                \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreatePipelineLayout);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyPipelineLayout);          \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateSampler);                  \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroySampler);                 \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateDescriptorSetLayout);      \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyDescriptorSetLayout);     \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateDescriptorPool);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyDescriptorPool);          \
+			VK_IMPORT_DEVICE_FUNC(false, vkResetDescriptorPool);            \
+			VK_IMPORT_DEVICE_FUNC(false, vkAllocateDescriptorSets);         \
+			VK_IMPORT_DEVICE_FUNC(false, vkFreeDescriptorSets);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkUpdateDescriptorSets);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkCreateQueryPool);                \
+			VK_IMPORT_DEVICE_FUNC(false, vkDestroyQueryPool);               \
+			VK_IMPORT_DEVICE_FUNC(false, vkQueueSubmit);                    \
+			VK_IMPORT_DEVICE_FUNC(false, vkQueueWaitIdle);                  \
+			VK_IMPORT_DEVICE_FUNC(false, vkDeviceWaitIdle);                 \
+			VK_IMPORT_DEVICE_FUNC(false, vkWaitForFences);                  \
+			VK_IMPORT_DEVICE_FUNC(false, vkBeginCommandBuffer);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkEndCommandBuffer);               \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdPipelineBarrier);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdBeginRenderPass);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdEndRenderPass);               \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdSetViewport);                 \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdDraw);                        \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdDrawIndexed);                 \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdDrawIndirect);                \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdDrawIndexedIndirect);         \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdDispatch);                    \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdDispatchIndirect);            \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdBindPipeline);                \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdSetStencilReference);         \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdSetBlendConstants);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdSetScissor);                  \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdBindDescriptorSets);          \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdBindIndexBuffer);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdBindVertexBuffers);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdClearColorImage);             \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdClearDepthStencilImage);      \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdClearAttachments);            \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdResolveImage);                \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyBuffer);                  \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyBufferToImage);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyImage);                   \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyImageToBuffer);           \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdBlitImage);                   \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdResetQueryPool);              \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdWriteTimestamp);              \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdBeginQuery);                  \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdEndQuery);                    \
+			VK_IMPORT_DEVICE_FUNC(false, vkCmdCopyQueryPoolResults);        \
+			VK_IMPORT_DEVICE_FUNC(false, vkMapMemory);                      \
+			VK_IMPORT_DEVICE_FUNC(false, vkUnmapMemory);                    \
+			VK_IMPORT_DEVICE_FUNC(false, vkFlushMappedMemoryRanges);        \
+			VK_IMPORT_DEVICE_FUNC(false, vkInvalidateMappedMemoryRanges);   \
+			VK_IMPORT_DEVICE_FUNC(false, vkBindBufferMemory);               \
+			VK_IMPORT_DEVICE_FUNC(false, vkBindImageMemory);                \
+			/* VK_KHR_swapchain */                                          \
+			VK_IMPORT_DEVICE_FUNC(true,  vkCreateSwapchainKHR);             \
+			VK_IMPORT_DEVICE_FUNC(true,  vkDestroySwapchainKHR);            \
+			VK_IMPORT_DEVICE_FUNC(true,  vkGetSwapchainImagesKHR);          \
+			VK_IMPORT_DEVICE_FUNC(true,  vkAcquireNextImageKHR);            \
+			VK_IMPORT_DEVICE_FUNC(true,  vkQueuePresentKHR);                \
+			/* VK_EXT_debug_utils */                                        \
+			VK_IMPORT_DEVICE_FUNC(true,  vkSetDebugUtilsObjectNameEXT);     \
+			VK_IMPORT_DEVICE_FUNC(true,  vkCmdBeginDebugUtilsLabelEXT);     \
+			VK_IMPORT_DEVICE_FUNC(true,  vkCmdEndDebugUtilsLabelEXT);       \
+			VK_IMPORT_DEVICE_FUNC(true,  vkCmdInsertDebugUtilsLabelEXT);    \
+			/* VK_KHR_draw_indirect_count */                                \
+			VK_IMPORT_DEVICE_FUNC(true,  vkCmdDrawIndirectCountKHR);        \
+			VK_IMPORT_DEVICE_FUNC(true,  vkCmdDrawIndexedIndirectCountKHR); \
 
 #define VK_DESTROY                                \
 			VK_DESTROY_FUNC(Buffer);              \