[Vulkan] Error propagation for immediate-mode drawer

This commit is contained in:
DrChat 2017-12-19 13:43:52 -06:00
parent 4ca8cafc1b
commit 8fc71f6f7c
4 changed files with 210 additions and 112 deletions

View File

@ -54,6 +54,7 @@ bool VulkanContext::Initialize() {
if (target_window_) { if (target_window_) {
// Create swap chain used to present to the window. // Create swap chain used to present to the window.
VkResult status = VK_ERROR_FEATURE_NOT_PRESENT;
VkSurfaceKHR surface = nullptr; VkSurfaceKHR surface = nullptr;
#if XE_PLATFORM_WIN32 #if XE_PLATFORM_WIN32
VkWin32SurfaceCreateInfoKHR create_info; VkWin32SurfaceCreateInfoKHR create_info;
@ -63,9 +64,9 @@ bool VulkanContext::Initialize() {
create_info.hinstance = create_info.hinstance =
static_cast<HINSTANCE>(target_window_->native_platform_handle()); static_cast<HINSTANCE>(target_window_->native_platform_handle());
create_info.hwnd = static_cast<HWND>(target_window_->native_handle()); create_info.hwnd = static_cast<HWND>(target_window_->native_handle());
auto err = vkCreateWin32SurfaceKHR(*provider->instance(), &create_info, status = vkCreateWin32SurfaceKHR(*provider->instance(), &create_info,
nullptr, &surface); nullptr, &surface);
CheckResult(err, "vkCreateWin32SurfaceKHR"); CheckResult(status, "vkCreateWin32SurfaceKHR");
#elif XE_PLATFORM_LINUX #elif XE_PLATFORM_LINUX
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
GtkWidget* window_handle = GtkWidget* window_handle =
@ -83,15 +84,20 @@ bool VulkanContext::Initialize() {
create_info.connection = static_cast<xcb_connection_t*>( create_info.connection = static_cast<xcb_connection_t*>(
target_window_->native_platform_handle()); target_window_->native_platform_handle());
create_info.window = static_cast<xcb_window_t>(window); create_info.window = static_cast<xcb_window_t>(window);
auto err = vkCreateXcbSurfaceKHR(*provider->instance(), &create_info, status = vkCreateXcbSurfaceKHR(*provider->instance(), &create_info, nullptr,
nullptr, &surface); &surface);
CheckResult(err, "vkCreateXcbSurfaceKHR"); CheckResult(status, "vkCreateXcbSurfaceKHR");
#else #else
#error Unsupported GDK Backend on Linux. #error Unsupported GDK Backend on Linux.
#endif // GDK_WINDOWING_X11 #endif // GDK_WINDOWING_X11
#else #else
#error Platform not yet implemented. #error Platform not yet implemented.
#endif // XE_PLATFORM_WIN32 #endif // XE_PLATFORM_WIN32
if (status != VK_SUCCESS) {
XELOGE("Failed to create presentation surface");
return false;
}
swap_chain_ = std::make_unique<VulkanSwapChain>(provider->instance(), swap_chain_ = std::make_unique<VulkanSwapChain>(provider->instance(),
provider->device()); provider->device());
if (swap_chain_->Initialize(surface) != VK_SUCCESS) { if (swap_chain_->Initialize(surface) != VK_SUCCESS) {
@ -102,6 +108,13 @@ bool VulkanContext::Initialize() {
// Only initialize immediate mode drawer if we are not an offscreen context. // Only initialize immediate mode drawer if we are not an offscreen context.
immediate_drawer_ = std::make_unique<VulkanImmediateDrawer>(this); immediate_drawer_ = std::make_unique<VulkanImmediateDrawer>(this);
status = immediate_drawer_->Initialize();
if (status != VK_SUCCESS) {
XELOGE("Failed to initialize the immediate mode drawer");
vkDestroySurfaceKHR(*provider->instance(), surface, nullptr);
immediate_drawer_.reset();
return false;
}
} }
return true; return true;

View File

@ -41,9 +41,9 @@ class LightweightCircularBuffer {
index_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; index_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
index_buffer_info.queueFamilyIndexCount = 0; index_buffer_info.queueFamilyIndexCount = 0;
index_buffer_info.pQueueFamilyIndices = nullptr; index_buffer_info.pQueueFamilyIndices = nullptr;
auto err = auto status =
vkCreateBuffer(device_, &index_buffer_info, nullptr, &index_buffer_); vkCreateBuffer(device_, &index_buffer_info, nullptr, &index_buffer_);
CheckResult(err, "vkCreateBuffer"); CheckResult(status, "vkCreateBuffer");
// Vertex buffer. // Vertex buffer.
VkBufferCreateInfo vertex_buffer_info; VkBufferCreateInfo vertex_buffer_info;
@ -55,9 +55,9 @@ class LightweightCircularBuffer {
vertex_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vertex_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
vertex_buffer_info.queueFamilyIndexCount = 0; vertex_buffer_info.queueFamilyIndexCount = 0;
vertex_buffer_info.pQueueFamilyIndices = nullptr; vertex_buffer_info.pQueueFamilyIndices = nullptr;
err = status =
vkCreateBuffer(*device, &vertex_buffer_info, nullptr, &vertex_buffer_); vkCreateBuffer(*device, &vertex_buffer_info, nullptr, &vertex_buffer_);
CheckResult(err, "vkCreateBuffer"); CheckResult(status, "vkCreateBuffer");
// Allocate underlying buffer. // Allocate underlying buffer.
// We alias it for both vertices and indices. // We alias it for both vertices and indices.
@ -69,16 +69,20 @@ class LightweightCircularBuffer {
vkBindBufferMemory(*device, vertex_buffer_, buffer_memory_, 0); vkBindBufferMemory(*device, vertex_buffer_, buffer_memory_, 0);
// Persistent mapping. // Persistent mapping.
err = vkMapMemory(device_, buffer_memory_, 0, VK_WHOLE_SIZE, 0, status = vkMapMemory(device_, buffer_memory_, 0, VK_WHOLE_SIZE, 0,
&buffer_data_); &buffer_data_);
CheckResult(err, "vkMapMemory"); CheckResult(status, "vkMapMemory");
} }
~LightweightCircularBuffer() { ~LightweightCircularBuffer() {
vkUnmapMemory(device_, buffer_memory_); if (buffer_memory_) {
vkDestroyBuffer(device_, index_buffer_, nullptr); vkUnmapMemory(device_, buffer_memory_);
vkDestroyBuffer(device_, vertex_buffer_, nullptr); buffer_memory_ = nullptr;
vkFreeMemory(device_, buffer_memory_, nullptr); }
VK_SAFE_DESTROY(vkDestroyBuffer, device_, index_buffer_, nullptr);
VK_SAFE_DESTROY(vkDestroyBuffer, device_, vertex_buffer_, nullptr);
VK_SAFE_DESTROY(vkFreeMemory, device_, buffer_memory_, nullptr);
} }
VkBuffer vertex_buffer() const { return vertex_buffer_; } VkBuffer vertex_buffer() const { return vertex_buffer_; }
@ -137,15 +141,19 @@ class LightweightCircularBuffer {
class VulkanImmediateTexture : public ImmediateTexture { class VulkanImmediateTexture : public ImmediateTexture {
public: public:
VulkanImmediateTexture(VulkanDevice* device, VkDescriptorPool descriptor_pool, VulkanImmediateTexture(VulkanDevice* device, VkDescriptorPool descriptor_pool,
VkDescriptorSetLayout descriptor_set_layout, VkSampler sampler, uint32_t width, uint32_t height)
VkImageView image_view, VkSampler sampler,
uint32_t width, uint32_t height)
: ImmediateTexture(width, height), : ImmediateTexture(width, height),
device_(*device), device_(device),
descriptor_pool_(descriptor_pool), descriptor_pool_(descriptor_pool),
image_view_(image_view), sampler_(sampler) {}
sampler_(sampler) {
~VulkanImmediateTexture() override { Shutdown(); }
VkResult Initialize(VkDescriptorSetLayout descriptor_set_layout,
VkImageView image_view) {
handle = reinterpret_cast<uintptr_t>(this); handle = reinterpret_cast<uintptr_t>(this);
image_view_ = image_view;
VkResult status;
// Create descriptor set used just for this texture. // Create descriptor set used just for this texture.
// It never changes, so we can reuse it and not worry with updates. // It never changes, so we can reuse it and not worry with updates.
@ -155,9 +163,12 @@ class VulkanImmediateTexture : public ImmediateTexture {
set_alloc_info.descriptorPool = descriptor_pool_; set_alloc_info.descriptorPool = descriptor_pool_;
set_alloc_info.descriptorSetCount = 1; set_alloc_info.descriptorSetCount = 1;
set_alloc_info.pSetLayouts = &descriptor_set_layout; set_alloc_info.pSetLayouts = &descriptor_set_layout;
auto err = status =
vkAllocateDescriptorSets(device_, &set_alloc_info, &descriptor_set_); vkAllocateDescriptorSets(*device_, &set_alloc_info, &descriptor_set_);
CheckResult(err, "vkAllocateDescriptorSets"); CheckResult(status, "vkAllocateDescriptorSets");
if (status != VK_SUCCESS) {
return status;
}
// Initialize descriptor with our texture. // Initialize descriptor with our texture.
VkDescriptorImageInfo texture_info; VkDescriptorImageInfo texture_info;
@ -173,17 +184,14 @@ class VulkanImmediateTexture : public ImmediateTexture {
descriptor_write.descriptorCount = 1; descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.pImageInfo = &texture_info; descriptor_write.pImageInfo = &texture_info;
vkUpdateDescriptorSets(device_, 1, &descriptor_write, 0, nullptr); vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
return VK_SUCCESS;
} }
VulkanImmediateTexture(VulkanDevice* device, VkDescriptorPool descriptor_pool, VkResult Initialize(VkDescriptorSetLayout descriptor_set_layout) {
VkDescriptorSetLayout descriptor_set_layout,
VkSampler sampler, uint32_t width, uint32_t height)
: ImmediateTexture(width, height),
device_(*device),
descriptor_pool_(descriptor_pool),
sampler_(sampler) {
handle = reinterpret_cast<uintptr_t>(this); handle = reinterpret_cast<uintptr_t>(this);
VkResult status;
// Create image object. // Create image object.
VkImageCreateInfo image_info; VkImageCreateInfo image_info;
@ -202,18 +210,27 @@ class VulkanImmediateTexture : public ImmediateTexture {
image_info.queueFamilyIndexCount = 0; image_info.queueFamilyIndexCount = 0;
image_info.pQueueFamilyIndices = nullptr; image_info.pQueueFamilyIndices = nullptr;
image_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; image_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
auto err = vkCreateImage(device_, &image_info, nullptr, &image_); status = vkCreateImage(*device_, &image_info, nullptr, &image_);
CheckResult(err, "vkCreateImage"); CheckResult(status, "vkCreateImage");
if (status != VK_SUCCESS) {
return status;
}
// Allocate memory for the image. // Allocate memory for the image.
VkMemoryRequirements memory_requirements; VkMemoryRequirements memory_requirements;
vkGetImageMemoryRequirements(device_, image_, &memory_requirements); vkGetImageMemoryRequirements(*device_, image_, &memory_requirements);
device_memory_ = device->AllocateMemory( device_memory_ = device_->AllocateMemory(
memory_requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); memory_requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (!device_memory_) {
return VK_ERROR_INITIALIZATION_FAILED;
}
// Bind memory and the image together. // Bind memory and the image together.
err = vkBindImageMemory(device_, image_, device_memory_, 0); status = vkBindImageMemory(*device_, image_, device_memory_, 0);
CheckResult(err, "vkBindImageMemory"); CheckResult(status, "vkBindImageMemory");
if (status != VK_SUCCESS) {
return status;
}
// Create image view used by the shader. // Create image view used by the shader.
VkImageViewCreateInfo view_info; VkImageViewCreateInfo view_info;
@ -230,8 +247,11 @@ class VulkanImmediateTexture : public ImmediateTexture {
VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A,
}; };
view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
err = vkCreateImageView(device_, &view_info, nullptr, &image_view_); status = vkCreateImageView(*device_, &view_info, nullptr, &image_view_);
CheckResult(err, "vkCreateImageView"); CheckResult(status, "vkCreateImageView");
if (status != VK_SUCCESS) {
return status;
}
// Create descriptor set used just for this texture. // Create descriptor set used just for this texture.
// It never changes, so we can reuse it and not worry with updates. // It never changes, so we can reuse it and not worry with updates.
@ -241,8 +261,12 @@ class VulkanImmediateTexture : public ImmediateTexture {
set_alloc_info.descriptorPool = descriptor_pool_; set_alloc_info.descriptorPool = descriptor_pool_;
set_alloc_info.descriptorSetCount = 1; set_alloc_info.descriptorSetCount = 1;
set_alloc_info.pSetLayouts = &descriptor_set_layout; set_alloc_info.pSetLayouts = &descriptor_set_layout;
err = vkAllocateDescriptorSets(device_, &set_alloc_info, &descriptor_set_); status =
CheckResult(err, "vkAllocateDescriptorSets"); vkAllocateDescriptorSets(*device_, &set_alloc_info, &descriptor_set_);
CheckResult(status, "vkAllocateDescriptorSets");
if (status != VK_SUCCESS) {
return status;
}
// Initialize descriptor with our texture. // Initialize descriptor with our texture.
VkDescriptorImageInfo texture_info; VkDescriptorImageInfo texture_info;
@ -258,20 +282,23 @@ class VulkanImmediateTexture : public ImmediateTexture {
descriptor_write.descriptorCount = 1; descriptor_write.descriptorCount = 1;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.pImageInfo = &texture_info; descriptor_write.pImageInfo = &texture_info;
vkUpdateDescriptorSets(device_, 1, &descriptor_write, 0, nullptr); vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
return VK_SUCCESS;
} }
~VulkanImmediateTexture() override { void Shutdown() {
vkFreeDescriptorSets(device_, descriptor_pool_, 1, &descriptor_set_); if (descriptor_set_) {
vkFreeDescriptorSets(*device_, descriptor_pool_, 1, &descriptor_set_);
if (device_memory_) { descriptor_set_ = nullptr;
vkDestroyImageView(device_, image_view_, nullptr);
vkDestroyImage(device_, image_, nullptr);
vkFreeMemory(device_, device_memory_, nullptr);
} }
VK_SAFE_DESTROY(vkDestroyImageView, *device_, image_view_, nullptr);
VK_SAFE_DESTROY(vkDestroyImage, *device_, image_, nullptr);
VK_SAFE_DESTROY(vkFreeMemory, *device_, device_memory_, nullptr);
} }
void Upload(const uint8_t* src_data) { VkResult Upload(const uint8_t* src_data) {
// TODO(benvanik): assert not in use? textures aren't dynamic right now. // TODO(benvanik): assert not in use? textures aren't dynamic right now.
// Get device image layout. // Get device image layout.
@ -280,18 +307,22 @@ class VulkanImmediateTexture : public ImmediateTexture {
subresource.mipLevel = 0; subresource.mipLevel = 0;
subresource.arrayLayer = 0; subresource.arrayLayer = 0;
VkSubresourceLayout layout; VkSubresourceLayout layout;
vkGetImageSubresourceLayout(device_, image_, &subresource, &layout); vkGetImageSubresourceLayout(*device_, image_, &subresource, &layout);
// Map memory for upload. // Map memory for upload.
uint8_t* gpu_data = nullptr; uint8_t* gpu_data = nullptr;
auto err = vkMapMemory(device_, device_memory_, 0, layout.size, 0, auto status = vkMapMemory(*device_, device_memory_, 0, layout.size, 0,
reinterpret_cast<void**>(&gpu_data)); reinterpret_cast<void**>(&gpu_data));
CheckResult(err, "vkMapMemory"); CheckResult(status, "vkMapMemory");
// Copy the entire texture, hoping its layout matches what we expect. if (status == VK_SUCCESS) {
std::memcpy(gpu_data + layout.offset, src_data, layout.size); // Copy the entire texture, hoping its layout matches what we expect.
std::memcpy(gpu_data + layout.offset, src_data, layout.size);
vkUnmapMemory(device_, device_memory_); vkUnmapMemory(*device_, device_memory_);
}
return status;
} }
// Queues a command to transition this texture to a new layout. This assumes // Queues a command to transition this texture to a new layout. This assumes
@ -321,7 +352,7 @@ class VulkanImmediateTexture : public ImmediateTexture {
VkImageLayout layout() const { return image_layout_; } VkImageLayout layout() const { return image_layout_; }
private: private:
VkDevice device_ = nullptr; ui::vulkan::VulkanDevice* device_ = nullptr;
VkDescriptorPool descriptor_pool_ = nullptr; VkDescriptorPool descriptor_pool_ = nullptr;
VkSampler sampler_ = nullptr; // Not owned. VkSampler sampler_ = nullptr; // Not owned.
VkImage image_ = nullptr; VkImage image_ = nullptr;
@ -332,7 +363,11 @@ class VulkanImmediateTexture : public ImmediateTexture {
}; };
VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context) VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
: ImmediateDrawer(graphics_context), context_(graphics_context) { : ImmediateDrawer(graphics_context), context_(graphics_context) {}
VulkanImmediateDrawer::~VulkanImmediateDrawer() { Shutdown(); }
VkResult VulkanImmediateDrawer::Initialize() {
auto device = context_->device(); auto device = context_->device();
// NEAREST + CLAMP // NEAREST + CLAMP
@ -355,17 +390,23 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
sampler_info.maxLod = 0.0f; sampler_info.maxLod = 0.0f;
sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
sampler_info.unnormalizedCoordinates = VK_FALSE; sampler_info.unnormalizedCoordinates = VK_FALSE;
auto err = vkCreateSampler(*device, &sampler_info, nullptr, auto status = vkCreateSampler(*device, &sampler_info, nullptr,
&samplers_.nearest_clamp); &samplers_.nearest_clamp);
CheckResult(err, "vkCreateSampler"); CheckResult(status, "vkCreateSampler");
if (status != VK_SUCCESS) {
return status;
}
// NEAREST + REPEAT // NEAREST + REPEAT
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
err = vkCreateSampler(*device, &sampler_info, nullptr, status = vkCreateSampler(*device, &sampler_info, nullptr,
&samplers_.nearest_repeat); &samplers_.nearest_repeat);
CheckResult(err, "vkCreateSampler"); CheckResult(status, "vkCreateSampler");
if (status != VK_SUCCESS) {
return status;
}
// LINEAR + CLAMP // LINEAR + CLAMP
sampler_info.magFilter = VK_FILTER_LINEAR; sampler_info.magFilter = VK_FILTER_LINEAR;
@ -373,17 +414,23 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
err = status =
vkCreateSampler(*device, &sampler_info, nullptr, &samplers_.linear_clamp); vkCreateSampler(*device, &sampler_info, nullptr, &samplers_.linear_clamp);
CheckResult(err, "vkCreateSampler"); CheckResult(status, "vkCreateSampler");
if (status != VK_SUCCESS) {
return status;
}
// LINEAR + REPEAT // LINEAR + REPEAT
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
err = vkCreateSampler(*device, &sampler_info, nullptr, status = vkCreateSampler(*device, &sampler_info, nullptr,
&samplers_.linear_repeat); &samplers_.linear_repeat);
CheckResult(err, "vkCreateSampler"); CheckResult(status, "vkCreateSampler");
if (status != VK_SUCCESS) {
return status;
}
// Create the descriptor set layout used for our texture sampler. // Create the descriptor set layout used for our texture sampler.
// As it changes almost every draw we keep it separate from the uniform buffer // As it changes almost every draw we keep it separate from the uniform buffer
@ -401,9 +448,12 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
texture_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; texture_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
texture_binding.pImmutableSamplers = nullptr; texture_binding.pImmutableSamplers = nullptr;
texture_set_layout_info.pBindings = &texture_binding; texture_set_layout_info.pBindings = &texture_binding;
err = vkCreateDescriptorSetLayout(*device, &texture_set_layout_info, nullptr, status = vkCreateDescriptorSetLayout(*device, &texture_set_layout_info,
&texture_set_layout_); nullptr, &texture_set_layout_);
CheckResult(err, "vkCreateDescriptorSetLayout"); CheckResult(status, "vkCreateDescriptorSetLayout");
if (status != VK_SUCCESS) {
return status;
}
// Descriptor pool used for all of our cached descriptors. // Descriptor pool used for all of our cached descriptors.
// In the steady state we don't allocate anything, so these are all manually // In the steady state we don't allocate anything, so these are all manually
@ -419,9 +469,12 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
pool_sizes[0].descriptorCount = 128; pool_sizes[0].descriptorCount = 128;
descriptor_pool_info.poolSizeCount = 1; descriptor_pool_info.poolSizeCount = 1;
descriptor_pool_info.pPoolSizes = pool_sizes; descriptor_pool_info.pPoolSizes = pool_sizes;
err = vkCreateDescriptorPool(*device, &descriptor_pool_info, nullptr, status = vkCreateDescriptorPool(*device, &descriptor_pool_info, nullptr,
&descriptor_pool_); &descriptor_pool_);
CheckResult(err, "vkCreateDescriptorPool"); CheckResult(status, "vkCreateDescriptorPool");
if (status != VK_SUCCESS) {
return status;
}
// Create the pipeline layout used for our pipeline. // Create the pipeline layout used for our pipeline.
// If we had multiple pipelines they would share this. // If we had multiple pipelines they would share this.
@ -443,9 +496,12 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
pipeline_layout_info.pushConstantRangeCount = pipeline_layout_info.pushConstantRangeCount =
static_cast<uint32_t>(xe::countof(push_constant_ranges)); static_cast<uint32_t>(xe::countof(push_constant_ranges));
pipeline_layout_info.pPushConstantRanges = push_constant_ranges; pipeline_layout_info.pPushConstantRanges = push_constant_ranges;
err = vkCreatePipelineLayout(*device, &pipeline_layout_info, nullptr, status = vkCreatePipelineLayout(*device, &pipeline_layout_info, nullptr,
&pipeline_layout_); &pipeline_layout_);
CheckResult(err, "vkCreatePipelineLayout"); CheckResult(status, "vkCreatePipelineLayout");
if (status != VK_SUCCESS) {
return status;
}
// Vertex and fragment shaders. // Vertex and fragment shaders.
VkShaderModuleCreateInfo vertex_shader_info; VkShaderModuleCreateInfo vertex_shader_info;
@ -455,9 +511,9 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
vertex_shader_info.codeSize = sizeof(immediate_vert); vertex_shader_info.codeSize = sizeof(immediate_vert);
vertex_shader_info.pCode = reinterpret_cast<const uint32_t*>(immediate_vert); vertex_shader_info.pCode = reinterpret_cast<const uint32_t*>(immediate_vert);
VkShaderModule vertex_shader; VkShaderModule vertex_shader;
err = vkCreateShaderModule(*device, &vertex_shader_info, nullptr, status = vkCreateShaderModule(*device, &vertex_shader_info, nullptr,
&vertex_shader); &vertex_shader);
CheckResult(err, "vkCreateShaderModule"); CheckResult(status, "vkCreateShaderModule");
VkShaderModuleCreateInfo fragment_shader_info; VkShaderModuleCreateInfo fragment_shader_info;
fragment_shader_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; fragment_shader_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
fragment_shader_info.pNext = nullptr; fragment_shader_info.pNext = nullptr;
@ -466,9 +522,9 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
fragment_shader_info.pCode = fragment_shader_info.pCode =
reinterpret_cast<const uint32_t*>(immediate_frag); reinterpret_cast<const uint32_t*>(immediate_frag);
VkShaderModule fragment_shader; VkShaderModule fragment_shader;
err = vkCreateShaderModule(*device, &fragment_shader_info, nullptr, status = vkCreateShaderModule(*device, &fragment_shader_info, nullptr,
&fragment_shader); &fragment_shader);
CheckResult(err, "vkCreateShaderModule"); CheckResult(status, "vkCreateShaderModule");
// Pipeline used when rendering triangles. // Pipeline used when rendering triangles.
VkGraphicsPipelineCreateInfo pipeline_info; VkGraphicsPipelineCreateInfo pipeline_info;
@ -611,42 +667,49 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
pipeline_info.subpass = 0; pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = nullptr; pipeline_info.basePipelineHandle = nullptr;
pipeline_info.basePipelineIndex = -1; pipeline_info.basePipelineIndex = -1;
err = vkCreateGraphicsPipelines(*device, nullptr, 1, &pipeline_info, nullptr, if (status == VK_SUCCESS) {
&triangle_pipeline_); status = vkCreateGraphicsPipelines(*device, nullptr, 1, &pipeline_info,
CheckResult(err, "vkCreateGraphicsPipelines"); nullptr, &triangle_pipeline_);
CheckResult(status, "vkCreateGraphicsPipelines");
}
// Silly, but let's make a pipeline just for drawing lines. // Silly, but let's make a pipeline just for drawing lines.
pipeline_info.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT; pipeline_info.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
input_info.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; input_info.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
pipeline_info.basePipelineHandle = triangle_pipeline_; pipeline_info.basePipelineHandle = triangle_pipeline_;
pipeline_info.basePipelineIndex = -1; pipeline_info.basePipelineIndex = -1;
err = vkCreateGraphicsPipelines(*device, nullptr, 1, &pipeline_info, nullptr, if (status == VK_SUCCESS) {
&line_pipeline_); status = vkCreateGraphicsPipelines(*device, nullptr, 1, &pipeline_info,
CheckResult(err, "vkCreateGraphicsPipelines"); nullptr, &line_pipeline_);
CheckResult(status, "vkCreateGraphicsPipelines");
}
vkDestroyShaderModule(*device, vertex_shader, nullptr); VK_SAFE_DESTROY(vkDestroyShaderModule, *device, vertex_shader, nullptr);
vkDestroyShaderModule(*device, fragment_shader, nullptr); VK_SAFE_DESTROY(vkDestroyShaderModule, *device, fragment_shader, nullptr);
// Allocate the buffer we'll use for our vertex and index data. // Allocate the buffer we'll use for our vertex and index data.
circular_buffer_ = std::make_unique<LightweightCircularBuffer>(device); circular_buffer_ = std::make_unique<LightweightCircularBuffer>(device);
return status;
} }
VulkanImmediateDrawer::~VulkanImmediateDrawer() { void VulkanImmediateDrawer::Shutdown() {
auto device = context_->device(); auto device = context_->device();
circular_buffer_.reset(); circular_buffer_.reset();
vkDestroyPipeline(*device, line_pipeline_, nullptr); VK_SAFE_DESTROY(vkDestroyPipeline, *device, line_pipeline_, nullptr);
vkDestroyPipeline(*device, triangle_pipeline_, nullptr); VK_SAFE_DESTROY(vkDestroyPipeline, *device, triangle_pipeline_, nullptr);
vkDestroyPipelineLayout(*device, pipeline_layout_, nullptr); VK_SAFE_DESTROY(vkDestroyPipelineLayout, *device, pipeline_layout_, nullptr);
vkDestroyDescriptorPool(*device, descriptor_pool_, nullptr); VK_SAFE_DESTROY(vkDestroyDescriptorPool, *device, descriptor_pool_, nullptr);
vkDestroyDescriptorSetLayout(*device, texture_set_layout_, nullptr); VK_SAFE_DESTROY(vkDestroyDescriptorSetLayout, *device, texture_set_layout_,
nullptr);
vkDestroySampler(*device, samplers_.nearest_clamp, nullptr); VK_SAFE_DESTROY(vkDestroySampler, *device, samplers_.nearest_clamp, nullptr);
vkDestroySampler(*device, samplers_.nearest_repeat, nullptr); VK_SAFE_DESTROY(vkDestroySampler, *device, samplers_.nearest_repeat, nullptr);
vkDestroySampler(*device, samplers_.linear_clamp, nullptr); VK_SAFE_DESTROY(vkDestroySampler, *device, samplers_.linear_clamp, nullptr);
vkDestroySampler(*device, samplers_.linear_repeat, nullptr); VK_SAFE_DESTROY(vkDestroySampler, *device, samplers_.linear_repeat, nullptr);
} }
std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::CreateTexture( std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::CreateTexture(
@ -654,10 +717,17 @@ std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::CreateTexture(
const uint8_t* data) { const uint8_t* data) {
auto device = context_->device(); auto device = context_->device();
VkResult status;
VkSampler sampler = GetSampler(filter, repeat); VkSampler sampler = GetSampler(filter, repeat);
auto texture = std::make_unique<VulkanImmediateTexture>( auto texture = std::make_unique<VulkanImmediateTexture>(
device, descriptor_pool_, texture_set_layout_, sampler, width, height); device, descriptor_pool_, sampler, width, height);
status = texture->Initialize(texture_set_layout_);
if (status != VK_SUCCESS) {
texture->Shutdown();
return nullptr;
}
if (data) { if (data) {
UpdateTexture(texture.get(), data); UpdateTexture(texture.get(), data);
} }
@ -667,9 +737,17 @@ std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::CreateTexture(
std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::WrapTexture( std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::WrapTexture(
VkImageView image_view, VkSampler sampler, uint32_t width, VkImageView image_view, VkSampler sampler, uint32_t width,
uint32_t height) { uint32_t height) {
return std::make_unique<VulkanImmediateTexture>( VkResult status;
context_->device(), descriptor_pool_, texture_set_layout_, image_view,
sampler, width, height); auto texture = std::make_unique<VulkanImmediateTexture>(
context_->device(), descriptor_pool_, sampler, width, height);
status = texture->Initialize(texture_set_layout_, image_view);
if (status != VK_SUCCESS) {
texture->Shutdown();
return nullptr;
}
return texture;
} }
void VulkanImmediateDrawer::UpdateTexture(ImmediateTexture* texture, void VulkanImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
@ -738,8 +816,6 @@ void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
} }
void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) { void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {
auto swap_chain = context_->swap_chain();
switch (draw.primitive_type) { switch (draw.primitive_type) {
case ImmediatePrimitiveType::kLines: case ImmediatePrimitiveType::kLines:
vkCmdBindPipeline(current_cmd_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, vkCmdBindPipeline(current_cmd_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS,

View File

@ -27,6 +27,9 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
VulkanImmediateDrawer(VulkanContext* graphics_context); VulkanImmediateDrawer(VulkanContext* graphics_context);
~VulkanImmediateDrawer() override; ~VulkanImmediateDrawer() override;
VkResult Initialize();
void Shutdown();
std::unique_ptr<ImmediateTexture> CreateTexture(uint32_t width, std::unique_ptr<ImmediateTexture> CreateTexture(uint32_t width,
uint32_t height, uint32_t height,
ImmediateTextureFilter filter, ImmediateTextureFilter filter,

View File

@ -25,6 +25,12 @@ namespace xe {
namespace ui { namespace ui {
namespace vulkan { namespace vulkan {
#define VK_SAFE_DESTROY(fn, dev, obj, alloc) \
if (obj) { \
fn(dev, obj, alloc); \
obj = nullptr; \
}
class Fence { class Fence {
public: public:
Fence(VkDevice device) : device_(device) { Fence(VkDevice device) : device_(device) {