Use indirect draw call.
This commit is contained in:
@@ -241,6 +241,25 @@ void VulkanTutorial::draw_frame() {
|
||||
std::memcpy(uniform_buffer, &uniforms, sizeof(Uniforms));
|
||||
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[] = {
|
||||
m_swapchain.ready_to_render(),
|
||||
};
|
||||
@@ -559,6 +578,8 @@ void VulkanTutorial::initialize_image_states(size_t image_index) {
|
||||
create_uniform_buffer(image_states);
|
||||
create_descriptor_set(image_states);
|
||||
|
||||
create_draw_buffer(image_states);
|
||||
|
||||
create_command_buffer(image_states);
|
||||
|
||||
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) {
|
||||
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
|
||||
);
|
||||
|
||||
vkCmdDrawIndexed(
|
||||
m_context.cmdDrawIndexedIndirectCount(
|
||||
image_states.m_command_buffer,
|
||||
uint32_t(indices.size()),
|
||||
1,
|
||||
image_states.m_draw_buffer,
|
||||
DrawBufferOffset,
|
||||
image_states.m_draw_buffer,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
MaxDrawTileCount,
|
||||
sizeof(VkDrawIndexedIndirectCommand)
|
||||
);
|
||||
|
||||
vkCmdEndRenderPass(image_states.m_command_buffer);
|
||||
|
||||
@@ -84,8 +84,14 @@ private:
|
||||
void create_uniform_buffer(ImageStates& image_states);
|
||||
void create_descriptor_set(ImageStates& image_states);
|
||||
|
||||
void create_draw_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:
|
||||
vk::Context m_context;
|
||||
|
||||
@@ -117,6 +123,8 @@ private:
|
||||
VkDeviceSize m_uniform_buffer_offset;
|
||||
vk::DescriptorSet m_descriptor_set;
|
||||
|
||||
vk::Buffer m_draw_buffer;
|
||||
|
||||
vk::CommandBuffer m_command_buffer;
|
||||
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)
|
||||
throw std::runtime_error("failed to create vulkan instance");
|
||||
|
||||
initialize_extension_functions();
|
||||
initialize_instance_extension_functions();
|
||||
|
||||
if(settings.debug()) {
|
||||
createDebugUtilsMessenger(
|
||||
@@ -733,7 +733,9 @@ void Context::create_device(const ContextSettings& settings) {
|
||||
.geometryShader = true,
|
||||
};
|
||||
|
||||
std::vector<const char*> extensions;
|
||||
std::vector<const char*> extensions {
|
||||
VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME,
|
||||
};
|
||||
if(m_window) {
|
||||
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
};
|
||||
@@ -756,6 +758,8 @@ void Context::create_device(const ContextSettings& settings) {
|
||||
) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to create logical device");
|
||||
|
||||
initialize_device_extension_functions();
|
||||
|
||||
m_queues.resize(m_queue_families.size());
|
||||
for(size_t index = 0; index < m_queue_families.size(); ++index) {
|
||||
vkGetDeviceQueue(
|
||||
@@ -777,10 +781,10 @@ void Context::create_internal_objects() {
|
||||
m_transfer_fence = Fence(*this);
|
||||
}
|
||||
|
||||
void Context::initialize_extension_functions() {
|
||||
void Context::initialize_instance_extension_functions() {
|
||||
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( \
|
||||
m_instance, "vk" #func_name); \
|
||||
if(ptr_name == nullptr) \
|
||||
@@ -789,9 +793,27 @@ void Context::initialize_extension_functions() {
|
||||
errors_count += 1; \
|
||||
}
|
||||
|
||||
GET_PROC_ADDR(createDebugUtilsMessenger, CreateDebugUtilsMessengerEXT)
|
||||
GET_PROC_ADDR(destroyDebugUtilsMessenger, DestroyDebugUtilsMessengerEXT)
|
||||
GET_PROC_ADDR(setDebugUtilsObjectName, SetDebugUtilsObjectNameEXT)
|
||||
GET_INSTANCE_PROC_ADDR(createDebugUtilsMessenger, CreateDebugUtilsMessengerEXT)
|
||||
GET_INSTANCE_PROC_ADDR(destroyDebugUtilsMessenger, DestroyDebugUtilsMessengerEXT)
|
||||
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)
|
||||
throw std::runtime_error("failed to load extensions");
|
||||
|
||||
@@ -154,6 +154,8 @@ public:
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT destroyDebugUtilsMessenger = nullptr;
|
||||
PFN_vkSetDebugUtilsObjectNameEXT setDebugUtilsObjectName = nullptr;
|
||||
|
||||
PFN_vkCmdDrawIndexedIndirectCountKHR cmdDrawIndexedIndirectCount = nullptr;
|
||||
|
||||
private:
|
||||
void create_instance(const ContextSettings& settings);
|
||||
void create_surface(const ContextSettings& settings);
|
||||
@@ -165,7 +167,8 @@ private:
|
||||
void create_device(const ContextSettings& settings);
|
||||
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(
|
||||
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);
|
||||
}
|
||||
|
||||
void* MemoryBlock::map(Context& context, VkDeviceSize offset, VkDeviceSize size) {
|
||||
Byte* MemoryBlock::map(Context& context, VkDeviceSize offset, VkDeviceSize size) {
|
||||
assert(!is_null());
|
||||
assert(context);
|
||||
assert(offset + size <= m_size);
|
||||
@@ -100,7 +100,7 @@ void* MemoryBlock::map(Context& context, VkDeviceSize offset, VkDeviceSize size)
|
||||
) != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to map memory");
|
||||
|
||||
return ptr;
|
||||
return reinterpret_cast<Byte*>(ptr);
|
||||
}
|
||||
|
||||
void MemoryBlock::unmap(Context& context) noexcept {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2022 Simon Boyé
|
||||
#pragma once
|
||||
|
||||
#include <core/types.h>
|
||||
|
||||
#include <vk/forward.h>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
@@ -61,8 +63,8 @@ public:
|
||||
|
||||
void free() noexcept;
|
||||
|
||||
void* map(Context& context);
|
||||
void* map(Context& context, VkDeviceSize offset, VkDeviceSize size);
|
||||
Byte* map(Context& context);
|
||||
Byte* map(Context& context, VkDeviceSize offset, VkDeviceSize size);
|
||||
void unmap(Context& context) noexcept;
|
||||
|
||||
void flush(Context& context);
|
||||
|
||||
Reference in New Issue
Block a user