Browse Source

Use indirect draw call.

master
Draklaw 4 years ago
parent
commit
3ce7962d4c
  1. 42
      src/VulkanTutorial.cpp
  2. 8
      src/VulkanTutorial.h
  3. 36
      src/vk/Context.cpp
  4. 5
      src/vk/Context.h
  5. 6
      src/vk/Memory.cpp
  6. 6
      src/vk/Memory.h

42
src/VulkanTutorial.cpp

@ -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,
0, image_states.m_draw_buffer,
0, 0,
0 MaxDrawTileCount,
sizeof(VkDrawIndexedIndirectCommand)
); );
vkCmdEndRenderPass(image_states.m_command_buffer); vkCmdEndRenderPass(image_states.m_command_buffer);

8
src/VulkanTutorial.h

@ -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;
}; };

36
src/vk/Context.cpp

@ -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");

5
src/vk/Context.h

@ -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,

6
src/vk/Memory.cpp

@ -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 {

6
src/vk/Memory.h

@ -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);

Loading…
Cancel
Save