[Vulkan] Error propagation for immediate-mode drawer
This commit is contained in:
parent
4ca8cafc1b
commit
8fc71f6f7c
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue