aboutsummaryrefslogtreecommitdiff
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
parentfb74519a68fe77f30ca57919bf1f0d6329f11644 (diff)
downloadamber-610296cc045b094509a6bd2f420ebdef1f98edf9.tar.gz
Vulkan: enable validation layer (#184)
Fixes #153
-rw-r--r--samples/CMakeLists.txt1
-rw-r--r--samples/config_helper_vulkan.cc146
-rw-r--r--samples/config_helper_vulkan.h5
-rw-r--r--samples/log.cc42
-rw-r--r--samples/log.h27
-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
-rw-r--r--tests/cases/compute_in_spirv_generated_by_clspv.amber164
21 files changed, 524 insertions, 216 deletions
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index 73a617a..58243d7 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -17,6 +17,7 @@ include_directories("${PROJECT_SOURCE_DIR}/include")
set(AMBER_SOURCES
amber.cc
config_helper.cc
+ log.cc
${CMAKE_BINARY_DIR}/src/build-versions.h.fake
)
diff --git a/samples/config_helper_vulkan.cc b/samples/config_helper_vulkan.cc
index 625d665..14d91db 100644
--- a/samples/config_helper_vulkan.cc
+++ b/samples/config_helper_vulkan.cc
@@ -16,11 +16,56 @@
#include <algorithm>
#include <cassert>
+#include <cstring>
#include <set>
+#include "samples/log.h"
+
namespace sample {
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;
+}
+
// Convert required features given as a string array to
// VkPhysicalDeviceFeatures.
VkPhysicalDeviceFeatures NamesToVulkanFeatures(
@@ -255,6 +300,62 @@ VkPhysicalDeviceFeatures NamesToVulkanFeatures(
return required_vulkan_features;
}
+bool AreAllValidationLayersSupported() {
+ std::vector<VkLayerProperties> available_layer_properties;
+ uint32_t available_layer_count = 0;
+ if (vkEnumerateInstanceLayerProperties(&available_layer_count, nullptr) !=
+ VK_SUCCESS) {
+ return false;
+ }
+ available_layer_properties.resize(available_layer_count);
+ if (vkEnumerateInstanceLayerProperties(&available_layer_count,
+ available_layer_properties.data()) !=
+ VK_SUCCESS) {
+ return false;
+ }
+
+ 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 true;
+
+ std::string missing_layers;
+ for (const auto& missing_layer : required_layer_set)
+ missing_layers = missing_layers + missing_layer + ",\n\t\t";
+ LogError("Vulkan: missing validation layers:\n\t\t" + missing_layers);
+ return true;
+}
+
+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;
+}
+
// Check if |physical_device| supports all required features given
// in |required_features|.
bool AreAllRequiredFeaturesSupported(
@@ -561,14 +662,46 @@ void ConfigHelperVulkan::CreateVulkanInstance() {
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.apiVersion = VK_MAKE_VERSION(1, 0, 0);
+ if (!AreAllValidationLayersSupported()) {
+ assert(false && "Sample: not all validation layers are supported");
+ }
+
+ if (!AreAllValidationExtensionsSupported()) {
+ assert(false &&
+ "Sample: 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;
assert(vkCreateInstance(&instance_info, nullptr, &vulkan_instance_) ==
VK_SUCCESS);
}
+void ConfigHelperVulkan::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(vulkan_instance_,
+ "vkCreateDebugReportCallbackEXT"));
+ if (!vkCreateDebugReportCallbackEXT)
+ assert(false && "Sample: vkCreateDebugReportCallbackEXT is nullptr");
+
+ if (vkCreateDebugReportCallbackEXT(vulkan_instance_, &info, nullptr,
+ &vulkan_callback_) != VK_SUCCESS) {
+ assert(false && "Sample: vkCreateDebugReportCallbackEXT fail");
+ }
+}
+
void ConfigHelperVulkan::ChooseVulkanPhysicalDevice(
const VkPhysicalDeviceFeatures& required_features,
const std::vector<std::string>& required_extensions) {
@@ -607,7 +740,7 @@ void ConfigHelperVulkan::ChooseVulkanPhysicalDevice(
void ConfigHelperVulkan::CreateVulkanDevice(
const VkPhysicalDeviceFeatures& required_features,
const std::vector<std::string>& required_extensions) {
- VkDeviceQueueCreateInfo queue_info;
+ VkDeviceQueueCreateInfo queue_info = {};
const float priorities[] = {1.0f};
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
@@ -640,6 +773,7 @@ std::unique_ptr<amber::EngineConfig> ConfigHelperVulkan::CreateConfig(
auto required_vulkan_features = NamesToVulkanFeatures(required_features);
CreateVulkanInstance();
+ CreateDebugReportCallback();
ChooseVulkanPhysicalDevice(required_vulkan_features, required_extensions);
CreateVulkanDevice(required_vulkan_features, required_extensions);
vkGetDeviceQueue(vulkan_device_, vulkan_queue_family_index_, 0,
@@ -662,6 +796,16 @@ void ConfigHelperVulkan::Shutdown() {
if (vulkan_device_ != VK_NULL_HANDLE)
vkDestroyDevice(vulkan_device_, nullptr);
+ auto vkDestroyDebugReportCallbackEXT =
+ reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
+ vkGetInstanceProcAddr(vulkan_instance_,
+ "vkDestroyDebugReportCallbackEXT"));
+ assert(vkDestroyDebugReportCallbackEXT &&
+ "Sample: vkDestroyDebugReportCallbackEXT is nullptr");
+ if (vulkan_callback_ != VK_NULL_HANDLE)
+ vkDestroyDebugReportCallbackEXT(vulkan_instance_, vulkan_callback_,
+ nullptr);
+
if (vulkan_instance_ != VK_NULL_HANDLE)
vkDestroyInstance(vulkan_instance_, nullptr);
}
diff --git a/samples/config_helper_vulkan.h b/samples/config_helper_vulkan.h
index 61c4c40..a6ad9de 100644
--- a/samples/config_helper_vulkan.h
+++ b/samples/config_helper_vulkan.h
@@ -47,6 +47,10 @@ class ConfigHelperVulkan : public ConfigHelperImpl {
// Create Vulkan instance.
void CreateVulkanInstance();
+ // Create |vulkan_callback_| that reports validation layer errors
+ // via debugCallback() function in config_helper_vulkan.cc.
+ void CreateDebugReportCallback();
+
// Choose Vulkan physical device that supports both
// |required_features| and |required_extensions|.
void ChooseVulkanPhysicalDevice(
@@ -59,6 +63,7 @@ class ConfigHelperVulkan : public ConfigHelperImpl {
const std::vector<std::string>& required_extensions);
VkInstance vulkan_instance_ = VK_NULL_HANDLE;
+ VkDebugReportCallbackEXT vulkan_callback_ = VK_NULL_HANDLE;
VkPhysicalDevice vulkan_physical_device_ = VK_NULL_HANDLE;
VkPhysicalDeviceFeatures available_features_ = {};
std::vector<std::string> available_extensions_;
diff --git a/samples/log.cc b/samples/log.cc
new file mode 100644
index 0000000..66d365d
--- /dev/null
+++ b/samples/log.cc
@@ -0,0 +1,42 @@
+// Copyright 2019 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 "samples/log.h"
+
+#include <string>
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#else // __ANDROID__
+#include <iostream>
+#endif // __ANDROID__
+
+namespace sample {
+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 sample
diff --git a/samples/log.h b/samples/log.h
new file mode 100644
index 0000000..ff9b316
--- /dev/null
+++ b/samples/log.h
@@ -0,0 +1,27 @@
+// Copyright 2019 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 SAMPLES_LOG_H_
+#define SAMPLES_LOG_H_
+
+#include <string>
+
+namespace sample {
+
+// This method is used for debug reports from Vulkan validation layers.
+void LogError(const std::string& msg);
+
+} // namespace sample
+
+#endif // SAMPLES_LOG_H_
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() {
diff --git a/tests/cases/compute_in_spirv_generated_by_clspv.amber b/tests/cases/compute_in_spirv_generated_by_clspv.amber
deleted file mode 100644
index 82251f2..0000000
--- a/tests/cases/compute_in_spirv_generated_by_clspv.amber
+++ /dev/null
@@ -1,164 +0,0 @@
-[comment]
-Source code in OpenCL C:
-
-typedef struct { int arr[2]; } S1;
-typedef struct { S1 s1; int a; S1 s2; } S2;
-
-S2 make_s2(int n) {
- S2 s2;
- s2.s1.arr[0] = n;
- s2.s1.arr[1] = n;
- s2.a = n;
- s2.s2.arr[0] = n;
- s2.s2.arr[1] = n;
- return s2;
-}
-
-S2 choose(int n) {
- if (n > 0) return make_s2(n - 5);
- return make_s2(0);
-}
-
-kernel void foo(global S2 *data, int n) {
- *data = choose(n);
-}
-
-The following SPIR-V code was generated by CLSPV with -cl-opt-disable option.
-GIT_COMMIT = 8638849b2167fcba90dbff0ee4cfe7dbf0380d24
-
-[compute shader spirv]
-; SPIR-V
-; Version: 1.0
-; Generator: Codeplay; 0
-; Bound: 71
-; Schema: 0
- OpCapability Shader
- OpCapability VariablePointers
- OpExtension "SPV_KHR_storage_buffer_storage_class"
- OpExtension "SPV_KHR_variable_pointers"
- OpMemoryModel Logical GLSL450
- OpEntryPoint GLCompute %52 "main"
- OpSource OpenCL_C 120
- OpDecorate %24 SpecId 0
- OpDecorate %25 SpecId 1
- OpDecorate %26 SpecId 2
- OpMemberDecorate %_struct_4 0 Offset 0
- OpMemberDecorate %_struct_5 0 Offset 0
- OpMemberDecorate %_struct_5 1 Offset 8
- OpMemberDecorate %_struct_5 2 Offset 12
- OpDecorate %_runtimearr__struct_5 ArrayStride 20
- OpMemberDecorate %_struct_7 0 Offset 0
- OpDecorate %_struct_7 Block
- OpMemberDecorate %_struct_9 0 Offset 0
- OpDecorate %_struct_9 Block
- OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
- OpDecorate %29 DescriptorSet 0
- OpDecorate %29 Binding 0
- OpDecorate %30 DescriptorSet 0
- OpDecorate %30 Binding 1
- OpDecorate %_arr_uint_uint_2 ArrayStride 4
- %uint = OpTypeInt 32 0
- %uint_2 = OpConstant %uint 2
-%_arr_uint_uint_2 = OpTypeArray %uint %uint_2
- %_struct_4 = OpTypeStruct %_arr_uint_uint_2
- %_struct_5 = OpTypeStruct %_struct_4 %uint %_struct_4
-%_runtimearr__struct_5 = OpTypeRuntimeArray %_struct_5
- %_struct_7 = OpTypeStruct %_runtimearr__struct_5
-%_ptr_StorageBuffer__struct_7 = OpTypePointer StorageBuffer %_struct_7
- %_struct_9 = OpTypeStruct %uint
-%_ptr_StorageBuffer__struct_9 = OpTypePointer StorageBuffer %_struct_9
- %void = OpTypeVoid
- %12 = OpTypeFunction %void
-%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
- %14 = OpTypeFunction %_struct_5 %uint
- %bool = OpTypeBool
- %v3uint = OpTypeVector %uint 3
-%_ptr_Private_v3uint = OpTypePointer Private %v3uint
- %uint_0 = OpConstant %uint 0
- %uint_1 = OpConstant %uint 1
- %20 = OpUndef %_struct_5
- %false = OpConstantFalse %bool
- %true = OpConstantTrue %bool
-%uint_4294967291 = OpConstant %uint 4294967291
- %24 = OpSpecConstant %uint 1
- %25 = OpSpecConstant %uint 1
- %26 = OpSpecConstant %uint 1
-%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %24 %25 %26
- %28 = OpVariable %_ptr_Private_v3uint Private %gl_WorkGroupSize
- %29 = OpVariable %_ptr_StorageBuffer__struct_7 StorageBuffer
- %30 = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer
- %31 = OpFunction %_struct_5 Const %14
- %32 = OpFunctionParameter %uint
- %33 = OpLabel
- %34 = OpCompositeConstruct %_arr_uint_uint_2 %32 %32
- %35 = OpCompositeConstruct %_struct_4 %34
- %36 = OpCompositeConstruct %_struct_5 %35 %32 %35
- OpReturnValue %36
- OpFunctionEnd
- %37 = OpFunction %_struct_5 Const %14
- %38 = OpFunctionParameter %uint
- %39 = OpLabel
- %40 = OpSGreaterThan %bool %38 %uint_0
- %41 = OpLogicalNot %bool %40
- OpSelectionMerge %44 None
- OpBranchConditional %41 %42 %44
- %42 = OpLabel
- %43 = OpFunctionCall %_struct_5 %31 %uint_0
- OpBranch %44
- %44 = OpLabel
- %46 = OpPhi %bool %false %42 %true %39
- %45 = OpPhi %_struct_5 %43 %42 %20 %39
- OpSelectionMerge %47 None
- OpBranchConditional %46 %49 %47
- %47 = OpLabel
- %48 = OpPhi %_struct_5 %45 %44 %51 %49
- OpReturnValue %48
- %49 = OpLabel
- %50 = OpIAdd %uint %38 %uint_4294967291
- %51 = OpFunctionCall %_struct_5 %31 %50
- OpBranch %47
- OpFunctionEnd
- %52 = OpFunction %void None %12
- %53 = OpLabel
- %54 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0
- %55 = OpLoad %uint %54
- %56 = OpFunctionCall %_struct_5 %37 %55
- %57 = OpCompositeExtract %_struct_4 %56 0
- %58 = OpCompositeExtract %_arr_uint_uint_2 %57 0
- %59 = OpCompositeExtract %uint %58 0
- %60 = OpCompositeExtract %uint %58 1
- %61 = OpCompositeExtract %uint %56 1
- %62 = OpCompositeExtract %_struct_4 %56 2
- %63 = OpCompositeExtract %_arr_uint_uint_2 %62 0
- %64 = OpCompositeExtract %uint %63 0
- %65 = OpCompositeExtract %uint %63 1
- %66 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_0 %uint_0 %uint_0
- OpStore %66 %59
- %67 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_0 %uint_0 %uint_1
- OpStore %67 %60
- %68 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_1
- OpStore %68 %61
- %69 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_2 %uint_0 %uint_0
- OpStore %69 %64
- %70 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_2 %uint_0 %uint_1
- OpStore %70 %65
- OpReturn
- OpFunctionEnd
-[require]
-VK_KHR_storage_buffer_storage_class
-VK_KHR_get_physical_device_properties2
-VK_KHR_variable_pointers
-
-[test]
-# ssbo [bind] subdata [type] [offset] [values ...]
-ssbo 0 subdata int 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-ssbo 1 subdata int 0 13
-
-compute 3 1 1
-
-# probe ssbo [type] [bind] [offset] == [values ...]
-probe ssbo int 0 0 == 8
-probe ssbo int 0 4 == 8
-probe ssbo int 0 8 == 8
-probe ssbo int 0 12 == 8
-probe ssbo int 0 16 == 8