From 49287579ff595965d50ac6af51cea3f60f2ea621 Mon Sep 17 00:00:00 2001 From: DrChat Date: Sat, 16 Dec 2017 15:14:48 -0600 Subject: [PATCH] [Vulkan] Robustify error handling during initialization --- src/xenia/gpu/vulkan/buffer_cache.cc | 73 +++++++--- src/xenia/gpu/vulkan/buffer_cache.h | 5 +- src/xenia/gpu/vulkan/pipeline_cache.cc | 132 ++++++++++++------ src/xenia/gpu/vulkan/pipeline_cache.h | 8 +- src/xenia/gpu/vulkan/render_cache.cc | 34 ++++- src/xenia/gpu/vulkan/render_cache.h | 3 + src/xenia/gpu/vulkan/texture_cache.cc | 45 ++++-- src/xenia/gpu/vulkan/texture_cache.h | 3 + .../gpu/vulkan/vulkan_command_processor.cc | 44 +++++- src/xenia/ui/vulkan/blitter.cc | 103 ++++++++++---- src/xenia/ui/vulkan/blitter.h | 2 +- src/xenia/ui/vulkan/circular_buffer.cc | 19 +-- src/xenia/ui/vulkan/circular_buffer.h | 4 +- 13 files changed, 339 insertions(+), 136 deletions(-) diff --git a/src/xenia/gpu/vulkan/buffer_cache.cc b/src/xenia/gpu/vulkan/buffer_cache.cc index eaf3324bd..663fe378f 100644 --- a/src/xenia/gpu/vulkan/buffer_cache.cc +++ b/src/xenia/gpu/vulkan/buffer_cache.cc @@ -27,19 +27,24 @@ constexpr VkDeviceSize kConstantRegisterUniformRange = BufferCache::BufferCache(RegisterFile* register_file, Memory* memory, ui::vulkan::VulkanDevice* device, size_t capacity) - : register_file_(register_file), memory_(memory), device_(*device) { + : register_file_(register_file), memory_(memory), device_(device) { transient_buffer_ = std::make_unique( - device, + device_, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, capacity); +} +BufferCache::~BufferCache() { Shutdown(); } + +VkResult BufferCache::Initialize() { VkMemoryRequirements pool_reqs; transient_buffer_->GetBufferMemoryRequirements(&pool_reqs); - gpu_memory_pool_ = device->AllocateMemory(pool_reqs); + gpu_memory_pool_ = device_->AllocateMemory(pool_reqs); - if (!transient_buffer_->Initialize(gpu_memory_pool_, 0)) { - assert_always(); + VkResult status = transient_buffer_->Initialize(gpu_memory_pool_, 0); + if (status != VK_SUCCESS) { + return status; } // Descriptor pool used for all of our cached descriptors. @@ -56,9 +61,11 @@ BufferCache::BufferCache(RegisterFile* register_file, Memory* memory, pool_sizes[0].descriptorCount = 2; descriptor_pool_info.poolSizeCount = 1; descriptor_pool_info.pPoolSizes = pool_sizes; - auto err = vkCreateDescriptorPool(device_, &descriptor_pool_info, nullptr, - &descriptor_pool_); - CheckResult(err, "vkCreateDescriptorPool"); + status = vkCreateDescriptorPool(*device_, &descriptor_pool_info, nullptr, + &descriptor_pool_); + if (status != VK_SUCCESS) { + return status; + } // Create the descriptor set layout used for our uniform buffer. // As it is a static binding that uses dynamic offsets during draws we can @@ -83,14 +90,17 @@ BufferCache::BufferCache(RegisterFile* register_file, Memory* memory, descriptor_set_layout_info.pNext = nullptr; descriptor_set_layout_info.flags = 0; VkDescriptorSetLayoutBinding uniform_bindings[] = { - vertex_uniform_binding, fragment_uniform_binding, + vertex_uniform_binding, + fragment_uniform_binding, }; descriptor_set_layout_info.bindingCount = static_cast(xe::countof(uniform_bindings)); descriptor_set_layout_info.pBindings = uniform_bindings; - err = vkCreateDescriptorSetLayout(device_, &descriptor_set_layout_info, - nullptr, &descriptor_set_layout_); - CheckResult(err, "vkCreateDescriptorSetLayout"); + status = vkCreateDescriptorSetLayout(*device_, &descriptor_set_layout_info, + nullptr, &descriptor_set_layout_); + if (status != VK_SUCCESS) { + return status; + } // Create the descriptor we'll use for the uniform buffer. // This is what we hand out to everyone (who then also needs to use our @@ -101,9 +111,11 @@ BufferCache::BufferCache(RegisterFile* register_file, Memory* memory, set_alloc_info.descriptorPool = descriptor_pool_; set_alloc_info.descriptorSetCount = 1; set_alloc_info.pSetLayouts = &descriptor_set_layout_; - err = vkAllocateDescriptorSets(device_, &set_alloc_info, - &transient_descriptor_set_); - CheckResult(err, "vkAllocateDescriptorSets"); + status = vkAllocateDescriptorSets(*device_, &set_alloc_info, + &transient_descriptor_set_); + if (status != VK_SUCCESS) { + return status; + } // Initialize descriptor set with our buffers. VkDescriptorBufferInfo buffer_info; @@ -132,18 +144,33 @@ BufferCache::BufferCache(RegisterFile* register_file, Memory* memory, fragment_uniform_binding_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; fragment_uniform_binding_write.pBufferInfo = &buffer_info; - vkUpdateDescriptorSets(device_, 2, descriptor_writes, 0, nullptr); + vkUpdateDescriptorSets(*device_, 2, descriptor_writes, 0, nullptr); + + return VK_SUCCESS; } -BufferCache::~BufferCache() { - vkFreeDescriptorSets(device_, descriptor_pool_, 1, - &transient_descriptor_set_); - vkDestroyDescriptorSetLayout(device_, descriptor_set_layout_, nullptr); - vkDestroyDescriptorPool(device_, descriptor_pool_, nullptr); +void BufferCache::Shutdown() { + if (transient_descriptor_set_) { + vkFreeDescriptorSets(*device_, descriptor_pool_, 1, + &transient_descriptor_set_); + transient_descriptor_set_ = nullptr; + } + + if (descriptor_set_layout_) { + vkDestroyDescriptorSetLayout(*device_, descriptor_set_layout_, nullptr); + descriptor_set_layout_ = nullptr; + } + + if (descriptor_pool_) { + vkDestroyDescriptorPool(*device_, descriptor_pool_, nullptr); + descriptor_pool_ = nullptr; + } + transient_buffer_->Shutdown(); if (gpu_memory_pool_) { - vkFreeMemory(device_, gpu_memory_pool_, nullptr); + vkFreeMemory(*device_, gpu_memory_pool_, nullptr); + gpu_memory_pool_ = nullptr; } } @@ -416,7 +443,7 @@ void BufferCache::Flush(VkCommandBuffer command_buffer) { dirty_range.memory = transient_buffer_->gpu_memory(); dirty_range.offset = 0; dirty_range.size = transient_buffer_->capacity(); - vkFlushMappedMemoryRanges(device_, 1, &dirty_range); + vkFlushMappedMemoryRanges(*device_, 1, &dirty_range); } void BufferCache::InvalidateCache() { transient_cache_.clear(); } diff --git a/src/xenia/gpu/vulkan/buffer_cache.h b/src/xenia/gpu/vulkan/buffer_cache.h index d8e2489de..ffaa8b8fd 100644 --- a/src/xenia/gpu/vulkan/buffer_cache.h +++ b/src/xenia/gpu/vulkan/buffer_cache.h @@ -33,6 +33,9 @@ class BufferCache { ui::vulkan::VulkanDevice* device, size_t capacity); ~BufferCache(); + VkResult Initialize(); + void Shutdown(); + // Descriptor set containing the dynamic uniform buffer used for constant // uploads. Used in conjunction with a dynamic offset returned by // UploadConstantRegisters. @@ -109,7 +112,7 @@ class BufferCache { RegisterFile* register_file_ = nullptr; Memory* memory_ = nullptr; - VkDevice device_ = nullptr; + ui::vulkan::VulkanDevice* device_ = nullptr; VkDeviceMemory gpu_memory_pool_ = nullptr; diff --git a/src/xenia/gpu/vulkan/pipeline_cache.cc b/src/xenia/gpu/vulkan/pipeline_cache.cc index 4d5dc9c49..58d7bd844 100644 --- a/src/xenia/gpu/vulkan/pipeline_cache.cc +++ b/src/xenia/gpu/vulkan/pipeline_cache.cc @@ -33,11 +33,20 @@ using xe::ui::vulkan::CheckResult; #include "xenia/gpu/vulkan/shaders/bin/quad_list_geom.h" #include "xenia/gpu/vulkan/shaders/bin/rect_list_geom.h" -PipelineCache::PipelineCache( - RegisterFile* register_file, ui::vulkan::VulkanDevice* device, - VkDescriptorSetLayout uniform_descriptor_set_layout, - VkDescriptorSetLayout texture_descriptor_set_layout) +PipelineCache::PipelineCache(RegisterFile* register_file, + ui::vulkan::VulkanDevice* device) : register_file_(register_file), device_(*device) { + // We can also use the GLSL translator with a Vulkan dialect. + shader_translator_.reset(new SpirvShaderTranslator()); +} + +PipelineCache::~PipelineCache() { Shutdown(); } + +VkResult PipelineCache::Initialize( + VkDescriptorSetLayout uniform_descriptor_set_layout, + VkDescriptorSetLayout texture_descriptor_set_layout) { + VkResult status; + // Initialize the shared driver pipeline cache. // We'll likely want to serialize this and reuse it, if that proves to be // useful. If the shaders are expensive and this helps we could do it per @@ -48,9 +57,11 @@ PipelineCache::PipelineCache( pipeline_cache_info.flags = 0; pipeline_cache_info.initialDataSize = 0; pipeline_cache_info.pInitialData = nullptr; - auto err = vkCreatePipelineCache(device_, &pipeline_cache_info, nullptr, - &pipeline_cache_); - CheckResult(err, "vkCreatePipelineCache"); + status = vkCreatePipelineCache(device_, &pipeline_cache_info, nullptr, + &pipeline_cache_); + if (status != VK_SUCCESS) { + return status; + } // Descriptors used by the pipelines. // These are the only ones we can ever bind. @@ -82,9 +93,11 @@ PipelineCache::PipelineCache( pipeline_layout_info.pushConstantRangeCount = static_cast(xe::countof(push_constant_ranges)); pipeline_layout_info.pPushConstantRanges = push_constant_ranges; - err = vkCreatePipelineLayout(*device, &pipeline_layout_info, nullptr, - &pipeline_layout_); - CheckResult(err, "vkCreatePipelineLayout"); + status = vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, + &pipeline_layout_); + if (status != VK_SUCCESS) { + return status; + } // Initialize our shared geometry shaders. // These will be used as needed to emulate primitive types Vulkan doesn't @@ -97,34 +110,48 @@ PipelineCache::PipelineCache( static_cast(sizeof(line_quad_list_geom)); shader_module_info.pCode = reinterpret_cast(line_quad_list_geom); - err = vkCreateShaderModule(device_, &shader_module_info, nullptr, - &geometry_shaders_.line_quad_list); - CheckResult(err, "vkCreateShaderModule"); + status = vkCreateShaderModule(device_, &shader_module_info, nullptr, + &geometry_shaders_.line_quad_list); + if (status != VK_SUCCESS) { + return status; + } + shader_module_info.codeSize = static_cast(sizeof(point_list_geom)); shader_module_info.pCode = reinterpret_cast(point_list_geom); - err = vkCreateShaderModule(device_, &shader_module_info, nullptr, - &geometry_shaders_.point_list); - CheckResult(err, "vkCreateShaderModule"); + status = vkCreateShaderModule(device_, &shader_module_info, nullptr, + &geometry_shaders_.point_list); + if (status != VK_SUCCESS) { + return status; + } + shader_module_info.codeSize = static_cast(sizeof(quad_list_geom)); shader_module_info.pCode = reinterpret_cast(quad_list_geom); - err = vkCreateShaderModule(device_, &shader_module_info, nullptr, - &geometry_shaders_.quad_list); - CheckResult(err, "vkCreateShaderModule"); + status = vkCreateShaderModule(device_, &shader_module_info, nullptr, + &geometry_shaders_.quad_list); + if (status != VK_SUCCESS) { + return status; + } + shader_module_info.codeSize = static_cast(sizeof(rect_list_geom)); shader_module_info.pCode = reinterpret_cast(rect_list_geom); - err = vkCreateShaderModule(device_, &shader_module_info, nullptr, - &geometry_shaders_.rect_list); - CheckResult(err, "vkCreateShaderModule"); + status = vkCreateShaderModule(device_, &shader_module_info, nullptr, + &geometry_shaders_.rect_list); + if (status != VK_SUCCESS) { + return status; + } + shader_module_info.codeSize = static_cast(sizeof(dummy_frag)); shader_module_info.pCode = reinterpret_cast(dummy_frag); - err = vkCreateShaderModule(device_, &shader_module_info, nullptr, - &dummy_pixel_shader_); + status = vkCreateShaderModule(device_, &shader_module_info, nullptr, + &dummy_pixel_shader_); + if (status != VK_SUCCESS) { + return status; + } - // We can also use the GLSL translator with a Vulkan dialect. - shader_translator_.reset(new SpirvShaderTranslator()); + return VK_SUCCESS; } -PipelineCache::~PipelineCache() { +void PipelineCache::Shutdown() { // Destroy all pipelines. for (auto it : cached_pipelines_) { vkDestroyPipeline(device_, it.second, nullptr); @@ -132,14 +159,35 @@ PipelineCache::~PipelineCache() { cached_pipelines_.clear(); // Destroy geometry shaders. - vkDestroyShaderModule(device_, geometry_shaders_.line_quad_list, nullptr); - vkDestroyShaderModule(device_, geometry_shaders_.point_list, nullptr); - vkDestroyShaderModule(device_, geometry_shaders_.quad_list, nullptr); - vkDestroyShaderModule(device_, geometry_shaders_.rect_list, nullptr); - vkDestroyShaderModule(device_, dummy_pixel_shader_, nullptr); + if (geometry_shaders_.line_quad_list) { + vkDestroyShaderModule(device_, geometry_shaders_.line_quad_list, nullptr); + geometry_shaders_.line_quad_list = nullptr; + } + if (geometry_shaders_.point_list) { + vkDestroyShaderModule(device_, geometry_shaders_.point_list, nullptr); + geometry_shaders_.point_list = nullptr; + } + if (geometry_shaders_.quad_list) { + vkDestroyShaderModule(device_, geometry_shaders_.quad_list, nullptr); + geometry_shaders_.quad_list = nullptr; + } + if (geometry_shaders_.rect_list) { + vkDestroyShaderModule(device_, geometry_shaders_.rect_list, nullptr); + geometry_shaders_.rect_list = nullptr; + } + if (dummy_pixel_shader_) { + vkDestroyShaderModule(device_, dummy_pixel_shader_, nullptr); + dummy_pixel_shader_ = nullptr; + } - vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr); - vkDestroyPipelineCache(device_, pipeline_cache_, nullptr); + if (pipeline_layout_) { + vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr); + pipeline_layout_ = nullptr; + } + if (pipeline_cache_) { + vkDestroyPipelineCache(device_, pipeline_cache_, nullptr); + pipeline_cache_ = nullptr; + } // Destroy all shaders. for (auto it : shader_map_) { @@ -334,20 +382,20 @@ void PipelineCache::DumpShaderDisasmNV( pipeline_cache_info.flags = 0; pipeline_cache_info.initialDataSize = 0; pipeline_cache_info.pInitialData = nullptr; - auto err = vkCreatePipelineCache(device_, &pipeline_cache_info, nullptr, - &dummy_pipeline_cache); - CheckResult(err, "vkCreatePipelineCache"); + auto status = vkCreatePipelineCache(device_, &pipeline_cache_info, nullptr, + &dummy_pipeline_cache); + CheckResult(status, "vkCreatePipelineCache"); // Create a pipeline on the dummy cache and dump it. VkPipeline dummy_pipeline; - err = vkCreateGraphicsPipelines(device_, dummy_pipeline_cache, 1, - &pipeline_info, nullptr, &dummy_pipeline); + status = vkCreateGraphicsPipelines(device_, dummy_pipeline_cache, 1, + &pipeline_info, nullptr, &dummy_pipeline); std::vector pipeline_data; size_t data_size = 0; - err = vkGetPipelineCacheData(device_, dummy_pipeline_cache, &data_size, - nullptr); - if (err == VK_SUCCESS) { + status = vkGetPipelineCacheData(device_, dummy_pipeline_cache, &data_size, + nullptr); + if (status == VK_SUCCESS) { pipeline_data.resize(data_size); vkGetPipelineCacheData(device_, dummy_pipeline_cache, &data_size, pipeline_data.data()); diff --git a/src/xenia/gpu/vulkan/pipeline_cache.h b/src/xenia/gpu/vulkan/pipeline_cache.h index 5b14f03ce..b3fbcdcc0 100644 --- a/src/xenia/gpu/vulkan/pipeline_cache.h +++ b/src/xenia/gpu/vulkan/pipeline_cache.h @@ -39,11 +39,13 @@ class PipelineCache { kError, }; - PipelineCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device, - VkDescriptorSetLayout uniform_descriptor_set_layout, - VkDescriptorSetLayout texture_descriptor_set_layout); + PipelineCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device); ~PipelineCache(); + VkResult Initialize(VkDescriptorSetLayout uniform_descriptor_set_layout, + VkDescriptorSetLayout texture_descriptor_set_layout); + void Shutdown(); + // Loads a shader from the cache, possibly translating it. VulkanShader* LoadShader(ShaderType shader_type, uint32_t guest_address, const uint32_t* host_address, uint32_t dword_count); diff --git a/src/xenia/gpu/vulkan/render_cache.cc b/src/xenia/gpu/vulkan/render_cache.cc index 19879fa53..b5ae200dc 100644 --- a/src/xenia/gpu/vulkan/render_cache.cc +++ b/src/xenia/gpu/vulkan/render_cache.cc @@ -510,7 +510,11 @@ bool CachedRenderPass::IsCompatible( RenderCache::RenderCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device) - : register_file_(register_file), device_(device) { + : register_file_(register_file), device_(device) {} + +RenderCache::~RenderCache() { Shutdown(); } + +VkResult RenderCache::Initialize() { VkResult status = VK_SUCCESS; // Create the buffer we'll bind to our memory. @@ -524,8 +528,11 @@ RenderCache::RenderCache(RegisterFile* register_file, buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; buffer_info.queueFamilyIndexCount = 0; buffer_info.pQueueFamilyIndices = nullptr; - status = vkCreateBuffer(*device, &buffer_info, nullptr, &edram_buffer_); + status = vkCreateBuffer(*device_, &buffer_info, nullptr, &edram_buffer_); CheckResult(status, "vkCreateBuffer"); + if (status != VK_SUCCESS) { + return status; + } // Query requirements for the buffer. // It should be 1:1. @@ -535,19 +542,24 @@ RenderCache::RenderCache(RegisterFile* register_file, // Allocate EDRAM memory. // TODO(benvanik): do we need it host visible? - edram_memory_ = device->AllocateMemory(buffer_requirements); + edram_memory_ = device_->AllocateMemory(buffer_requirements); assert_not_null(edram_memory_); + if (!edram_memory_) { + return VK_ERROR_INITIALIZATION_FAILED; + } // Bind buffer to map our entire memory. status = vkBindBufferMemory(*device_, edram_buffer_, edram_memory_, 0); CheckResult(status, "vkBindBufferMemory"); + if (status != VK_SUCCESS) { + return status; + } if (status == VK_SUCCESS) { // For debugging, upload a grid into the EDRAM buffer. uint32_t* gpu_data = nullptr; status = vkMapMemory(*device_, edram_memory_, 0, buffer_requirements.size, 0, reinterpret_cast(&gpu_data)); - CheckResult(status, "vkMapMemory"); if (status == VK_SUCCESS) { for (int i = 0; i < kEdramBufferCapacity / 4; i++) { @@ -557,9 +569,11 @@ RenderCache::RenderCache(RegisterFile* register_file, vkUnmapMemory(*device_, edram_memory_); } } + + return VK_SUCCESS; } -RenderCache::~RenderCache() { +void RenderCache::Shutdown() { // TODO(benvanik): wait for idle. // Dispose all render passes (and their framebuffers). @@ -575,8 +589,14 @@ RenderCache::~RenderCache() { cached_tile_views_.clear(); // Release underlying EDRAM memory. - vkDestroyBuffer(*device_, edram_buffer_, nullptr); - vkFreeMemory(*device_, edram_memory_, nullptr); + if (edram_buffer_) { + vkDestroyBuffer(*device_, edram_buffer_, nullptr); + edram_buffer_ = nullptr; + } + if (edram_memory_) { + vkFreeMemory(*device_, edram_memory_, nullptr); + edram_memory_ = nullptr; + } } bool RenderCache::dirty() const { diff --git a/src/xenia/gpu/vulkan/render_cache.h b/src/xenia/gpu/vulkan/render_cache.h index e6074a119..6872bca9d 100644 --- a/src/xenia/gpu/vulkan/render_cache.h +++ b/src/xenia/gpu/vulkan/render_cache.h @@ -276,6 +276,9 @@ class RenderCache { RenderCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device); ~RenderCache(); + VkResult Initialize(); + void Shutdown(); + // Call this to determine if you should start a new render pass or continue // with an already open pass. bool dirty() const; diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc index 056623abf..464a3ac14 100644 --- a/src/xenia/gpu/vulkan/texture_cache.cc +++ b/src/xenia/gpu/vulkan/texture_cache.cc @@ -128,8 +128,12 @@ TextureCache::TextureCache(Memory* memory, RegisterFile* register_file, staging_buffer_(device, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, kStagingBufferSize), wb_staging_buffer_(device, VK_BUFFER_USAGE_TRANSFER_DST_BIT, - kStagingBufferSize) { - VkResult err = VK_SUCCESS; + kStagingBufferSize) {} + +TextureCache::~TextureCache() { Shutdown(); } + +VkResult TextureCache::Initialize() { + VkResult status = VK_SUCCESS; // Descriptor pool used for all of our cached descriptors. VkDescriptorPoolSize pool_sizes[1]; @@ -176,33 +180,43 @@ TextureCache::TextureCache(Memory* memory, RegisterFile* register_file, descriptor_set_layout_info.bindingCount = static_cast(xe::countof(bindings)); descriptor_set_layout_info.pBindings = bindings; - err = vkCreateDescriptorSetLayout(*device_, &descriptor_set_layout_info, - nullptr, &texture_descriptor_set_layout_); - CheckResult(err, "vkCreateDescriptorSetLayout"); - - if (!staging_buffer_.Initialize()) { - assert_always(); + status = + vkCreateDescriptorSetLayout(*device_, &descriptor_set_layout_info, + nullptr, &texture_descriptor_set_layout_); + if (status != VK_SUCCESS) { + return status; } - if (!wb_staging_buffer_.Initialize()) { - assert_always(); + status = staging_buffer_.Initialize(); + if (status != VK_SUCCESS) { + return status; + } + + status = wb_staging_buffer_.Initialize(); + if (status != VK_SUCCESS) { + return status; } // Create a memory allocator for textures. VmaAllocatorCreateInfo alloc_info = { 0, *device_, *device_, 0, 0, nullptr, nullptr, }; - err = vmaCreateAllocator(&alloc_info, &mem_allocator_); - CheckResult(err, "vmaCreateAllocator"); + status = vmaCreateAllocator(&alloc_info, &mem_allocator_); + if (status != VK_SUCCESS) { + vkDestroyDescriptorSetLayout(*device_, texture_descriptor_set_layout_, + nullptr); + return status; + } invalidated_textures_sets_[0].reserve(64); invalidated_textures_sets_[1].reserve(64); invalidated_textures_ = &invalidated_textures_sets_[0]; device_queue_ = device_->AcquireQueue(); + return VK_SUCCESS; } -TextureCache::~TextureCache() { +void TextureCache::Shutdown() { if (device_queue_) { device_->ReleaseQueue(device_queue_); } @@ -211,7 +225,10 @@ TextureCache::~TextureCache() { ClearCache(); Scavenge(); - vmaDestroyAllocator(mem_allocator_); + if (mem_allocator_ != nullptr) { + vmaDestroyAllocator(mem_allocator_); + mem_allocator_ = nullptr; + } vkDestroyDescriptorSetLayout(*device_, texture_descriptor_set_layout_, nullptr); } diff --git a/src/xenia/gpu/vulkan/texture_cache.h b/src/xenia/gpu/vulkan/texture_cache.h index 642b2fc66..483b88bd2 100644 --- a/src/xenia/gpu/vulkan/texture_cache.h +++ b/src/xenia/gpu/vulkan/texture_cache.h @@ -76,6 +76,9 @@ class TextureCache { TraceWriter* trace_writer, ui::vulkan::VulkanDevice* device); ~TextureCache(); + VkResult Initialize(); + void Shutdown(); + // Descriptor set layout containing all possible texture bindings. // The set contains one descriptor for each texture sampler [0-31]. VkDescriptorSetLayout texture_descriptor_set_layout() const { diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.cc b/src/xenia/gpu/vulkan/vulkan_command_processor.cc index 1e50a8ab9..fd7852f15 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.cc @@ -69,10 +69,14 @@ bool VulkanCommandProcessor::SetupContext() { queue_mutex_ = &device_->primary_queue_mutex(); } + VkResult status = VK_SUCCESS; + // Setup a blitter. blitter_ = std::make_unique(); - if (!blitter_->Initialize(device_)) { + status = blitter_->Initialize(device_); + if (status != VK_SUCCESS) { XELOGE("Unable to initialize blitter"); + blitter_->Shutdown(); return false; } @@ -83,21 +87,47 @@ bool VulkanCommandProcessor::SetupContext() { // Initialize the state machine caches. buffer_cache_ = std::make_unique( register_file_, memory_, device_, kDefaultBufferCacheCapacity); + status = buffer_cache_->Initialize(); + if (status != VK_SUCCESS) { + XELOGE("Unable to initialize buffer cache"); + buffer_cache_->Shutdown(); + return false; + } + texture_cache_ = std::make_unique(memory_, register_file_, &trace_writer_, device_); - pipeline_cache_ = std::make_unique( - register_file_, device_, buffer_cache_->constant_descriptor_set_layout(), + status = texture_cache_->Initialize(); + if (status != VK_SUCCESS) { + XELOGE("Unable to initialize texture cache"); + texture_cache_->Shutdown(); + return false; + } + + pipeline_cache_ = std::make_unique(register_file_, device_); + status = pipeline_cache_->Initialize( + buffer_cache_->constant_descriptor_set_layout(), texture_cache_->texture_descriptor_set_layout()); + if (status != VK_SUCCESS) { + XELOGE("Unable to initialize pipeline cache"); + pipeline_cache_->Shutdown(); + return false; + } + render_cache_ = std::make_unique(register_file_, device_); + status = render_cache_->Initialize(); + if (status != VK_SUCCESS) { + XELOGE("Unable to initialize render cache"); + render_cache_->Shutdown(); + return false; + } VkEventCreateInfo info = { VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, nullptr, 0, }; - VkResult result = - vkCreateEvent(*device_, &info, nullptr, - reinterpret_cast(&swap_state_.backend_data)); - if (result != VK_SUCCESS) { + status = vkCreateEvent(*device_, &info, nullptr, + reinterpret_cast(&swap_state_.backend_data)); + if (status != VK_SUCCESS) { return false; } diff --git a/src/xenia/ui/vulkan/blitter.cc b/src/xenia/ui/vulkan/blitter.cc index 587c4aa46..5e838313e 100644 --- a/src/xenia/ui/vulkan/blitter.cc +++ b/src/xenia/ui/vulkan/blitter.cc @@ -23,30 +23,41 @@ namespace vulkan { Blitter::Blitter() {} Blitter::~Blitter() { Shutdown(); } -bool Blitter::Initialize(VulkanDevice* device) { +VkResult Blitter::Initialize(VulkanDevice* device) { device_ = device; + VkResult status = VK_SUCCESS; + // Shaders VkShaderModuleCreateInfo shader_create_info; std::memset(&shader_create_info, 0, sizeof(shader_create_info)); shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shader_create_info.codeSize = sizeof(blit_vert); shader_create_info.pCode = reinterpret_cast(blit_vert); - auto result = vkCreateShaderModule(*device_, &shader_create_info, nullptr, - &blit_vertex_); - CheckResult(result, "vkCreateShaderModule"); + status = vkCreateShaderModule(*device_, &shader_create_info, nullptr, + &blit_vertex_); + CheckResult(status, "vkCreateShaderModule"); + if (status != VK_SUCCESS) { + return status; + } shader_create_info.codeSize = sizeof(blit_color_frag); shader_create_info.pCode = reinterpret_cast(blit_color_frag); - result = vkCreateShaderModule(*device_, &shader_create_info, nullptr, + status = vkCreateShaderModule(*device_, &shader_create_info, nullptr, &blit_color_); - CheckResult(result, "vkCreateShaderModule"); + CheckResult(status, "vkCreateShaderModule"); + if (status != VK_SUCCESS) { + return status; + } shader_create_info.codeSize = sizeof(blit_depth_frag); shader_create_info.pCode = reinterpret_cast(blit_depth_frag); - result = vkCreateShaderModule(*device_, &shader_create_info, nullptr, + status = vkCreateShaderModule(*device_, &shader_create_info, nullptr, &blit_depth_); - CheckResult(result, "vkCreateShaderModule"); + CheckResult(status, "vkCreateShaderModule"); + if (status != VK_SUCCESS) { + return status; + } // Create the descriptor set layout used for our texture sampler. // As it changes almost every draw we cache it per texture. @@ -63,9 +74,12 @@ bool Blitter::Initialize(VulkanDevice* device) { texture_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; texture_binding.pImmutableSamplers = nullptr; texture_set_layout_info.pBindings = &texture_binding; - result = vkCreateDescriptorSetLayout(*device_, &texture_set_layout_info, + status = vkCreateDescriptorSetLayout(*device_, &texture_set_layout_info, nullptr, &descriptor_set_layout_); - CheckResult(result, "vkCreateDescriptorSetLayout"); + CheckResult(status, "vkCreateDescriptorSetLayout"); + if (status != VK_SUCCESS) { + return status; + } // Create a descriptor pool VkDescriptorPoolSize pool_sizes[1]; @@ -99,9 +113,12 @@ bool Blitter::Initialize(VulkanDevice* device) { pipeline_layout_info.pushConstantRangeCount = static_cast(xe::countof(push_constant_ranges)); pipeline_layout_info.pPushConstantRanges = push_constant_ranges; - result = vkCreatePipelineLayout(*device_, &pipeline_layout_info, nullptr, + status = vkCreatePipelineLayout(*device_, &pipeline_layout_info, nullptr, &pipeline_layout_); - CheckResult(result, "vkCreatePipelineLayout"); + CheckResult(status, "vkCreatePipelineLayout"); + if (status != VK_SUCCESS) { + return status; + } // Create two samplers. VkSamplerCreateInfo sampler_create_info = { @@ -124,31 +141,63 @@ bool Blitter::Initialize(VulkanDevice* device) { VK_BORDER_COLOR_INT_TRANSPARENT_BLACK, VK_FALSE, }; - result = + status = vkCreateSampler(*device_, &sampler_create_info, nullptr, &samp_nearest_); - CheckResult(result, "vkCreateSampler"); + CheckResult(status, "vkCreateSampler"); + if (status != VK_SUCCESS) { + return status; + } sampler_create_info.minFilter = VK_FILTER_LINEAR; sampler_create_info.magFilter = VK_FILTER_LINEAR; sampler_create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - result = + status = vkCreateSampler(*device_, &sampler_create_info, nullptr, &samp_linear_); - CheckResult(result, "vkCreateSampler"); + CheckResult(status, "vkCreateSampler"); + if (status != VK_SUCCESS) { + return status; + } - return true; + return VK_SUCCESS; } void Blitter::Shutdown() { - vkDestroySampler(*device_, samp_nearest_, nullptr); - vkDestroySampler(*device_, samp_linear_, nullptr); - vkDestroyShaderModule(*device_, blit_vertex_, nullptr); - vkDestroyShaderModule(*device_, blit_color_, nullptr); - vkDestroyShaderModule(*device_, blit_depth_, nullptr); - vkDestroyPipeline(*device_, pipeline_color_, nullptr); - vkDestroyPipeline(*device_, pipeline_depth_, nullptr); - vkDestroyPipelineLayout(*device_, pipeline_layout_, nullptr); - vkDestroyDescriptorSetLayout(*device_, descriptor_set_layout_, nullptr); - + if (samp_nearest_) { + vkDestroySampler(*device_, samp_nearest_, nullptr); + samp_nearest_ = nullptr; + } + if (samp_linear_) { + vkDestroySampler(*device_, samp_linear_, nullptr); + samp_linear_ = nullptr; + } + if (blit_vertex_) { + vkDestroyShaderModule(*device_, blit_vertex_, nullptr); + blit_vertex_ = nullptr; + } + if (blit_color_) { + vkDestroyShaderModule(*device_, blit_color_, nullptr); + blit_color_ = nullptr; + } + if (blit_depth_) { + vkDestroyShaderModule(*device_, blit_depth_, nullptr); + blit_depth_ = nullptr; + } + if (pipeline_color_) { + vkDestroyPipeline(*device_, pipeline_color_, nullptr); + pipeline_color_ = nullptr; + } + if (pipeline_depth_) { + vkDestroyPipeline(*device_, pipeline_depth_, nullptr); + pipeline_depth_ = nullptr; + } + if (pipeline_layout_) { + vkDestroyPipelineLayout(*device_, pipeline_layout_, nullptr); + pipeline_layout_ = nullptr; + } + if (descriptor_set_layout_) { + vkDestroyDescriptorSetLayout(*device_, descriptor_set_layout_, nullptr); + descriptor_set_layout_ = nullptr; + } for (auto& pipeline : pipelines_) { vkDestroyPipeline(*device_, pipeline.second, nullptr); } diff --git a/src/xenia/ui/vulkan/blitter.h b/src/xenia/ui/vulkan/blitter.h index 1ec48fd4f..78cf1366a 100644 --- a/src/xenia/ui/vulkan/blitter.h +++ b/src/xenia/ui/vulkan/blitter.h @@ -27,7 +27,7 @@ class Blitter { Blitter(); ~Blitter(); - bool Initialize(VulkanDevice* device); + VkResult Initialize(VulkanDevice* device); void Scavenge(); void Shutdown(); diff --git a/src/xenia/ui/vulkan/circular_buffer.cc b/src/xenia/ui/vulkan/circular_buffer.cc index 7b9b4bae2..0347413cc 100644 --- a/src/xenia/ui/vulkan/circular_buffer.cc +++ b/src/xenia/ui/vulkan/circular_buffer.cc @@ -46,7 +46,8 @@ CircularBuffer::CircularBuffer(VulkanDevice* device, VkBufferUsageFlags usage, } CircularBuffer::~CircularBuffer() { Shutdown(); } -bool CircularBuffer::Initialize(VkDeviceMemory memory, VkDeviceSize offset) { +VkResult CircularBuffer::Initialize(VkDeviceMemory memory, + VkDeviceSize offset) { assert_true(offset % alignment_ == 0); gpu_memory_ = memory; gpu_base_ = offset; @@ -59,7 +60,7 @@ bool CircularBuffer::Initialize(VkDeviceMemory memory, VkDeviceSize offset) { if (status != VK_SUCCESS) { XELOGE("CircularBuffer::Initialize - Failed to bind memory!"); Shutdown(); - return false; + return status; } // Map the memory so we can access it. @@ -69,13 +70,13 @@ bool CircularBuffer::Initialize(VkDeviceMemory memory, VkDeviceSize offset) { if (status != VK_SUCCESS) { XELOGE("CircularBuffer::Initialize - Failed to map memory!"); Shutdown(); - return false; + return status; } - return true; + return VK_SUCCESS; } -bool CircularBuffer::Initialize() { +VkResult CircularBuffer::Initialize() { VkResult status = VK_SUCCESS; VkMemoryRequirements reqs; @@ -87,7 +88,7 @@ bool CircularBuffer::Initialize() { if (!gpu_memory_) { XELOGE("CircularBuffer::Initialize - Failed to allocate memory!"); Shutdown(); - return false; + return VK_ERROR_INITIALIZATION_FAILED; } capacity_ = reqs.size; @@ -99,7 +100,7 @@ bool CircularBuffer::Initialize() { if (status != VK_SUCCESS) { XELOGE("CircularBuffer::Initialize - Failed to bind memory!"); Shutdown(); - return false; + return status; } // Map the memory so we can access it. @@ -109,10 +110,10 @@ bool CircularBuffer::Initialize() { if (status != VK_SUCCESS) { XELOGE("CircularBuffer::Initialize - Failed to map memory!"); Shutdown(); - return false; + return status; } - return true; + return VK_SUCCESS; } void CircularBuffer::Shutdown() { diff --git a/src/xenia/ui/vulkan/circular_buffer.h b/src/xenia/ui/vulkan/circular_buffer.h index d7504f5e8..6940b2532 100644 --- a/src/xenia/ui/vulkan/circular_buffer.h +++ b/src/xenia/ui/vulkan/circular_buffer.h @@ -43,8 +43,8 @@ class CircularBuffer { VkFence fence; }; - bool Initialize(VkDeviceMemory memory, VkDeviceSize offset); - bool Initialize(); + VkResult Initialize(VkDeviceMemory memory, VkDeviceSize offset); + VkResult Initialize(); void Shutdown(); void GetBufferMemoryRequirements(VkMemoryRequirements* reqs);