Use indirect draw call.
This commit is contained in:
@@ -241,6 +241,25 @@ void VulkanTutorial::draw_frame() {
|
|||||||
std::memcpy(uniform_buffer, &uniforms, sizeof(Uniforms));
|
std::memcpy(uniform_buffer, &uniforms, sizeof(Uniforms));
|
||||||
m_uniform_buffer_memory.unmap(m_context);
|
m_uniform_buffer_memory.unmap(m_context);
|
||||||
|
|
||||||
|
std::vector<VkDrawIndexedIndirectCommand> draw_commands {
|
||||||
|
{
|
||||||
|
.indexCount = uint32_t(indices.size()),
|
||||||
|
.instanceCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Byte* draw_buffer = image_states.m_draw_buffer.memory().map(
|
||||||
|
m_context,
|
||||||
|
0,
|
||||||
|
DrawBufferOffset + 1 * sizeof(VkDrawIndexedIndirectCommand)
|
||||||
|
);
|
||||||
|
*reinterpret_cast<uint32_t*>(draw_buffer) = uint32_t(draw_commands.size());
|
||||||
|
std::memcpy(
|
||||||
|
draw_buffer + DrawBufferOffset,
|
||||||
|
draw_commands.data(),
|
||||||
|
draw_commands.size() * sizeof(VkDrawIndexedIndirectCommand)
|
||||||
|
);
|
||||||
|
image_states.m_draw_buffer.memory().unmap(m_context);
|
||||||
|
|
||||||
VkSemaphore wait_semaphores[] = {
|
VkSemaphore wait_semaphores[] = {
|
||||||
m_swapchain.ready_to_render(),
|
m_swapchain.ready_to_render(),
|
||||||
};
|
};
|
||||||
@@ -559,6 +578,8 @@ void VulkanTutorial::initialize_image_states(size_t image_index) {
|
|||||||
create_uniform_buffer(image_states);
|
create_uniform_buffer(image_states);
|
||||||
create_descriptor_set(image_states);
|
create_descriptor_set(image_states);
|
||||||
|
|
||||||
|
create_draw_buffer(image_states);
|
||||||
|
|
||||||
create_command_buffer(image_states);
|
create_command_buffer(image_states);
|
||||||
|
|
||||||
image_states.m_render_done = vk::Semaphore(m_context);
|
image_states.m_render_done = vk::Semaphore(m_context);
|
||||||
@@ -636,6 +657,16 @@ void VulkanTutorial::create_descriptor_set(ImageStates& image_states) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VulkanTutorial::create_draw_buffer(ImageStates& image_states) {
|
||||||
|
image_states.m_draw_buffer = vk::Buffer(
|
||||||
|
m_context,
|
||||||
|
DrawBufferOffset + MaxDrawTileCount * sizeof(VkDrawIndexedIndirectCommand),
|
||||||
|
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||||
|
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void VulkanTutorial::create_command_buffer(ImageStates& image_states) {
|
void VulkanTutorial::create_command_buffer(ImageStates& image_states) {
|
||||||
image_states.m_command_buffer = vk::CommandBuffer(m_context, m_command_pool);
|
image_states.m_command_buffer = vk::CommandBuffer(m_context, m_command_pool);
|
||||||
|
|
||||||
@@ -716,13 +747,14 @@ void VulkanTutorial::create_command_buffer(ImageStates& image_states) {
|
|||||||
0, nullptr
|
0, nullptr
|
||||||
);
|
);
|
||||||
|
|
||||||
vkCmdDrawIndexed(
|
m_context.cmdDrawIndexedIndirectCount(
|
||||||
image_states.m_command_buffer,
|
image_states.m_command_buffer,
|
||||||
uint32_t(indices.size()),
|
image_states.m_draw_buffer,
|
||||||
1,
|
DrawBufferOffset,
|
||||||
|
image_states.m_draw_buffer,
|
||||||
0,
|
0,
|
||||||
0,
|
MaxDrawTileCount,
|
||||||
0
|
sizeof(VkDrawIndexedIndirectCommand)
|
||||||
);
|
);
|
||||||
|
|
||||||
vkCmdEndRenderPass(image_states.m_command_buffer);
|
vkCmdEndRenderPass(image_states.m_command_buffer);
|
||||||
|
|||||||
@@ -84,8 +84,14 @@ private:
|
|||||||
void create_uniform_buffer(ImageStates& image_states);
|
void create_uniform_buffer(ImageStates& image_states);
|
||||||
void create_descriptor_set(ImageStates& image_states);
|
void create_descriptor_set(ImageStates& image_states);
|
||||||
|
|
||||||
|
void create_draw_buffer(ImageStates& image_states);
|
||||||
|
|
||||||
void create_command_buffer(ImageStates& image_states);
|
void create_command_buffer(ImageStates& image_states);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr uint32_t DrawBufferOffset = 4;
|
||||||
|
static constexpr uint32_t MaxDrawTileCount = 256;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vk::Context m_context;
|
vk::Context m_context;
|
||||||
|
|
||||||
@@ -117,6 +123,8 @@ private:
|
|||||||
VkDeviceSize m_uniform_buffer_offset;
|
VkDeviceSize m_uniform_buffer_offset;
|
||||||
vk::DescriptorSet m_descriptor_set;
|
vk::DescriptorSet m_descriptor_set;
|
||||||
|
|
||||||
|
vk::Buffer m_draw_buffer;
|
||||||
|
|
||||||
vk::CommandBuffer m_command_buffer;
|
vk::CommandBuffer m_command_buffer;
|
||||||
vk::Semaphore m_render_done;
|
vk::Semaphore m_render_done;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -562,7 +562,7 @@ void Context::create_instance(const ContextSettings& settings) {
|
|||||||
if(vkCreateInstance(&instance_info, nullptr, &m_instance) != VK_SUCCESS)
|
if(vkCreateInstance(&instance_info, nullptr, &m_instance) != VK_SUCCESS)
|
||||||
throw std::runtime_error("failed to create vulkan instance");
|
throw std::runtime_error("failed to create vulkan instance");
|
||||||
|
|
||||||
initialize_extension_functions();
|
initialize_instance_extension_functions();
|
||||||
|
|
||||||
if(settings.debug()) {
|
if(settings.debug()) {
|
||||||
createDebugUtilsMessenger(
|
createDebugUtilsMessenger(
|
||||||
@@ -733,7 +733,9 @@ void Context::create_device(const ContextSettings& settings) {
|
|||||||
.geometryShader = true,
|
.geometryShader = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<const char*> extensions;
|
std::vector<const char*> extensions {
|
||||||
|
VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME,
|
||||||
|
};
|
||||||
if(m_window) {
|
if(m_window) {
|
||||||
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
};
|
};
|
||||||
@@ -756,6 +758,8 @@ void Context::create_device(const ContextSettings& settings) {
|
|||||||
) != VK_SUCCESS)
|
) != VK_SUCCESS)
|
||||||
throw std::runtime_error("failed to create logical device");
|
throw std::runtime_error("failed to create logical device");
|
||||||
|
|
||||||
|
initialize_device_extension_functions();
|
||||||
|
|
||||||
m_queues.resize(m_queue_families.size());
|
m_queues.resize(m_queue_families.size());
|
||||||
for(size_t index = 0; index < m_queue_families.size(); ++index) {
|
for(size_t index = 0; index < m_queue_families.size(); ++index) {
|
||||||
vkGetDeviceQueue(
|
vkGetDeviceQueue(
|
||||||
@@ -777,10 +781,10 @@ void Context::create_internal_objects() {
|
|||||||
m_transfer_fence = Fence(*this);
|
m_transfer_fence = Fence(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::initialize_extension_functions() {
|
void Context::initialize_instance_extension_functions() {
|
||||||
uint32_t errors_count = 0;
|
uint32_t errors_count = 0;
|
||||||
|
|
||||||
#define GET_PROC_ADDR(ptr_name, func_name) \
|
#define GET_INSTANCE_PROC_ADDR(ptr_name, func_name) \
|
||||||
ptr_name = (PFN_vk ## func_name)vkGetInstanceProcAddr( \
|
ptr_name = (PFN_vk ## func_name)vkGetInstanceProcAddr( \
|
||||||
m_instance, "vk" #func_name); \
|
m_instance, "vk" #func_name); \
|
||||||
if(ptr_name == nullptr) \
|
if(ptr_name == nullptr) \
|
||||||
@@ -789,9 +793,27 @@ void Context::initialize_extension_functions() {
|
|||||||
errors_count += 1; \
|
errors_count += 1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
GET_PROC_ADDR(createDebugUtilsMessenger, CreateDebugUtilsMessengerEXT)
|
GET_INSTANCE_PROC_ADDR(createDebugUtilsMessenger, CreateDebugUtilsMessengerEXT)
|
||||||
GET_PROC_ADDR(destroyDebugUtilsMessenger, DestroyDebugUtilsMessengerEXT)
|
GET_INSTANCE_PROC_ADDR(destroyDebugUtilsMessenger, DestroyDebugUtilsMessengerEXT)
|
||||||
GET_PROC_ADDR(setDebugUtilsObjectName, SetDebugUtilsObjectNameEXT)
|
GET_INSTANCE_PROC_ADDR(setDebugUtilsObjectName, SetDebugUtilsObjectNameEXT)
|
||||||
|
|
||||||
|
if(errors_count != 0)
|
||||||
|
throw std::runtime_error("failed to load extensions");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Context::initialize_device_extension_functions() {
|
||||||
|
uint32_t errors_count = 0;
|
||||||
|
|
||||||
|
#define GET_DEVICE_PROC_ADDR(ptr_name, func_name) \
|
||||||
|
ptr_name = (PFN_vk ## func_name)vkGetDeviceProcAddr( \
|
||||||
|
m_device, "vk" #func_name); \
|
||||||
|
if(ptr_name == nullptr) \
|
||||||
|
{ \
|
||||||
|
logger.error() << "failed to load extension function 'vk" #func_name "'"; \
|
||||||
|
errors_count += 1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_DEVICE_PROC_ADDR(cmdDrawIndexedIndirectCount, CmdDrawIndexedIndirectCountKHR)
|
||||||
|
|
||||||
if(errors_count != 0)
|
if(errors_count != 0)
|
||||||
throw std::runtime_error("failed to load extensions");
|
throw std::runtime_error("failed to load extensions");
|
||||||
|
|||||||
@@ -154,6 +154,8 @@ public:
|
|||||||
PFN_vkDestroyDebugUtilsMessengerEXT destroyDebugUtilsMessenger = nullptr;
|
PFN_vkDestroyDebugUtilsMessengerEXT destroyDebugUtilsMessenger = nullptr;
|
||||||
PFN_vkSetDebugUtilsObjectNameEXT setDebugUtilsObjectName = nullptr;
|
PFN_vkSetDebugUtilsObjectNameEXT setDebugUtilsObjectName = nullptr;
|
||||||
|
|
||||||
|
PFN_vkCmdDrawIndexedIndirectCountKHR cmdDrawIndexedIndirectCount = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void create_instance(const ContextSettings& settings);
|
void create_instance(const ContextSettings& settings);
|
||||||
void create_surface(const ContextSettings& settings);
|
void create_surface(const ContextSettings& settings);
|
||||||
@@ -165,7 +167,8 @@ private:
|
|||||||
void create_device(const ContextSettings& settings);
|
void create_device(const ContextSettings& settings);
|
||||||
void create_internal_objects();
|
void create_internal_objects();
|
||||||
|
|
||||||
void initialize_extension_functions();
|
void initialize_instance_extension_functions();
|
||||||
|
void initialize_device_extension_functions();
|
||||||
|
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL log_debug_message(
|
static VKAPI_ATTR VkBool32 VKAPI_CALL log_debug_message(
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
||||||
|
|||||||
@@ -80,11 +80,11 @@ void MemoryBlock::free() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* MemoryBlock::map(Context& context) {
|
Byte* MemoryBlock::map(Context& context) {
|
||||||
return map(context, 0, m_size);
|
return map(context, 0, m_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* MemoryBlock::map(Context& context, VkDeviceSize offset, VkDeviceSize size) {
|
Byte* MemoryBlock::map(Context& context, VkDeviceSize offset, VkDeviceSize size) {
|
||||||
assert(!is_null());
|
assert(!is_null());
|
||||||
assert(context);
|
assert(context);
|
||||||
assert(offset + size <= m_size);
|
assert(offset + size <= m_size);
|
||||||
@@ -100,7 +100,7 @@ void* MemoryBlock::map(Context& context, VkDeviceSize offset, VkDeviceSize size)
|
|||||||
) != VK_SUCCESS)
|
) != VK_SUCCESS)
|
||||||
throw std::runtime_error("failed to map memory");
|
throw std::runtime_error("failed to map memory");
|
||||||
|
|
||||||
return ptr;
|
return reinterpret_cast<Byte*>(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryBlock::unmap(Context& context) noexcept {
|
void MemoryBlock::unmap(Context& context) noexcept {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright 2022 Simon Boyé
|
// Copyright 2022 Simon Boyé
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <core/types.h>
|
||||||
|
|
||||||
#include <vk/forward.h>
|
#include <vk/forward.h>
|
||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
@@ -61,8 +63,8 @@ public:
|
|||||||
|
|
||||||
void free() noexcept;
|
void free() noexcept;
|
||||||
|
|
||||||
void* map(Context& context);
|
Byte* map(Context& context);
|
||||||
void* map(Context& context, VkDeviceSize offset, VkDeviceSize size);
|
Byte* map(Context& context, VkDeviceSize offset, VkDeviceSize size);
|
||||||
void unmap(Context& context) noexcept;
|
void unmap(Context& context) noexcept;
|
||||||
|
|
||||||
void flush(Context& context);
|
void flush(Context& context);
|
||||||
|
|||||||
Reference in New Issue
Block a user