aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaebaek Seo <duke.acacia@gmail.com>2019-01-10 15:47:32 -0500
committerGitHub <noreply@github.com>2019-01-10 15:47:32 -0500
commit610296cc045b094509a6bd2f420ebdef1f98edf9 (patch)
treec7dd0b7a076eb8762e0be39cd2ddcb9694fa6527 /src
parentfb74519a68fe77f30ca57919bf1f0d6329f11644 (diff)
downloadamber-610296cc045b094509a6bd2f420ebdef1f98edf9.tar.gz
Vulkan: enable validation layer (#184)
Fixes #153
Diffstat (limited to 'src')
-rw-r--r--src/amber.cc5
-rw-r--r--src/vulkan/CMakeLists.txt1
-rw-r--r--src/vulkan/buffer.cc20
-rw-r--r--src/vulkan/buffer_descriptor.cc10
-rw-r--r--src/vulkan/command.cc10
-rw-r--r--src/vulkan/device.cc161
-rw-r--r--src/vulkan/device.h2
-rw-r--r--src/vulkan/engine_vulkan.cc17
-rw-r--r--src/vulkan/frame_buffer.cc5
-rw-r--r--src/vulkan/graphics_pipeline.cc4
-rw-r--r--src/vulkan/image.cc13
-rw-r--r--src/vulkan/log.cc44
-rw-r--r--src/vulkan/log.h29
-rw-r--r--src/vulkan/pipeline.cc24
-rw-r--r--src/vulkan/resource.cc10
15 files changed, 304 insertions, 51 deletions
diff --git a/src/amber.cc b/src/amber.cc
index 65ef22d..021b4ef 100644
--- a/src/amber.cc
+++ b/src/amber.cc
@@ -81,8 +81,11 @@ amber::Result Amber::ExecuteWithShaderData(const amber::Recipe* recipe,
Executor executor;
r = executor.Execute(engine.get(), script, shader_data);
- if (!r.IsSuccess())
+ if (!r.IsSuccess()) {
+ // Clean up Vulkan/Dawn objects
+ engine->Shutdown();
return r;
+ }
return engine->Shutdown();
}
diff --git a/src/vulkan/CMakeLists.txt b/src/vulkan/CMakeLists.txt
index 46ec379..aa8bc74 100644
--- a/src/vulkan/CMakeLists.txt
+++ b/src/vulkan/CMakeLists.txt
@@ -23,6 +23,7 @@ set(VULKAN_ENGINE_SOURCES
engine_vulkan.cc
format_data.cc
frame_buffer.cc
+ log.cc
resource.cc
image.cc
pipeline.cc
diff --git a/src/vulkan/buffer.cc b/src/vulkan/buffer.cc
index c6ce26e..8276c09 100644
--- a/src/vulkan/buffer.cc
+++ b/src/vulkan/buffer.cc
@@ -99,20 +99,18 @@ void Buffer::CopyFromBuffer(VkCommandBuffer command, const Buffer& src) {
}
void Buffer::Shutdown() {
- // TODO(jaebaek): Doublecheck what happens if |view_| is VK_NULL_HANDLE on
- // Android and Windows.
- if (view_ != VK_NULL_HANDLE) {
+ if (view_ != VK_NULL_HANDLE)
vkDestroyBufferView(GetDevice(), view_, nullptr);
- view_ = VK_NULL_HANDLE;
- }
- if (is_buffer_host_accessible_)
- UnMapMemory(memory_);
+ if (memory_ != VK_NULL_HANDLE) {
+ if (is_buffer_host_accessible_)
+ UnMapMemory(memory_);
+
+ vkFreeMemory(GetDevice(), memory_, nullptr);
+ }
- vkDestroyBuffer(GetDevice(), buffer_, nullptr);
- vkFreeMemory(GetDevice(), memory_, nullptr);
- buffer_ = VK_NULL_HANDLE;
- memory_ = VK_NULL_HANDLE;
+ if (buffer_ != VK_NULL_HANDLE)
+ vkDestroyBuffer(GetDevice(), buffer_, nullptr);
if (!is_buffer_host_accessible_)
Resource::Shutdown();
diff --git a/src/vulkan/buffer_descriptor.cc b/src/vulkan/buffer_descriptor.cc
index baf736c..b4d11c6 100644
--- a/src/vulkan/buffer_descriptor.cc
+++ b/src/vulkan/buffer_descriptor.cc
@@ -173,9 +173,13 @@ ResourceInfo BufferDescriptor::GetResourceInfo() {
}
void BufferDescriptor::Shutdown() {
- buffer_->Shutdown();
- for (auto& buffer : not_destroyed_buffers_)
- buffer->Shutdown();
+ if (buffer_)
+ buffer_->Shutdown();
+
+ for (auto& buffer : not_destroyed_buffers_) {
+ if (buffer)
+ buffer->Shutdown();
+ }
}
} // namespace vulkan
diff --git a/src/vulkan/command.cc b/src/vulkan/command.cc
index 24abe12..02159d8 100644
--- a/src/vulkan/command.cc
+++ b/src/vulkan/command.cc
@@ -39,7 +39,8 @@ Result CommandPool::Initialize(uint32_t queue_family_index) {
}
void CommandPool::Shutdown() {
- vkDestroyCommandPool(device_, pool_, nullptr);
+ if (pool_ != VK_NULL_HANDLE)
+ vkDestroyCommandPool(device_, pool_, nullptr);
}
CommandBuffer::CommandBuffer(VkDevice device, VkCommandPool pool, VkQueue queue)
@@ -123,8 +124,11 @@ Result CommandBuffer::SubmitAndReset(uint32_t timeout_ms) {
}
void CommandBuffer::Shutdown() {
- vkDestroyFence(device_, fence_, nullptr);
- vkFreeCommandBuffers(device_, pool_, 1, &command_);
+ if (fence_ != VK_NULL_HANDLE)
+ vkDestroyFence(device_, fence_, nullptr);
+
+ if (command_ != VK_NULL_HANDLE)
+ vkFreeCommandBuffers(device_, pool_, 1, &command_);
}
} // namespace vulkan
diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc
index e211e4e..c83e9a1 100644
--- a/src/vulkan/device.cc
+++ b/src/vulkan/device.cc
@@ -14,16 +14,61 @@
#include "src/vulkan/device.h"
+#include <cassert>
+#include <cstring>
#include <memory>
#include <set>
#include <vector>
#include "src/make_unique.h"
+#include "src/vulkan/log.h"
namespace amber {
namespace vulkan {
namespace {
+const char* const kRequiredValidationLayers[] = {
+#ifdef __ANDROID__
+ // Note that the order of enabled layers is important. It is
+ // based on Android NDK Vulkan document.
+ "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation",
+ "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation",
+ "VK_LAYER_GOOGLE_unique_objects",
+#else // __ANDROID__
+ "VK_LAYER_LUNARG_standard_validation",
+#endif // __ANDROID__
+};
+
+const size_t kNumberOfRequiredValidationLayers =
+ sizeof(kRequiredValidationLayers) / sizeof(const char*);
+
+const char* kExtensionForValidationLayer = "VK_EXT_debug_report";
+
+VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flag,
+ VkDebugReportObjectTypeEXT,
+ uint64_t,
+ size_t,
+ int32_t,
+ const char* layerPrefix,
+ const char* msg,
+ void*) {
+ std::string flag_message;
+ switch (flag) {
+ case VK_DEBUG_REPORT_ERROR_BIT_EXT:
+ flag_message = "[ERROR]";
+ break;
+ case VK_DEBUG_REPORT_WARNING_BIT_EXT:
+ flag_message = "[WARNING]";
+ break;
+ default:
+ flag_message = "[UNKNOWN]";
+ break;
+ }
+
+ LogError(flag_message + " validation layer (" + layerPrefix + "):\n" + msg);
+ return VK_FALSE;
+}
+
VkPhysicalDeviceFeatures RequestedFeatures(
const std::vector<Feature>& required_features) {
VkPhysicalDeviceFeatures requested_features = {};
@@ -491,6 +536,61 @@ bool AreAllExtensionsSupported(
return required_extension_set.empty();
}
+Result AreAllValidationLayersSupported() {
+ std::vector<VkLayerProperties> available_layer_properties;
+ uint32_t available_layer_count = 0;
+ if (vkEnumerateInstanceLayerProperties(&available_layer_count, nullptr) !=
+ VK_SUCCESS) {
+ return Result("Vulkan: vkEnumerateInstanceLayerProperties fail");
+ }
+ available_layer_properties.resize(available_layer_count);
+ if (vkEnumerateInstanceLayerProperties(&available_layer_count,
+ available_layer_properties.data()) !=
+ VK_SUCCESS) {
+ return Result("Vulkan: vkEnumerateInstanceLayerProperties fail");
+ }
+
+ std::set<std::string> required_layer_set(
+ kRequiredValidationLayers,
+ &kRequiredValidationLayers[kNumberOfRequiredValidationLayers]);
+ for (const auto& property : available_layer_properties) {
+ required_layer_set.erase(property.layerName);
+ }
+
+ if (required_layer_set.empty())
+ return {};
+
+ std::string missing_layers;
+ for (const auto& missing_layer : required_layer_set)
+ missing_layers = missing_layers + missing_layer + ",\n\t\t";
+ return Result("Vulkan: missing validation layers:\n\t\t" + missing_layers);
+}
+
+bool AreAllValidationExtensionsSupported() {
+ for (const auto& layer : kRequiredValidationLayers) {
+ uint32_t available_extension_count = 0;
+ std::vector<VkExtensionProperties> extension_properties;
+
+ if (vkEnumerateInstanceExtensionProperties(
+ layer, &available_extension_count, nullptr) != VK_SUCCESS) {
+ return false;
+ }
+ extension_properties.resize(available_extension_count);
+ if (vkEnumerateInstanceExtensionProperties(
+ layer, &available_extension_count, extension_properties.data()) !=
+ VK_SUCCESS) {
+ return false;
+ }
+
+ for (const auto& ext : extension_properties) {
+ if (!strcmp(kExtensionForValidationLayer, ext.extensionName))
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace
Device::Device() = default;
@@ -512,6 +612,14 @@ Device::~Device() = default;
void Device::Shutdown() {
if (destroy_device_) {
vkDestroyDevice(device_, nullptr);
+
+ auto vkDestroyDebugReportCallbackEXT =
+ reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
+ vkGetInstanceProcAddr(instance_,
+ "vkDestroyDebugReportCallbackEXT"));
+ assert(vkDestroyDebugReportCallbackEXT);
+ vkDestroyDebugReportCallbackEXT(instance_, callback_, nullptr);
+
vkDestroyInstance(instance_, nullptr);
}
}
@@ -523,6 +631,10 @@ Result Device::Initialize(const std::vector<Feature>& required_features,
if (!r.IsSuccess())
return r;
+ r = CreateDebugReportCallback();
+ if (!r.IsSuccess())
+ return r;
+
r = ChoosePhysicalDevice(required_features, required_extensions);
if (!r.IsSuccess())
return r;
@@ -577,21 +689,50 @@ bool Device::ChooseQueueFamilyIndex(const VkPhysicalDevice& physical_device) {
}
Result Device::CreateInstance() {
- VkApplicationInfo appInfo = {};
- appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);
-
- VkInstanceCreateInfo instInfo = {};
- instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- instInfo.pApplicationInfo = &appInfo;
- // TODO(jaebaek): Enable layers, extensions
-
- if (vkCreateInstance(&instInfo, nullptr, &instance_) != VK_SUCCESS)
+ VkApplicationInfo app_info = {};
+ app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ app_info.apiVersion = VK_MAKE_VERSION(1, 0, 0);
+
+ Result r = AreAllValidationLayersSupported();
+ if (!r.IsSuccess())
+ return r;
+
+ if (!AreAllValidationExtensionsSupported())
+ return Result("Vulkan: extensions of validation layers are not supported");
+
+ VkInstanceCreateInfo instance_info = {};
+ instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ instance_info.pApplicationInfo = &app_info;
+ instance_info.enabledLayerCount = kNumberOfRequiredValidationLayers;
+ instance_info.ppEnabledLayerNames = kRequiredValidationLayers;
+ instance_info.enabledExtensionCount = 1U;
+ instance_info.ppEnabledExtensionNames = &kExtensionForValidationLayer;
+
+ if (vkCreateInstance(&instance_info, nullptr, &instance_) != VK_SUCCESS)
return Result("Vulkan::Calling vkCreateInstance Fail");
return {};
}
+Result Device::CreateDebugReportCallback() {
+ VkDebugReportCallbackCreateInfoEXT info = {};
+ info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
+ info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
+ info.pfnCallback = debugCallback;
+
+ auto vkCreateDebugReportCallbackEXT =
+ reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
+ vkGetInstanceProcAddr(instance_, "vkCreateDebugReportCallbackEXT"));
+ if (!vkCreateDebugReportCallbackEXT)
+ return Result("Vulkan: vkCreateDebugReportCallbackEXT is nullptr");
+
+ if (vkCreateDebugReportCallbackEXT(instance_, &info, nullptr, &callback_) !=
+ VK_SUCCESS) {
+ return Result("Vulkan: vkCreateDebugReportCallbackEXT fail");
+ }
+ return {};
+}
+
Result Device::ChoosePhysicalDevice(
const std::vector<Feature>& required_features,
const std::vector<std::string>& required_extensions) {
diff --git a/src/vulkan/device.h b/src/vulkan/device.h
index df161da..5afc550 100644
--- a/src/vulkan/device.h
+++ b/src/vulkan/device.h
@@ -54,6 +54,7 @@ class Device {
private:
Result CreateInstance();
+ Result CreateDebugReportCallback();
// Get a physical device by checking if the physical device has a proper
// queue family, required features, and required extensions. Note that
@@ -77,6 +78,7 @@ class Device {
const std::vector<std::string>& required_extensions);
VkInstance instance_ = VK_NULL_HANDLE;
+ VkDebugReportCallbackEXT callback_ = VK_NULL_HANDLE;
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
VkPhysicalDeviceMemoryProperties physical_memory_properties_ = {};
VkPhysicalDeviceFeatures available_physical_device_features_ = {};
diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc
index 0dfe51c..1533abb 100644
--- a/src/vulkan/engine_vulkan.cc
+++ b/src/vulkan/engine_vulkan.cc
@@ -144,15 +144,24 @@ Result EngineVulkan::InitializeWithConfig(
}
Result EngineVulkan::Shutdown() {
- for (auto it = modules_.begin(); it != modules_.end(); ++it)
- vkDestroyShaderModule(device_->GetDevice(), it->second, nullptr);
+ if (!device_)
+ return {};
+
+ for (auto it = modules_.begin(); it != modules_.end(); ++it) {
+ auto vk_device = device_->GetDevice();
+ if (vk_device != VK_NULL_HANDLE && it->second != VK_NULL_HANDLE)
+ vkDestroyShaderModule(vk_device, it->second, nullptr);
+ }
- pipeline_->Shutdown();
+ if (pipeline_)
+ pipeline_->Shutdown();
if (vertex_buffer_)
vertex_buffer_->Shutdown();
- pool_->Shutdown();
+ if (pool_)
+ pool_->Shutdown();
+
device_->Shutdown();
return {};
}
diff --git a/src/vulkan/frame_buffer.cc b/src/vulkan/frame_buffer.cc
index 2cc4a1a..e05a1a5 100644
--- a/src/vulkan/frame_buffer.cc
+++ b/src/vulkan/frame_buffer.cc
@@ -133,9 +133,12 @@ Result FrameBuffer::ChangeFrameImageLayout(VkCommandBuffer command,
}
void FrameBuffer::Shutdown() {
- vkDestroyFramebuffer(device_, frame_, nullptr);
+ if (frame_ != VK_NULL_HANDLE)
+ vkDestroyFramebuffer(device_, frame_, nullptr);
+
if (color_image_)
color_image_->Shutdown();
+
if (depth_image_)
depth_image_->Shutdown();
}
diff --git a/src/vulkan/graphics_pipeline.cc b/src/vulkan/graphics_pipeline.cc
index 2b9a9e6..fad10d8 100644
--- a/src/vulkan/graphics_pipeline.cc
+++ b/src/vulkan/graphics_pipeline.cc
@@ -597,7 +597,9 @@ void GraphicsPipeline::Shutdown() {
Pipeline::Shutdown();
frame_->Shutdown();
- vkDestroyRenderPass(device_, render_pass_, nullptr);
+
+ if (render_pass_ != VK_NULL_HANDLE)
+ vkDestroyRenderPass(device_, render_pass_, nullptr);
}
} // namespace vulkan
diff --git a/src/vulkan/image.cc b/src/vulkan/image.cc
index 7b64daf..256be35 100644
--- a/src/vulkan/image.cc
+++ b/src/vulkan/image.cc
@@ -112,13 +112,14 @@ Result Image::CreateVkImageView() {
}
void Image::Shutdown() {
- vkDestroyImageView(GetDevice(), view_, nullptr);
- vkDestroyImage(GetDevice(), image_, nullptr);
- vkFreeMemory(GetDevice(), memory_, nullptr);
+ if (view_ != VK_NULL_HANDLE)
+ vkDestroyImageView(GetDevice(), view_, nullptr);
- view_ = VK_NULL_HANDLE;
- image_ = VK_NULL_HANDLE;
- memory_ = VK_NULL_HANDLE;
+ if (image_ != VK_NULL_HANDLE)
+ vkDestroyImage(GetDevice(), image_, nullptr);
+
+ if (memory_ != VK_NULL_HANDLE)
+ vkFreeMemory(GetDevice(), memory_, nullptr);
Resource::Shutdown();
}
diff --git a/src/vulkan/log.cc b/src/vulkan/log.cc
new file mode 100644
index 0000000..32ae55e
--- /dev/null
+++ b/src/vulkan/log.cc
@@ -0,0 +1,44 @@
+// Copyright 2018 The Amber Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/vulkan/log.h"
+
+#include <string>
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#else // __ANDROID__
+#include <iostream>
+#endif // __ANDROID__
+
+namespace amber {
+namespace vulkan {
+namespace {
+
+#ifdef __ANDROID__
+const char* kTAG = "Amber";
+#endif // __ANDROID__
+
+} // namespace
+
+void LogError(const std::string& msg) {
+#ifdef __ANDROID__
+ ((void)__android_log_print(ANDROID_LOG_ERROR, kTAG, "%s", msg.c_str()));
+#else // __ANDROID__
+ std::cerr << msg << std::endl << std::flush;
+#endif // __ANDROID__
+}
+
+} // namespace vulkan
+} // namespace amber
diff --git a/src/vulkan/log.h b/src/vulkan/log.h
new file mode 100644
index 0000000..c624590
--- /dev/null
+++ b/src/vulkan/log.h
@@ -0,0 +1,29 @@
+// Copyright 2018 The Amber Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_VULKAN_LOG_H_
+#define SRC_VULKAN_LOG_H_
+
+#include <string>
+
+namespace amber {
+namespace vulkan {
+
+// This method is used for debug reports from Vulkan validation layers.
+void LogError(const std::string& msg);
+
+} // namespace vulkan
+} // namespace amber
+
+#endif // SRC_VULKAN_LOG_H_
diff --git a/src/vulkan/pipeline.cc b/src/vulkan/pipeline.cc
index c5edbc5..1e8f917 100644
--- a/src/vulkan/pipeline.cc
+++ b/src/vulkan/pipeline.cc
@@ -66,24 +66,32 @@ Result Pipeline::InitializeCommandBuffer(VkCommandPool pool, VkQueue queue) {
}
void Pipeline::Shutdown() {
- Result r = command_->End();
- if (r.IsSuccess())
- command_->SubmitAndReset(fence_timeout_ms_);
- command_->Shutdown();
+ if (command_) {
+ Result r = command_->End();
+ if (r.IsSuccess())
+ command_->SubmitAndReset(fence_timeout_ms_);
+
+ command_->Shutdown();
+ }
DestroyVkDescriptorRelatedObjects();
}
void Pipeline::DestroyVkDescriptorRelatedObjects() {
for (auto& info : descriptor_set_info_) {
- vkDestroyDescriptorSetLayout(device_, info.layout, nullptr);
+ if (info.layout != VK_NULL_HANDLE)
+ vkDestroyDescriptorSetLayout(device_, info.layout, nullptr);
+
if (info.empty)
continue;
- vkDestroyDescriptorPool(device_, info.pool, nullptr);
+ if (info.pool != VK_NULL_HANDLE)
+ vkDestroyDescriptorPool(device_, info.pool, nullptr);
- for (auto& desc : info.descriptors_)
- desc->Shutdown();
+ for (auto& desc : info.descriptors_) {
+ if (desc)
+ desc->Shutdown();
+ }
}
if (pipeline_layout_ != VK_NULL_HANDLE)
diff --git a/src/vulkan/resource.cc b/src/vulkan/resource.cc
index be9bd0f..92a1462 100644
--- a/src/vulkan/resource.cc
+++ b/src/vulkan/resource.cc
@@ -56,9 +56,13 @@ Resource::Resource(VkDevice device,
Resource::~Resource() = default;
void Resource::Shutdown() {
- UnMapMemory(host_accessible_memory_);
- vkDestroyBuffer(device_, host_accessible_buffer_, nullptr);
- vkFreeMemory(device_, host_accessible_memory_, nullptr);
+ if (host_accessible_memory_ != VK_NULL_HANDLE) {
+ UnMapMemory(host_accessible_memory_);
+ vkFreeMemory(device_, host_accessible_memory_, nullptr);
+ }
+
+ if (host_accessible_buffer_ != VK_NULL_HANDLE)
+ vkDestroyBuffer(device_, host_accessible_buffer_, nullptr);
}
Result Resource::Initialize() {