|
|
@@ -15,8 +15,8 @@
|
|
|
#include <Utils/Log.h>
|
|
|
#include <Utils/ReadData.h>
|
|
|
#include <Jolt/Core/Profiler.h>
|
|
|
-#include <Jolt/Core/QuickSort.h>
|
|
|
#include <Jolt/Core/RTTI.h>
|
|
|
+#include <Jolt/Compute/VK/ComputeBufferVK.h>
|
|
|
|
|
|
JPH_SUPPRESS_WARNINGS_STD_BEGIN
|
|
|
#ifdef JPH_PLATFORM_WINDOWS
|
|
|
@@ -31,54 +31,42 @@ JPH_SUPPRESS_WARNINGS_STD_BEGIN
|
|
|
#endif
|
|
|
JPH_SUPPRESS_WARNINGS_STD_END
|
|
|
|
|
|
-#ifdef JPH_DEBUG
|
|
|
-
|
|
|
-static VKAPI_ATTR VkBool32 VKAPI_CALL sVulkanDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT inSeverity, [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT inType, const VkDebugUtilsMessengerCallbackDataEXT *inCallbackData, [[maybe_unused]] void *inUserData)
|
|
|
+RendererVK::RendererVK()
|
|
|
{
|
|
|
- Trace("VK: %s", inCallbackData->pMessage);
|
|
|
- JPH_ASSERT((inSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) == 0);
|
|
|
- return VK_FALSE;
|
|
|
+ // Ensure ComputeSystem doesn't get destructed
|
|
|
+ ComputeSystem::SetEmbedded();
|
|
|
}
|
|
|
|
|
|
-#endif // JPH_DEBUG
|
|
|
-
|
|
|
RendererVK::~RendererVK()
|
|
|
{
|
|
|
vkDeviceWaitIdle(mDevice);
|
|
|
|
|
|
- // Trace allocation stats
|
|
|
- Trace("VK: Max allocations: %u, max size: %u MB", mMaxNumAllocations, uint32(mMaxTotalAllocated >> 20));
|
|
|
-
|
|
|
// Destroy the shadow map
|
|
|
mShadowMap = nullptr;
|
|
|
vkDestroyFramebuffer(mDevice, mShadowFrameBuffer, nullptr);
|
|
|
|
|
|
// Release constant buffers
|
|
|
- for (unique_ptr<ConstantBufferVK> &cb : mVertexShaderConstantBufferProjection)
|
|
|
+ for (Ref<ComputeBuffer> &cb : mVertexShaderConstantBufferProjection)
|
|
|
cb = nullptr;
|
|
|
- for (unique_ptr<ConstantBufferVK> &cb : mVertexShaderConstantBufferOrtho)
|
|
|
+ for (Ref<ComputeBuffer> &cb : mVertexShaderConstantBufferOrtho)
|
|
|
cb = nullptr;
|
|
|
- for (unique_ptr<ConstantBufferVK> &cb : mPixelShaderConstantBuffer)
|
|
|
+ for (Ref<ComputeBuffer> &cb : mPixelShaderConstantBuffer)
|
|
|
cb = nullptr;
|
|
|
|
|
|
// Free all buffers
|
|
|
- for (BufferCache &bc : mFreedBuffers)
|
|
|
- for (BufferCache::value_type &vt : bc)
|
|
|
- for (BufferVK &bvk : vt.second)
|
|
|
- FreeBufferInternal(bvk);
|
|
|
- for (BufferCache::value_type &vt : mBufferCache)
|
|
|
- for (BufferVK &bvk : vt.second)
|
|
|
- FreeBufferInternal(bvk);
|
|
|
-
|
|
|
- // Free all blocks in the memory cache
|
|
|
- for (MemoryCache::value_type &mc : mMemoryCache)
|
|
|
- for (Memory &m : mc.second)
|
|
|
- if (m.mOffset == 0)
|
|
|
- vkFreeMemory(mDevice, m.mMemory, nullptr); // Don't care about memory tracking anymore
|
|
|
-
|
|
|
+ for (Array<BufferVK> &buffers : mPerFrameFreedBuffers)
|
|
|
+ {
|
|
|
+ for (BufferVK& buffer : buffers)
|
|
|
+ FreeBuffer(buffer);
|
|
|
+ buffers.clear();
|
|
|
+ }
|
|
|
+
|
|
|
for (VkFence fence : mInFlightFences)
|
|
|
vkDestroyFence(mDevice, fence, nullptr);
|
|
|
|
|
|
+ for (uint32 i = 0; i < cFrameCount; ++i)
|
|
|
+ vkFreeCommandBuffers(mDevice, mCommandPool, 1, &mCommandBuffers[i]);
|
|
|
+
|
|
|
vkDestroyCommandPool(mDevice, mCommandPool, nullptr);
|
|
|
|
|
|
vkDestroyPipelineLayout(mDevice, mPipelineLayout, nullptr);
|
|
|
@@ -97,102 +85,10 @@ RendererVK::~RendererVK()
|
|
|
DestroySwapChain();
|
|
|
|
|
|
vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
|
|
|
-
|
|
|
- vkDestroyDevice(mDevice, nullptr);
|
|
|
-
|
|
|
-#ifdef JPH_DEBUG
|
|
|
- PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = (PFN_vkDestroyDebugUtilsMessengerEXT)(void *)vkGetInstanceProcAddr(mInstance, "vkDestroyDebugUtilsMessengerEXT");
|
|
|
- if (vkDestroyDebugUtilsMessengerEXT != nullptr)
|
|
|
- vkDestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger, nullptr);
|
|
|
-#endif
|
|
|
-
|
|
|
- vkDestroyInstance(mInstance, nullptr);
|
|
|
}
|
|
|
|
|
|
-void RendererVK::Initialize(ApplicationWindow *inWindow)
|
|
|
+void RendererVK::OnInstanceCreated()
|
|
|
{
|
|
|
- Renderer::Initialize(inWindow);
|
|
|
-
|
|
|
- // Flip the sign of the projection matrix
|
|
|
- mPerspectiveYSign = -1.0f;
|
|
|
-
|
|
|
- // Required instance extensions
|
|
|
- Array<const char *> required_instance_extensions;
|
|
|
- required_instance_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
|
-#ifdef JPH_PLATFORM_WINDOWS
|
|
|
- required_instance_extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
|
-#elif defined(JPH_PLATFORM_LINUX)
|
|
|
- required_instance_extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
|
|
-#elif defined(JPH_PLATFORM_MACOS)
|
|
|
- required_instance_extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
|
|
- required_instance_extensions.push_back("VK_KHR_portability_enumeration");
|
|
|
- required_instance_extensions.push_back("VK_KHR_get_physical_device_properties2");
|
|
|
-#endif
|
|
|
-
|
|
|
- // Required device extensions
|
|
|
- Array<const char *> required_device_extensions;
|
|
|
- required_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
|
-#ifdef JPH_PLATFORM_MACOS
|
|
|
- required_device_extensions.push_back("VK_KHR_portability_subset"); // VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
|
|
|
-#endif
|
|
|
-
|
|
|
- // Query supported instance extensions
|
|
|
- uint32 instance_extension_count = 0;
|
|
|
- FatalErrorIfFailed(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr));
|
|
|
- Array<VkExtensionProperties> instance_extensions;
|
|
|
- instance_extensions.resize(instance_extension_count);
|
|
|
- FatalErrorIfFailed(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions.data()));
|
|
|
-
|
|
|
- // Query supported validation layers
|
|
|
- uint32 validation_layer_count;
|
|
|
- vkEnumerateInstanceLayerProperties(&validation_layer_count, nullptr);
|
|
|
- Array<VkLayerProperties> validation_layers(validation_layer_count);
|
|
|
- vkEnumerateInstanceLayerProperties(&validation_layer_count, validation_layers.data());
|
|
|
-
|
|
|
- // Create Vulkan instance
|
|
|
- VkInstanceCreateInfo instance_create_info = {};
|
|
|
- instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
|
-#ifdef JPH_PLATFORM_MACOS
|
|
|
- instance_create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
|
|
-#endif
|
|
|
-
|
|
|
-#ifdef JPH_DEBUG
|
|
|
- // Enable validation layer if supported
|
|
|
- const char *desired_validation_layers[] = { "VK_LAYER_KHRONOS_validation" };
|
|
|
- for (const VkLayerProperties &p : validation_layers)
|
|
|
- if (strcmp(desired_validation_layers[0], p.layerName) == 0)
|
|
|
- {
|
|
|
- instance_create_info.enabledLayerCount = 1;
|
|
|
- instance_create_info.ppEnabledLayerNames = desired_validation_layers;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- // Setup debug messenger callback if the extension is supported
|
|
|
- VkDebugUtilsMessengerCreateInfoEXT messenger_create_info = {};
|
|
|
- for (const VkExtensionProperties &ext : instance_extensions)
|
|
|
- if (strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, ext.extensionName) == 0)
|
|
|
- {
|
|
|
- messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
|
- messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
|
|
- messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
|
|
- messenger_create_info.pfnUserCallback = sVulkanDebugCallback;
|
|
|
- instance_create_info.pNext = &messenger_create_info;
|
|
|
- required_instance_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
|
- break;
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- instance_create_info.enabledExtensionCount = (uint32)required_instance_extensions.size();
|
|
|
- instance_create_info.ppEnabledExtensionNames = required_instance_extensions.data();
|
|
|
- FatalErrorIfFailed(vkCreateInstance(&instance_create_info, nullptr, &mInstance));
|
|
|
-
|
|
|
-#ifdef JPH_DEBUG
|
|
|
- // Finalize debug messenger callback
|
|
|
- PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)(std::uintptr_t)vkGetInstanceProcAddr(mInstance, "vkCreateDebugUtilsMessengerEXT");
|
|
|
- if (vkCreateDebugUtilsMessengerEXT != nullptr)
|
|
|
- FatalErrorIfFailed(vkCreateDebugUtilsMessengerEXT(mInstance, &messenger_create_info, nullptr, &mDebugMessenger));
|
|
|
-#endif
|
|
|
-
|
|
|
// Create surface
|
|
|
#ifdef JPH_PLATFORM_WINDOWS
|
|
|
VkWin32SurfaceCreateInfoKHR surface_create_info = {};
|
|
|
@@ -213,154 +109,29 @@ void RendererVK::Initialize(ApplicationWindow *inWindow)
|
|
|
surface_create_info.pLayer = static_cast<ApplicationWindowMacOS *>(mWindow)->GetMetalLayer();
|
|
|
FatalErrorIfFailed(vkCreateMetalSurfaceEXT(mInstance, &surface_create_info, nullptr, &mSurface));
|
|
|
#endif
|
|
|
+}
|
|
|
|
|
|
- // Select device
|
|
|
- uint32 device_count = 0;
|
|
|
- FatalErrorIfFailed(vkEnumeratePhysicalDevices(mInstance, &device_count, nullptr));
|
|
|
- Array<VkPhysicalDevice> devices;
|
|
|
- devices.resize(device_count);
|
|
|
- FatalErrorIfFailed(vkEnumeratePhysicalDevices(mInstance, &device_count, devices.data()));
|
|
|
- struct Device
|
|
|
- {
|
|
|
- VkPhysicalDevice mPhysicalDevice;
|
|
|
- String mName;
|
|
|
- VkSurfaceFormatKHR mFormat;
|
|
|
- uint32 mGraphicsQueueIndex;
|
|
|
- uint32 mPresentQueueIndex;
|
|
|
- int mScore;
|
|
|
- };
|
|
|
- Array<Device> available_devices;
|
|
|
- for (VkPhysicalDevice device : devices)
|
|
|
- {
|
|
|
- // Get device properties
|
|
|
- VkPhysicalDeviceProperties properties;
|
|
|
- vkGetPhysicalDeviceProperties(device, &properties);
|
|
|
-
|
|
|
- // Test if it is an appropriate type
|
|
|
- int score = 0;
|
|
|
- switch (properties.deviceType)
|
|
|
- {
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
|
|
- score = 30;
|
|
|
- break;
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
|
|
- score = 20;
|
|
|
- break;
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
|
|
- score = 10;
|
|
|
- break;
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
|
|
- score = 5;
|
|
|
- break;
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_OTHER:
|
|
|
- case VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM:
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // Check if the device supports all our required extensions
|
|
|
- uint32 device_extension_count;
|
|
|
- vkEnumerateDeviceExtensionProperties(device, nullptr, &device_extension_count, nullptr);
|
|
|
- Array<VkExtensionProperties> available_extensions;
|
|
|
- available_extensions.resize(device_extension_count);
|
|
|
- vkEnumerateDeviceExtensionProperties(device, nullptr, &device_extension_count, available_extensions.data());
|
|
|
- int found_extensions = 0;
|
|
|
- for (const char *required_device_extension : required_device_extensions)
|
|
|
- for (const VkExtensionProperties &ext : available_extensions)
|
|
|
- if (strcmp(required_device_extension, ext.extensionName) == 0)
|
|
|
- {
|
|
|
- found_extensions++;
|
|
|
- break;
|
|
|
- }
|
|
|
- if (found_extensions != int(required_device_extensions.size()))
|
|
|
- continue;
|
|
|
-
|
|
|
- // Find the right queues
|
|
|
- uint32 queue_family_count = 0;
|
|
|
- vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr);
|
|
|
- Array<VkQueueFamilyProperties> queue_families;
|
|
|
- queue_families.resize(queue_family_count);
|
|
|
- vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families.data());
|
|
|
- uint32 graphics_queue = ~uint32(0);
|
|
|
- uint32 present_queue = ~uint32(0);
|
|
|
- for (uint32 i = 0; i < uint32(queue_families.size()); ++i)
|
|
|
- {
|
|
|
- if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
|
|
- graphics_queue = i;
|
|
|
-
|
|
|
- VkBool32 present_support = false;
|
|
|
- vkGetPhysicalDeviceSurfaceSupportKHR(device, i, mSurface, &present_support);
|
|
|
- if (present_support)
|
|
|
- present_queue = i;
|
|
|
+void RendererVK::Initialize(ApplicationWindow *inWindow)
|
|
|
+{
|
|
|
+ Renderer::Initialize(inWindow);
|
|
|
|
|
|
- if (graphics_queue != ~uint32(0) && present_queue != ~uint32(0))
|
|
|
- break;
|
|
|
- }
|
|
|
- if (graphics_queue == ~uint32(0) || present_queue == ~uint32(0))
|
|
|
- continue;
|
|
|
+ // Flip the sign of the projection matrix
|
|
|
+ mPerspectiveYSign = -1.0f;
|
|
|
|
|
|
- // Select surface format
|
|
|
- VkSurfaceFormatKHR selected_format = SelectFormat(device);
|
|
|
- if (selected_format.format == VK_FORMAT_UNDEFINED)
|
|
|
- continue;
|
|
|
+ if (!ComputeSystemVKImpl::Initialize())
|
|
|
+ FatalError("Unable to initialize Vulkan");
|
|
|
|
|
|
- // Add the device
|
|
|
- available_devices.push_back({ device, properties.deviceName, selected_format, graphics_queue, present_queue, score });
|
|
|
- }
|
|
|
- if (available_devices.empty())
|
|
|
- FatalError("No Vulkan device found!");
|
|
|
- QuickSort(available_devices.begin(), available_devices.end(), [](const Device &inLHS, const Device &inRHS) {
|
|
|
- return inLHS.mScore > inRHS.mScore;
|
|
|
- });
|
|
|
- const Device &selected_device = available_devices[0];
|
|
|
- Trace("Selected device: %s", selected_device.mName.c_str());
|
|
|
- mPhysicalDevice = selected_device.mPhysicalDevice;
|
|
|
-
|
|
|
- // Get memory properties
|
|
|
- vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &mMemoryProperties);
|
|
|
-
|
|
|
- // Get features
|
|
|
- VkPhysicalDeviceFeatures physical_device_features = {};
|
|
|
- vkGetPhysicalDeviceFeatures(mPhysicalDevice, &physical_device_features);
|
|
|
-
|
|
|
- // Create device
|
|
|
- float queue_priority = 1.0f;
|
|
|
- VkDeviceQueueCreateInfo queue_create_info[2] = {};
|
|
|
- for (size_t i = 0; i < std::size(queue_create_info); ++i)
|
|
|
- {
|
|
|
- queue_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
- queue_create_info[i].queueCount = 1;
|
|
|
- queue_create_info[i].pQueuePriorities = &queue_priority;
|
|
|
- }
|
|
|
- queue_create_info[0].queueFamilyIndex = selected_device.mGraphicsQueueIndex;
|
|
|
- queue_create_info[1].queueFamilyIndex = selected_device.mPresentQueueIndex;
|
|
|
-
|
|
|
- VkPhysicalDeviceFeatures device_features = {};
|
|
|
-
|
|
|
- if (!physical_device_features.fillModeNonSolid)
|
|
|
- FatalError("fillModeNonSolid not supported!");
|
|
|
- device_features.fillModeNonSolid = VK_TRUE;
|
|
|
-
|
|
|
- VkDeviceCreateInfo device_create_info = {};
|
|
|
- device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
|
- device_create_info.queueCreateInfoCount = selected_device.mGraphicsQueueIndex != selected_device.mPresentQueueIndex? 2 : 1;
|
|
|
- device_create_info.pQueueCreateInfos = queue_create_info;
|
|
|
- device_create_info.enabledLayerCount = instance_create_info.enabledLayerCount;
|
|
|
- device_create_info.ppEnabledLayerNames = instance_create_info.ppEnabledLayerNames;
|
|
|
- device_create_info.enabledExtensionCount = uint32(required_device_extensions.size());
|
|
|
- device_create_info.ppEnabledExtensionNames = required_device_extensions.data();
|
|
|
- device_create_info.pEnabledFeatures = &device_features;
|
|
|
- FatalErrorIfFailed(vkCreateDevice(selected_device.mPhysicalDevice, &device_create_info, nullptr, &mDevice));
|
|
|
-
|
|
|
- // Get the queues
|
|
|
- mGraphicsQueueIndex = selected_device.mGraphicsQueueIndex;
|
|
|
- mPresentQueueIndex = selected_device.mPresentQueueIndex;
|
|
|
- vkGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
|
|
|
- vkGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue);
|
|
|
+ // Check if fill mode non solid is supported
|
|
|
+ VkPhysicalDeviceFeatures2 supported_features2 = {};
|
|
|
+ supported_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
|
|
+ vkGetPhysicalDeviceFeatures2(mPhysicalDevice, &supported_features2);
|
|
|
+ if (!supported_features2.features.fillModeNonSolid)
|
|
|
+ FatalError("This Vulkan implementation does not support fill mode non solid");
|
|
|
|
|
|
VkCommandPoolCreateInfo pool_info = {};
|
|
|
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
|
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
|
- pool_info.queueFamilyIndex = selected_device.mGraphicsQueueIndex;
|
|
|
+ pool_info.queueFamilyIndex = mGraphicsQueueIndex;
|
|
|
FatalErrorIfFailed(vkCreateCommandPool(mDevice, &pool_info, nullptr, &mCommandPool));
|
|
|
|
|
|
VkCommandBufferAllocateInfo command_buffer_info = {};
|
|
|
@@ -380,9 +151,9 @@ void RendererVK::Initialize(ApplicationWindow *inWindow)
|
|
|
// Create constant buffer. One per frame to avoid overwriting the constant buffer while the GPU is still using it.
|
|
|
for (uint n = 0; n < cFrameCount; ++n)
|
|
|
{
|
|
|
- mVertexShaderConstantBufferProjection[n] = CreateConstantBuffer(sizeof(VertexShaderConstantBuffer));
|
|
|
- mVertexShaderConstantBufferOrtho[n] = CreateConstantBuffer(sizeof(VertexShaderConstantBuffer));
|
|
|
- mPixelShaderConstantBuffer[n] = CreateConstantBuffer(sizeof(PixelShaderConstantBuffer));
|
|
|
+ mVertexShaderConstantBufferProjection[n] = CreateComputeBuffer(ComputeBuffer::EType::ConstantBuffer, 1, sizeof(VertexShaderConstantBuffer));
|
|
|
+ mVertexShaderConstantBufferOrtho[n] = CreateComputeBuffer(ComputeBuffer::EType::ConstantBuffer, 1, sizeof(VertexShaderConstantBuffer));
|
|
|
+ mPixelShaderConstantBuffer[n] = CreateComputeBuffer(ComputeBuffer::EType::ConstantBuffer, 1, sizeof(PixelShaderConstantBuffer));
|
|
|
}
|
|
|
|
|
|
// Create descriptor set layout for the uniform buffers
|
|
|
@@ -445,11 +216,11 @@ void RendererVK::Initialize(ApplicationWindow *inWindow)
|
|
|
for (uint i = 0; i < cFrameCount; i++)
|
|
|
{
|
|
|
VkDescriptorBufferInfo vs_buffer_info = {};
|
|
|
- vs_buffer_info.buffer = mVertexShaderConstantBufferProjection[i]->GetBuffer();
|
|
|
+ vs_buffer_info.buffer = StaticCast<ComputeBufferVK>(mVertexShaderConstantBufferProjection[i])->GetBufferCPU();
|
|
|
vs_buffer_info.range = sizeof(VertexShaderConstantBuffer);
|
|
|
|
|
|
VkDescriptorBufferInfo ps_buffer_info = {};
|
|
|
- ps_buffer_info.buffer = mPixelShaderConstantBuffer[i]->GetBuffer();
|
|
|
+ ps_buffer_info.buffer = StaticCast<ComputeBufferVK>(mPixelShaderConstantBuffer[i])->GetBufferCPU();
|
|
|
ps_buffer_info.range = sizeof(PixelShaderConstantBuffer);
|
|
|
|
|
|
VkWriteDescriptorSet descriptor_write[2] = {};
|
|
|
@@ -473,7 +244,7 @@ void RendererVK::Initialize(ApplicationWindow *inWindow)
|
|
|
for (uint i = 0; i < cFrameCount; i++)
|
|
|
{
|
|
|
VkDescriptorBufferInfo vs_buffer_info = {};
|
|
|
- vs_buffer_info.buffer = mVertexShaderConstantBufferOrtho[i]->GetBuffer();
|
|
|
+ vs_buffer_info.buffer = StaticCast<ComputeBufferVK>(mVertexShaderConstantBufferOrtho[i])->GetBufferCPU();
|
|
|
vs_buffer_info.range = sizeof(VertexShaderConstantBuffer);
|
|
|
|
|
|
VkWriteDescriptorSet descriptor_write = {};
|
|
|
@@ -561,7 +332,7 @@ void RendererVK::Initialize(ApplicationWindow *inWindow)
|
|
|
// Create normal render pass
|
|
|
VkAttachmentDescription attachments_normal[2] = {};
|
|
|
VkAttachmentDescription &color_attachment = attachments_normal[0];
|
|
|
- color_attachment.format = selected_device.mFormat.format;
|
|
|
+ color_attachment.format = mSelectedFormat.format;
|
|
|
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
|
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
|
@@ -611,6 +382,34 @@ void RendererVK::Initialize(ApplicationWindow *inWindow)
|
|
|
CreateSwapChain(mPhysicalDevice);
|
|
|
}
|
|
|
|
|
|
+void RendererVK::GetInstanceExtensions(Array<const char *> &outExtensions)
|
|
|
+{
|
|
|
+#ifdef JPH_PLATFORM_WINDOWS
|
|
|
+ outExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
|
+#elif defined(JPH_PLATFORM_LINUX)
|
|
|
+ outExtensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
|
|
+#elif defined(JPH_PLATFORM_MACOS)
|
|
|
+ outExtensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+void RendererVK::GetDeviceExtensions(Array<const char *> &outExtensions)
|
|
|
+{
|
|
|
+ outExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
|
|
+}
|
|
|
+
|
|
|
+void RendererVK::GetEnabledFeatures(VkPhysicalDeviceFeatures2 &ioFeatures)
|
|
|
+{
|
|
|
+ ioFeatures.features.fillModeNonSolid = VK_TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+bool RendererVK::HasPresentSupport(VkPhysicalDevice inDevice, uint32 inQueueFamilyIndex)
|
|
|
+{
|
|
|
+ VkBool32 present_support = false;
|
|
|
+ vkGetPhysicalDeviceSurfaceSupportKHR(inDevice, inQueueFamilyIndex, mSurface, &present_support);
|
|
|
+ return present_support == VK_TRUE;
|
|
|
+}
|
|
|
+
|
|
|
VkSurfaceFormatKHR RendererVK::SelectFormat(VkPhysicalDevice inDevice)
|
|
|
{
|
|
|
uint32 format_count;
|
|
|
@@ -777,7 +576,6 @@ void RendererVK::DestroySwapChain()
|
|
|
|
|
|
DestroyImage(mDepthImage, mDepthImageMemory);
|
|
|
mDepthImage = VK_NULL_HANDLE;
|
|
|
- mDepthImageMemory = VK_NULL_HANDLE;
|
|
|
}
|
|
|
|
|
|
for (VkFramebuffer frame_buffer : mSwapChainFramebuffers)
|
|
|
@@ -876,17 +674,14 @@ bool RendererVK::BeginFrame(const CameraState &inCamera, float inWorldScale)
|
|
|
FreeSemaphore(mImageAvailableSemaphores[mImageIndex]);
|
|
|
mImageAvailableSemaphores[mImageIndex] = semaphore;
|
|
|
|
|
|
- // Free buffers that weren't used this frame
|
|
|
- for (BufferCache::value_type &vt : mBufferCache)
|
|
|
- for (BufferVK &bvk : vt.second)
|
|
|
- FreeBufferInternal(bvk);
|
|
|
- mBufferCache.clear();
|
|
|
-
|
|
|
- // Recycle the buffers that were freed
|
|
|
- mBufferCache.swap(mFreedBuffers[mFrameIndex]);
|
|
|
-
|
|
|
vkResetFences(mDevice, 1, &mInFlightFences[mFrameIndex]);
|
|
|
|
|
|
+ // Release the buffers that belonged to the previous frame with this index. Nothing should be using them anymore.
|
|
|
+ Array<BufferVK> &buffers = mPerFrameFreedBuffers[mFrameIndex];
|
|
|
+ for (BufferVK &buffer : buffers)
|
|
|
+ FreeBuffer(buffer);
|
|
|
+ buffers.clear();
|
|
|
+
|
|
|
VkCommandBuffer command_buffer = GetCommandBuffer();
|
|
|
FatalErrorIfFailed(vkResetCommandBuffer(command_buffer, 0));
|
|
|
|
|
|
@@ -908,17 +703,17 @@ bool RendererVK::BeginFrame(const CameraState &inCamera, float inWorldScale)
|
|
|
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
|
|
|
|
|
|
// Set constants for vertex shader in projection mode
|
|
|
- VertexShaderConstantBuffer *vs = mVertexShaderConstantBufferProjection[mFrameIndex]->Map<VertexShaderConstantBuffer>();
|
|
|
+ VertexShaderConstantBuffer *vs = mVertexShaderConstantBufferProjection[mFrameIndex]->Map<VertexShaderConstantBuffer>(ComputeBuffer::EMode::Write);
|
|
|
*vs = mVSBuffer;
|
|
|
mVertexShaderConstantBufferProjection[mFrameIndex]->Unmap();
|
|
|
|
|
|
// Set constants for vertex shader in ortho mode
|
|
|
- vs = mVertexShaderConstantBufferOrtho[mFrameIndex]->Map<VertexShaderConstantBuffer>();
|
|
|
+ vs = mVertexShaderConstantBufferOrtho[mFrameIndex]->Map<VertexShaderConstantBuffer>(ComputeBuffer::EMode::Write);
|
|
|
*vs = mVSBufferOrtho;
|
|
|
mVertexShaderConstantBufferOrtho[mFrameIndex]->Unmap();
|
|
|
|
|
|
// Set constants for pixel shader
|
|
|
- PixelShaderConstantBuffer *ps = mPixelShaderConstantBuffer[mFrameIndex]->Map<PixelShaderConstantBuffer>();
|
|
|
+ PixelShaderConstantBuffer *ps = mPixelShaderConstantBuffer[mFrameIndex]->Map<PixelShaderConstantBuffer>(ComputeBuffer::EMode::Write);
|
|
|
*ps = mPSBuffer;
|
|
|
mPixelShaderConstantBuffer[mFrameIndex]->Unmap();
|
|
|
|
|
|
@@ -1015,7 +810,7 @@ Ref<Texture> RendererVK::CreateTexture(const Surface *inSurface)
|
|
|
|
|
|
Ref<VertexShader> RendererVK::CreateVertexShader(const char *inName)
|
|
|
{
|
|
|
- Array<uint8> data = ReadData((String("Shaders/VK/") + inName + ".vert.spv").c_str());
|
|
|
+ Array<uint8> data = ReadData((String("Shaders/VK/") + inName + ".spv").c_str());
|
|
|
|
|
|
VkShaderModuleCreateInfo create_info = {};
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
|
@@ -1029,7 +824,7 @@ Ref<VertexShader> RendererVK::CreateVertexShader(const char *inName)
|
|
|
|
|
|
Ref<PixelShader> RendererVK::CreatePixelShader(const char *inName)
|
|
|
{
|
|
|
- Array<uint8> data = ReadData((String("Shaders/VK/") + inName + ".frag.spv").c_str());
|
|
|
+ Array<uint8> data = ReadData((String("Shaders/VK/") + inName + ".spv").c_str());
|
|
|
|
|
|
VkShaderModuleCreateInfo create_info = {};
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
|
@@ -1056,104 +851,6 @@ RenderInstances *RendererVK::CreateRenderInstances()
|
|
|
return new RenderInstancesVK(this);
|
|
|
}
|
|
|
|
|
|
-uint32 RendererVK::FindMemoryType(uint32 inTypeFilter, VkMemoryPropertyFlags inProperties)
|
|
|
-{
|
|
|
- for (uint32 i = 0; i < mMemoryProperties.memoryTypeCount; i++)
|
|
|
- if ((inTypeFilter & (1 << i))
|
|
|
- && (mMemoryProperties.memoryTypes[i].propertyFlags & inProperties) == inProperties)
|
|
|
- return i;
|
|
|
-
|
|
|
- FatalError("Failed to find memory type!");
|
|
|
-}
|
|
|
-
|
|
|
-void RendererVK::AllocateMemory(VkDeviceSize inSize, uint32 inMemoryTypeBits, VkMemoryPropertyFlags inProperties, VkDeviceMemory &outMemory)
|
|
|
-{
|
|
|
- VkMemoryAllocateInfo alloc_info = {};
|
|
|
- alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
|
- alloc_info.allocationSize = inSize;
|
|
|
- alloc_info.memoryTypeIndex = FindMemoryType(inMemoryTypeBits, inProperties);
|
|
|
- FatalErrorIfFailed(vkAllocateMemory(mDevice, &alloc_info, nullptr, &outMemory));
|
|
|
-
|
|
|
- // Track allocation
|
|
|
- ++mNumAllocations;
|
|
|
- mTotalAllocated += inSize;
|
|
|
-
|
|
|
- // Track max usage
|
|
|
- mMaxTotalAllocated = max(mMaxTotalAllocated, mTotalAllocated);
|
|
|
- mMaxNumAllocations = max(mMaxNumAllocations, mNumAllocations);
|
|
|
-}
|
|
|
-
|
|
|
-void RendererVK::FreeMemory(VkDeviceMemory inMemory, VkDeviceSize inSize)
|
|
|
-{
|
|
|
- vkFreeMemory(mDevice, inMemory, nullptr);
|
|
|
-
|
|
|
- // Track free
|
|
|
- --mNumAllocations;
|
|
|
- mTotalAllocated -= inSize;
|
|
|
-}
|
|
|
-
|
|
|
-void RendererVK::CreateBuffer(VkDeviceSize inSize, VkBufferUsageFlags inUsage, VkMemoryPropertyFlags inProperties, BufferVK &outBuffer)
|
|
|
-{
|
|
|
- // Check the cache
|
|
|
- BufferCache::iterator i = mBufferCache.find({ inSize, inUsage, inProperties });
|
|
|
- if (i != mBufferCache.end() && !i->second.empty())
|
|
|
- {
|
|
|
- outBuffer = i->second.back();
|
|
|
- i->second.pop_back();
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // Create a new buffer
|
|
|
- outBuffer.mSize = inSize;
|
|
|
- outBuffer.mUsage = inUsage;
|
|
|
- outBuffer.mProperties = inProperties;
|
|
|
-
|
|
|
- VkBufferCreateInfo create_info = {};
|
|
|
- create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
|
- create_info.size = inSize;
|
|
|
- create_info.usage = inUsage;
|
|
|
- create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
- FatalErrorIfFailed(vkCreateBuffer(mDevice, &create_info, nullptr, &outBuffer.mBuffer));
|
|
|
-
|
|
|
- VkMemoryRequirements mem_requirements;
|
|
|
- vkGetBufferMemoryRequirements(mDevice, outBuffer.mBuffer, &mem_requirements);
|
|
|
-
|
|
|
- if (mem_requirements.size > cMaxAllocSize)
|
|
|
- {
|
|
|
- // Allocate block directly
|
|
|
- AllocateMemory(mem_requirements.size, mem_requirements.memoryTypeBits, inProperties, outBuffer.mMemory);
|
|
|
- outBuffer.mAllocatedSize = mem_requirements.size;
|
|
|
- outBuffer.mOffset = 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // Round allocation to the next power of 2 so that we can use a simple block based allocator
|
|
|
- outBuffer.mAllocatedSize = max(VkDeviceSize(GetNextPowerOf2(uint32(mem_requirements.size))), cMinAllocSize);
|
|
|
-
|
|
|
- // Ensure that we have memory available from the right pool
|
|
|
- Array<Memory> &mem_array = mMemoryCache[{ outBuffer.mAllocatedSize, outBuffer.mUsage, outBuffer.mProperties }];
|
|
|
- if (mem_array.empty())
|
|
|
- {
|
|
|
- // Allocate a bigger block
|
|
|
- VkDeviceMemory device_memory;
|
|
|
- AllocateMemory(cBlockSize, mem_requirements.memoryTypeBits, inProperties, device_memory);
|
|
|
-
|
|
|
- // Divide into sub blocks
|
|
|
- for (VkDeviceSize offset = 0; offset < cBlockSize; offset += outBuffer.mAllocatedSize)
|
|
|
- mem_array.push_back({ device_memory, offset });
|
|
|
- }
|
|
|
-
|
|
|
- // Claim memory from the pool
|
|
|
- Memory &memory = mem_array.back();
|
|
|
- outBuffer.mMemory = memory.mMemory;
|
|
|
- outBuffer.mOffset = memory.mOffset;
|
|
|
- mem_array.pop_back();
|
|
|
- }
|
|
|
-
|
|
|
- // Bind the memory to the buffer
|
|
|
- vkBindBufferMemory(mDevice, outBuffer.mBuffer, outBuffer.mMemory, outBuffer.mOffset);
|
|
|
-}
|
|
|
-
|
|
|
VkCommandBuffer RendererVK::StartTempCommandBuffer()
|
|
|
{
|
|
|
VkCommandBufferAllocateInfo alloc_info = {};
|
|
|
@@ -1204,10 +901,9 @@ void RendererVK::CreateDeviceLocalBuffer(const void *inData, VkDeviceSize inSize
|
|
|
BufferVK staging_buffer;
|
|
|
CreateBuffer(inSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, staging_buffer);
|
|
|
|
|
|
- void *data;
|
|
|
- vkMapMemory(mDevice, staging_buffer.mMemory, staging_buffer.mOffset, inSize, 0, &data);
|
|
|
+ void *data = MapBuffer(staging_buffer);
|
|
|
memcpy(data, inData, (size_t)inSize);
|
|
|
- vkUnmapMemory(mDevice, staging_buffer.mMemory);
|
|
|
+ UnmapBuffer(staging_buffer);
|
|
|
|
|
|
CreateBuffer(inSize, inUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, outBuffer);
|
|
|
|
|
|
@@ -1216,33 +912,6 @@ void RendererVK::CreateDeviceLocalBuffer(const void *inData, VkDeviceSize inSize
|
|
|
FreeBuffer(staging_buffer);
|
|
|
}
|
|
|
|
|
|
-void RendererVK::FreeBuffer(BufferVK &ioBuffer)
|
|
|
-{
|
|
|
- if (ioBuffer.mBuffer != VK_NULL_HANDLE)
|
|
|
- {
|
|
|
- JPH_ASSERT(mFrameIndex < cFrameCount);
|
|
|
- mFreedBuffers[mFrameIndex][{ ioBuffer.mSize, ioBuffer.mUsage, ioBuffer.mProperties }].push_back(ioBuffer);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void RendererVK::FreeBufferInternal(BufferVK &ioBuffer)
|
|
|
-{
|
|
|
- // Destroy the buffer
|
|
|
- vkDestroyBuffer(mDevice, ioBuffer.mBuffer, nullptr);
|
|
|
- ioBuffer.mBuffer = VK_NULL_HANDLE;
|
|
|
-
|
|
|
- if (ioBuffer.mAllocatedSize > cMaxAllocSize)
|
|
|
- FreeMemory(ioBuffer.mMemory, ioBuffer.mAllocatedSize);
|
|
|
- else
|
|
|
- mMemoryCache[{ ioBuffer.mAllocatedSize, ioBuffer.mUsage, ioBuffer.mProperties }].push_back({ ioBuffer.mMemory, ioBuffer.mOffset });
|
|
|
- ioBuffer.mMemory = VK_NULL_HANDLE;
|
|
|
-}
|
|
|
-
|
|
|
-unique_ptr<ConstantBufferVK> RendererVK::CreateConstantBuffer(VkDeviceSize inBufferSize)
|
|
|
-{
|
|
|
- return make_unique<ConstantBufferVK>(this, inBufferSize);
|
|
|
-}
|
|
|
-
|
|
|
VkImageView RendererVK::CreateImageView(VkImage inImage, VkFormat inFormat, VkImageAspectFlags inAspectFlags)
|
|
|
{
|
|
|
VkImageViewCreateInfo view_info = {};
|
|
|
@@ -1260,7 +929,7 @@ VkImageView RendererVK::CreateImageView(VkImage inImage, VkFormat inFormat, VkIm
|
|
|
return image_view;
|
|
|
}
|
|
|
|
|
|
-void RendererVK::CreateImage(uint32 inWidth, uint32 inHeight, VkFormat inFormat, VkImageTiling inTiling, VkImageUsageFlags inUsage, VkMemoryPropertyFlags inProperties, VkImage &outImage, VkDeviceMemory &outMemory)
|
|
|
+void RendererVK::CreateImage(uint32 inWidth, uint32 inHeight, VkFormat inFormat, VkImageTiling inTiling, VkImageUsageFlags inUsage, VkMemoryPropertyFlags inProperties, VkImage &outImage, MemoryVK &ioMemory)
|
|
|
{
|
|
|
VkImageCreateInfo image_info = {};
|
|
|
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
|
@@ -1281,19 +950,16 @@ void RendererVK::CreateImage(uint32 inWidth, uint32 inHeight, VkFormat inFormat,
|
|
|
VkMemoryRequirements mem_requirements;
|
|
|
vkGetImageMemoryRequirements(mDevice, outImage, &mem_requirements);
|
|
|
|
|
|
- AllocateMemory(mem_requirements.size, mem_requirements.memoryTypeBits, inProperties, outMemory);
|
|
|
+ AllocateMemory(mem_requirements.size, mem_requirements.memoryTypeBits, inProperties, ioMemory);
|
|
|
|
|
|
- vkBindImageMemory(mDevice, outImage, outMemory, 0);
|
|
|
+ vkBindImageMemory(mDevice, outImage, ioMemory.mMemory, 0);
|
|
|
}
|
|
|
|
|
|
-void RendererVK::DestroyImage(VkImage inImage, VkDeviceMemory inMemory)
|
|
|
+void RendererVK::DestroyImage(VkImage inImage, MemoryVK &ioMemory)
|
|
|
{
|
|
|
- VkMemoryRequirements mem_requirements;
|
|
|
- vkGetImageMemoryRequirements(mDevice, inImage, &mem_requirements);
|
|
|
-
|
|
|
vkDestroyImage(mDevice, inImage, nullptr);
|
|
|
|
|
|
- FreeMemory(inMemory, mem_requirements.size);
|
|
|
+ FreeMemory(ioMemory);
|
|
|
}
|
|
|
|
|
|
void RendererVK::UpdateViewPortAndScissorRect(uint32 inWidth, uint32 inHeight)
|
|
|
@@ -1316,9 +982,17 @@ void RendererVK::UpdateViewPortAndScissorRect(uint32 inWidth, uint32 inHeight)
|
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
|
}
|
|
|
|
|
|
-#ifdef JPH_ENABLE_VULKAN
|
|
|
+// The default renderer is Vulkan if we don't have DirectX 12 or Metal
|
|
|
+#if !defined(JPH_USE_DX12) && !defined(JPH_USE_MTL)
|
|
|
+
|
|
|
Renderer *Renderer::sCreate()
|
|
|
{
|
|
|
return new RendererVK;
|
|
|
}
|
|
|
-#endif
|
|
|
+
|
|
|
+#endif // !defined(JPH_USE_DX12) && !defined(JPH_USE_MTL)
|
|
|
+
|
|
|
+Renderer *CreateRendererVK()
|
|
|
+{
|
|
|
+ return new RendererVK;
|
|
|
+}
|