diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 247cadbde8..cbe7f7bb73 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -435,11 +435,14 @@ target_sources(rpcs3_emu PRIVATE if(TARGET 3rdparty_vulkan) target_sources(rpcs3_emu PRIVATE + RSX/VK/vkutils/buffer_view.cpp RSX/VK/vkutils/chip_class.cpp + RSX/VK/vkutils/command_pool.cpp RSX/VK/vkutils/fence.cpp RSX/VK/vkutils/mem_allocator.cpp RSX/VK/vkutils/memory_block.cpp RSX/VK/vkutils/physical_device.cpp + RSX/VK/vkutils/render_device.cpp RSX/VK/vkutils/sampler.cpp RSX/VK/vkutils/shared.cpp RSX/VK/VKCommandStream.cpp diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 355a3bbb77..006bea6ea9 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -2,6 +2,7 @@ #include "../Common/BufferUtils.h" #include "../rsx_methods.h" #include "VKGSRender.h" +#include "vkutils/buffer_view.h" namespace vk { diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 54f9315705..37460b0899 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -7,6 +7,7 @@ #include "VKRenderPass.h" #include "VKResourceManager.h" #include "VKCommandStream.h" +#include "vkutils/buffer_view.h" #include "Emu/RSX/rsx_methods.h" #include "Emu/Memory/vm_locking.h" diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 1e53fed275..f609bfdb61 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -53,6 +53,8 @@ extern u64 get_system_time(); namespace vk { + struct buffer_view; + struct command_buffer_chunk: public vk::command_buffer { vk::fence* submit_fence = nullptr; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 72dc73d628..18f167ba4f 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -21,12 +21,11 @@ #include "../Common/TextureUtils.h" #include "../display.h" #include "../rsx_utils.h" -#include "vkutils/chip_class.h" +#include "vkutils/command_pool.h" #include "vkutils/fence.h" -#include "vkutils/mem_allocator.h" #include "vkutils/memory_block.h" #include "vkutils/physical_device.h" -#include "vkutils/pipeline_binding_table.h" +#include "vkutils/render_device.h" #include "vkutils/shared.h" #include "vkutils/supported_extensions.h" @@ -45,11 +44,6 @@ //using enum rsx::format_class; using namespace ::rsx::format_class_; -namespace rsx -{ - class fragment_texture; -} - namespace vk { VKAPI_ATTR void *VKAPI_CALL mem_realloc(void *pUserData, void *pOriginal, usz size, usz alignment, VkSystemAllocationScope allocationScope); @@ -77,7 +71,6 @@ namespace vk class context; class render_device; - class swap_chain_image; class command_buffer; class image; struct image_view; @@ -192,325 +185,6 @@ namespace vk // TODO: Move queries out of the renderer! void do_query_cleanup(vk::command_buffer& cmd); - class render_device - { - physical_device *pgpu = nullptr; - memory_type_mapping memory_map{}; - gpu_formats_support m_formats_support{}; - pipeline_binding_table m_pipeline_binding_table{}; - std::unique_ptr m_allocator; - VkDevice dev = VK_NULL_HANDLE; - - public: - // Exported device endpoints - PFN_vkCmdBeginConditionalRenderingEXT cmdBeginConditionalRenderingEXT = nullptr; - PFN_vkCmdEndConditionalRenderingEXT cmdEndConditionalRenderingEXT = nullptr; - - public: - render_device() = default; - ~render_device() = default; - - void create(vk::physical_device &pdev, u32 graphics_queue_idx) - { - float queue_priorities[1] = { 0.f }; - pgpu = &pdev; - - VkDeviceQueueCreateInfo queue = {}; - queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue.pNext = NULL; - queue.queueFamilyIndex = graphics_queue_idx; - queue.queueCount = 1; - queue.pQueuePriorities = queue_priorities; - - // Set up instance information - std::vectorrequested_extensions = - { - VK_KHR_SWAPCHAIN_EXTENSION_NAME - }; - - // Enable hardware features manually - // Currently we require: - // 1. Anisotropic sampling - // 2. DXT support - // 3. Indexable storage buffers - VkPhysicalDeviceFeatures enabled_features{}; - if (pgpu->shader_types_support.allow_float16) - { - requested_extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); - } - - if (pgpu->conditional_render_support) - { - requested_extensions.push_back(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME); - } - - if (pgpu->unrestricted_depth_range_support) - { - requested_extensions.push_back(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME); - } - - enabled_features.robustBufferAccess = VK_TRUE; - enabled_features.fullDrawIndexUint32 = VK_TRUE; - enabled_features.independentBlend = VK_TRUE; - enabled_features.logicOp = VK_TRUE; - enabled_features.depthClamp = VK_TRUE; - enabled_features.depthBounds = VK_TRUE; - enabled_features.wideLines = VK_TRUE; - enabled_features.largePoints = VK_TRUE; - enabled_features.shaderFloat64 = VK_TRUE; - - if (g_cfg.video.antialiasing_level != msaa_level::none) - { - // MSAA features - if (!pgpu->features.shaderStorageImageMultisample || - !pgpu->features.shaderStorageImageWriteWithoutFormat) - { - // TODO: Slow fallback to emulate this - // Just warn and let the driver decide whether to crash or not - rsx_log.fatal("Your GPU driver does not support some required MSAA features. Expect problems."); - } - - enabled_features.sampleRateShading = VK_TRUE; - enabled_features.alphaToOne = VK_TRUE; - enabled_features.shaderStorageImageMultisample = VK_TRUE; - // enabled_features.shaderStorageImageReadWithoutFormat = VK_TRUE; // Unused currently, may be needed soon - enabled_features.shaderStorageImageWriteWithoutFormat = VK_TRUE; - } - - // enabled_features.shaderSampledImageArrayDynamicIndexing = TRUE; // Unused currently but will be needed soon - enabled_features.shaderClipDistance = VK_TRUE; - // enabled_features.shaderCullDistance = VK_TRUE; // Alt notation of clip distance - - enabled_features.samplerAnisotropy = VK_TRUE; - enabled_features.textureCompressionBC = VK_TRUE; - enabled_features.shaderStorageBufferArrayDynamicIndexing = VK_TRUE; - - // Optionally disable unsupported stuff - if (!pgpu->features.shaderFloat64) - { - rsx_log.error("Your GPU does not support double precision floats in shaders. Graphics may not work correctly."); - enabled_features.shaderFloat64 = VK_FALSE; - } - - if (!pgpu->features.depthBounds) - { - rsx_log.error("Your GPU does not support depth bounds testing. Graphics may not work correctly."); - enabled_features.depthBounds = VK_FALSE; - } - - if (!pgpu->features.sampleRateShading && enabled_features.sampleRateShading) - { - rsx_log.error("Your GPU does not support sample rate shading for multisampling. Graphics may be inaccurate when MSAA is enabled."); - enabled_features.sampleRateShading = VK_FALSE; - } - - if (!pgpu->features.alphaToOne && enabled_features.alphaToOne) - { - // AMD proprietary drivers do not expose alphaToOne support - rsx_log.error("Your GPU does not support alpha-to-one for multisampling. Graphics may be inaccurate when MSAA is enabled."); - enabled_features.alphaToOne = VK_FALSE; - } - - VkDeviceCreateInfo device = {}; - device.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device.pNext = nullptr; - device.queueCreateInfoCount = 1; - device.pQueueCreateInfos = &queue; - device.enabledLayerCount = 0; - device.ppEnabledLayerNames = nullptr; // Deprecated - device.enabledExtensionCount = ::size32(requested_extensions); - device.ppEnabledExtensionNames = requested_extensions.data(); - device.pEnabledFeatures = &enabled_features; - - VkPhysicalDeviceFloat16Int8FeaturesKHR shader_support_info{}; - if (pgpu->shader_types_support.allow_float16) - { - // Allow use of f16 type in shaders if possible - shader_support_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; - shader_support_info.shaderFloat16 = VK_TRUE; - device.pNext = &shader_support_info; - - rsx_log.notice("GPU/driver supports float16 data types natively. Using native float16_t variables if possible."); - } - else - { - rsx_log.notice("GPU/driver lacks support for float16 data types. All float16_t arithmetic will be emulated with float32_t."); - } - - CHECK_RESULT(vkCreateDevice(*pgpu, &device, nullptr, &dev)); - - // Import optional function endpoints - if (pgpu->conditional_render_support) - { - cmdBeginConditionalRenderingEXT = reinterpret_cast(vkGetDeviceProcAddr(dev, "vkCmdBeginConditionalRenderingEXT")); - cmdEndConditionalRenderingEXT = reinterpret_cast(vkGetDeviceProcAddr(dev, "vkCmdEndConditionalRenderingEXT")); - } - - memory_map = vk::get_memory_mapping(pdev); - m_formats_support = vk::get_optimal_tiling_supported_formats(pdev); - m_pipeline_binding_table = vk::get_pipeline_binding_table(pdev); - - if (g_cfg.video.disable_vulkan_mem_allocator) - m_allocator = std::make_unique(dev, pdev); - else - m_allocator = std::make_unique(dev, pdev); - } - - void destroy() - { - if (dev && pgpu) - { - if (m_allocator) - { - m_allocator->destroy(); - m_allocator.reset(); - } - - vkDestroyDevice(dev, nullptr); - dev = nullptr; - memory_map = {}; - m_formats_support = {}; - } - } - - const VkFormatProperties get_format_properties(VkFormat format) - { - auto found = pgpu->format_properties.find(format); - if (found != pgpu->format_properties.end()) - { - return found->second; - } - - auto& props = pgpu->format_properties[format]; - vkGetPhysicalDeviceFormatProperties(*pgpu, format, &props); - return props; - } - - bool get_compatible_memory_type(u32 typeBits, u32 desired_mask, u32 *type_index) const - { - VkPhysicalDeviceMemoryProperties mem_infos = pgpu->get_memory_properties(); - - for (u32 i = 0; i < 32; i++) - { - if ((typeBits & 1) == 1) - { - if ((mem_infos.memoryTypes[i].propertyFlags & desired_mask) == desired_mask) - { - if (type_index) - { - *type_index = i; - } - - return true; - } - } - - typeBits >>= 1; - } - - return false; - } - - const physical_device& gpu() const - { - return *pgpu; - } - - const memory_type_mapping& get_memory_mapping() const - { - return memory_map; - } - - const gpu_formats_support& get_formats_support() const - { - return m_formats_support; - } - - const pipeline_binding_table& get_pipeline_binding_table() const - { - return m_pipeline_binding_table; - } - - const gpu_shader_types_support& get_shader_types_support() const - { - return pgpu->shader_types_support; - } - - bool get_shader_stencil_export_support() const - { - return pgpu->stencil_export_support; - } - - bool get_depth_bounds_support() const - { - return pgpu->features.depthBounds != VK_FALSE; - } - - bool get_alpha_to_one_support() const - { - return pgpu->features.alphaToOne != VK_FALSE; - } - - bool get_conditional_render_support() const - { - return pgpu->conditional_render_support; - } - - bool get_unrestricted_depth_range_support() const - { - return pgpu->unrestricted_depth_range_support; - } - - mem_allocator_base* get_allocator() const - { - return m_allocator.get(); - } - - operator VkDevice() const - { - return dev; - } - }; - - class command_pool - { - vk::render_device *owner = nullptr; - VkCommandPool pool = nullptr; - - public: - command_pool() = default; - ~command_pool() = default; - - void create(vk::render_device &dev) - { - owner = &dev; - VkCommandPoolCreateInfo infos = {}; - infos.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - infos.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - - CHECK_RESULT(vkCreateCommandPool(dev, &infos, nullptr, &pool)); - } - - void destroy() - { - if (!pool) - return; - - vkDestroyCommandPool((*owner), pool, nullptr); - pool = nullptr; - } - - vk::render_device& get_owner() - { - return (*owner); - } - - operator VkCommandPool() - { - return pool; - } - }; - class command_buffer { private: @@ -1125,53 +799,6 @@ namespace vk VkDevice m_device; }; - struct buffer_view - { - VkBufferView value; - VkBufferViewCreateInfo info = {}; - - buffer_view(VkDevice dev, VkBuffer buffer, VkFormat format, VkDeviceSize offset, VkDeviceSize size) - : m_device(dev) - { - info.buffer = buffer; - info.format = format; - info.offset = offset; - info.range = size; - info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; - CHECK_RESULT(vkCreateBufferView(m_device, &info, nullptr, &value)); - } - - ~buffer_view() - { - vkDestroyBufferView(m_device, value, nullptr); - } - - buffer_view(const buffer_view&) = delete; - buffer_view(buffer_view&&) = delete; - - bool in_range(u32 address, u32 size, u32& offset) const - { - if (address < info.offset) - return false; - - const u32 _offset = address - static_cast(info.offset); - if (info.range < _offset) - return false; - - const auto remaining = info.range - _offset; - if (size <= remaining) - { - offset = _offset; - return true; - } - - return false; - } - - private: - VkDevice m_device; - }; - class event { VkDevice m_device = VK_NULL_HANDLE; diff --git a/rpcs3/Emu/RSX/VK/VKPresent.cpp b/rpcs3/Emu/RSX/VK/VKPresent.cpp index 8d20697105..549b1d85c7 100644 --- a/rpcs3/Emu/RSX/VK/VKPresent.cpp +++ b/rpcs3/Emu/RSX/VK/VKPresent.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "VKGSRender.h" +#include "vkutils/buffer_view.h" #include "Emu/Cell/Modules/cellVideoOut.h" #include "util/asm.hpp" diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 300b244609..ca6126929b 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -2,6 +2,7 @@ #include "VKGSRender.h" #include "../Common/BufferUtils.h" #include "../rsx_methods.h" +#include "vkutils/buffer_view.h" namespace vk { diff --git a/rpcs3/Emu/RSX/VK/vkutils/buffer_view.cpp b/rpcs3/Emu/RSX/VK/vkutils/buffer_view.cpp new file mode 100644 index 0000000000..0208344633 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/buffer_view.cpp @@ -0,0 +1,40 @@ +#include "buffer_view.h" +#include "shared.h" + +namespace vk +{ + buffer_view::buffer_view(VkDevice dev, VkBuffer buffer, VkFormat format, VkDeviceSize offset, VkDeviceSize size) + : m_device(dev) + { + info.buffer = buffer; + info.format = format; + info.offset = offset; + info.range = size; + info.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; + CHECK_RESULT(vkCreateBufferView(m_device, &info, nullptr, &value)); + } + + buffer_view::~buffer_view() + { + vkDestroyBufferView(m_device, value, nullptr); + } + + bool buffer_view::in_range(u32 address, u32 size, u32& offset) const + { + if (address < info.offset) + return false; + + const u32 _offset = address - static_cast(info.offset); + if (info.range < _offset) + return false; + + const auto remaining = info.range - _offset; + if (size <= remaining) + { + offset = _offset; + return true; + } + + return false; + } +} diff --git a/rpcs3/Emu/RSX/VK/vkutils/buffer_view.h b/rpcs3/Emu/RSX/VK/vkutils/buffer_view.h new file mode 100644 index 0000000000..271b614e6e --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/buffer_view.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../VulkanAPI.h" + +namespace vk +{ + struct buffer_view + { + VkBufferView value; + VkBufferViewCreateInfo info = {}; + + buffer_view(VkDevice dev, VkBuffer buffer, VkFormat format, VkDeviceSize offset, VkDeviceSize size); + ~buffer_view(); + + buffer_view(const buffer_view&) = delete; + buffer_view(buffer_view&&) = delete; + + bool in_range(u32 address, u32 size, u32& offset) const; + + private: + VkDevice m_device; + }; +} diff --git a/rpcs3/Emu/RSX/VK/vkutils/command_pool.cpp b/rpcs3/Emu/RSX/VK/vkutils/command_pool.cpp new file mode 100644 index 0000000000..012b67a885 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/command_pool.cpp @@ -0,0 +1,35 @@ +#include "command_pool.h" +#include "render_device.h" +#include "shared.h" + +namespace vk +{ + void command_pool::create(vk::render_device& dev) + { + owner = &dev; + VkCommandPoolCreateInfo infos = {}; + infos.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + infos.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + + CHECK_RESULT(vkCreateCommandPool(dev, &infos, nullptr, &pool)); + } + + void command_pool::destroy() + { + if (!pool) + return; + + vkDestroyCommandPool((*owner), pool, nullptr); + pool = nullptr; + } + + vk::render_device& command_pool::get_owner() + { + return (*owner); + } + + command_pool::operator VkCommandPool() + { + return pool; + } +} diff --git a/rpcs3/Emu/RSX/VK/vkutils/command_pool.h b/rpcs3/Emu/RSX/VK/vkutils/command_pool.h new file mode 100644 index 0000000000..8555e0ae90 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/command_pool.h @@ -0,0 +1,25 @@ +#pragma once + +#include "../VulkanAPI.h" + +namespace vk +{ + class render_device; + + class command_pool + { + vk::render_device* owner = nullptr; + VkCommandPool pool = nullptr; + + public: + command_pool() = default; + ~command_pool() = default; + + void create(vk::render_device& dev); + void destroy(); + + vk::render_device& get_owner(); + + operator VkCommandPool(); + }; +} diff --git a/rpcs3/Emu/RSX/VK/vkutils/render_device.cpp b/rpcs3/Emu/RSX/VK/vkutils/render_device.cpp new file mode 100644 index 0000000000..09e0cb13f3 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/render_device.cpp @@ -0,0 +1,265 @@ +#include "render_device.h" +#include "mem_allocator.h" +#include "shared.h" + +#include "Emu/system_config.h" + +namespace vk +{ + void render_device::create(vk::physical_device& pdev, u32 graphics_queue_idx) + { + float queue_priorities[1] = {0.f}; + pgpu = &pdev; + + VkDeviceQueueCreateInfo queue = {}; + queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue.pNext = NULL; + queue.queueFamilyIndex = graphics_queue_idx; + queue.queueCount = 1; + queue.pQueuePriorities = queue_priorities; + + // Set up instance information + std::vector requested_extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME}; + + // Enable hardware features manually + // Currently we require: + // 1. Anisotropic sampling + // 2. DXT support + // 3. Indexable storage buffers + VkPhysicalDeviceFeatures enabled_features{}; + if (pgpu->shader_types_support.allow_float16) + { + requested_extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); + } + + if (pgpu->conditional_render_support) + { + requested_extensions.push_back(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME); + } + + if (pgpu->unrestricted_depth_range_support) + { + requested_extensions.push_back(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME); + } + + enabled_features.robustBufferAccess = VK_TRUE; + enabled_features.fullDrawIndexUint32 = VK_TRUE; + enabled_features.independentBlend = VK_TRUE; + enabled_features.logicOp = VK_TRUE; + enabled_features.depthClamp = VK_TRUE; + enabled_features.depthBounds = VK_TRUE; + enabled_features.wideLines = VK_TRUE; + enabled_features.largePoints = VK_TRUE; + enabled_features.shaderFloat64 = VK_TRUE; + + if (g_cfg.video.antialiasing_level != msaa_level::none) + { + // MSAA features + if (!pgpu->features.shaderStorageImageMultisample || !pgpu->features.shaderStorageImageWriteWithoutFormat) + { + // TODO: Slow fallback to emulate this + // Just warn and let the driver decide whether to crash or not + rsx_log.fatal("Your GPU driver does not support some required MSAA features. Expect problems."); + } + + enabled_features.sampleRateShading = VK_TRUE; + enabled_features.alphaToOne = VK_TRUE; + enabled_features.shaderStorageImageMultisample = VK_TRUE; + // enabled_features.shaderStorageImageReadWithoutFormat = VK_TRUE; // Unused currently, may be needed soon + enabled_features.shaderStorageImageWriteWithoutFormat = VK_TRUE; + } + + // enabled_features.shaderSampledImageArrayDynamicIndexing = TRUE; // Unused currently but will be needed soon + enabled_features.shaderClipDistance = VK_TRUE; + // enabled_features.shaderCullDistance = VK_TRUE; // Alt notation of clip distance + + enabled_features.samplerAnisotropy = VK_TRUE; + enabled_features.textureCompressionBC = VK_TRUE; + enabled_features.shaderStorageBufferArrayDynamicIndexing = VK_TRUE; + + // Optionally disable unsupported stuff + if (!pgpu->features.shaderFloat64) + { + rsx_log.error("Your GPU does not support double precision floats in shaders. Graphics may not work correctly."); + enabled_features.shaderFloat64 = VK_FALSE; + } + + if (!pgpu->features.depthBounds) + { + rsx_log.error("Your GPU does not support depth bounds testing. Graphics may not work correctly."); + enabled_features.depthBounds = VK_FALSE; + } + + if (!pgpu->features.sampleRateShading && enabled_features.sampleRateShading) + { + rsx_log.error("Your GPU does not support sample rate shading for multisampling. Graphics may be inaccurate when MSAA is enabled."); + enabled_features.sampleRateShading = VK_FALSE; + } + + if (!pgpu->features.alphaToOne && enabled_features.alphaToOne) + { + // AMD proprietary drivers do not expose alphaToOne support + rsx_log.error("Your GPU does not support alpha-to-one for multisampling. Graphics may be inaccurate when MSAA is enabled."); + enabled_features.alphaToOne = VK_FALSE; + } + + VkDeviceCreateInfo device = {}; + device.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device.pNext = nullptr; + device.queueCreateInfoCount = 1; + device.pQueueCreateInfos = &queue; + device.enabledLayerCount = 0; + device.ppEnabledLayerNames = nullptr; // Deprecated + device.enabledExtensionCount = ::size32(requested_extensions); + device.ppEnabledExtensionNames = requested_extensions.data(); + device.pEnabledFeatures = &enabled_features; + + VkPhysicalDeviceFloat16Int8FeaturesKHR shader_support_info{}; + if (pgpu->shader_types_support.allow_float16) + { + // Allow use of f16 type in shaders if possible + shader_support_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; + shader_support_info.shaderFloat16 = VK_TRUE; + device.pNext = &shader_support_info; + + rsx_log.notice("GPU/driver supports float16 data types natively. Using native float16_t variables if possible."); + } + else + { + rsx_log.notice("GPU/driver lacks support for float16 data types. All float16_t arithmetic will be emulated with float32_t."); + } + + CHECK_RESULT(vkCreateDevice(*pgpu, &device, nullptr, &dev)); + + // Import optional function endpoints + if (pgpu->conditional_render_support) + { + cmdBeginConditionalRenderingEXT = reinterpret_cast(vkGetDeviceProcAddr(dev, "vkCmdBeginConditionalRenderingEXT")); + cmdEndConditionalRenderingEXT = reinterpret_cast(vkGetDeviceProcAddr(dev, "vkCmdEndConditionalRenderingEXT")); + } + + memory_map = vk::get_memory_mapping(pdev); + m_formats_support = vk::get_optimal_tiling_supported_formats(pdev); + m_pipeline_binding_table = vk::get_pipeline_binding_table(pdev); + + if (g_cfg.video.disable_vulkan_mem_allocator) + m_allocator = std::make_unique(dev, pdev); + else + m_allocator = std::make_unique(dev, pdev); + } + + void render_device::destroy() + { + if (dev && pgpu) + { + if (m_allocator) + { + m_allocator->destroy(); + m_allocator.reset(); + } + + vkDestroyDevice(dev, nullptr); + dev = nullptr; + memory_map = {}; + m_formats_support = {}; + } + } + + const VkFormatProperties render_device::get_format_properties(VkFormat format) + { + auto found = pgpu->format_properties.find(format); + if (found != pgpu->format_properties.end()) + { + return found->second; + } + + auto& props = pgpu->format_properties[format]; + vkGetPhysicalDeviceFormatProperties(*pgpu, format, &props); + return props; + } + + bool render_device::get_compatible_memory_type(u32 typeBits, u32 desired_mask, u32* type_index) const + { + VkPhysicalDeviceMemoryProperties mem_infos = pgpu->get_memory_properties(); + + for (u32 i = 0; i < 32; i++) + { + if ((typeBits & 1) == 1) + { + if ((mem_infos.memoryTypes[i].propertyFlags & desired_mask) == desired_mask) + { + if (type_index) + { + *type_index = i; + } + + return true; + } + } + + typeBits >>= 1; + } + + return false; + } + + const physical_device& render_device::gpu() const + { + return *pgpu; + } + + const memory_type_mapping& render_device::get_memory_mapping() const + { + return memory_map; + } + + const gpu_formats_support& render_device::get_formats_support() const + { + return m_formats_support; + } + + const pipeline_binding_table& render_device::get_pipeline_binding_table() const + { + return m_pipeline_binding_table; + } + + const gpu_shader_types_support& render_device::get_shader_types_support() const + { + return pgpu->shader_types_support; + } + + bool render_device::get_shader_stencil_export_support() const + { + return pgpu->stencil_export_support; + } + + bool render_device::get_depth_bounds_support() const + { + return pgpu->features.depthBounds != VK_FALSE; + } + + bool render_device::get_alpha_to_one_support() const + { + return pgpu->features.alphaToOne != VK_FALSE; + } + + bool render_device::get_conditional_render_support() const + { + return pgpu->conditional_render_support; + } + + bool render_device::get_unrestricted_depth_range_support() const + { + return pgpu->unrestricted_depth_range_support; + } + + mem_allocator_base* render_device::get_allocator() const + { + return m_allocator.get(); + } + + render_device::operator VkDevice() const + { + return dev; + } +} diff --git a/rpcs3/Emu/RSX/VK/vkutils/render_device.h b/rpcs3/Emu/RSX/VK/vkutils/render_device.h new file mode 100644 index 0000000000..c0313c8353 --- /dev/null +++ b/rpcs3/Emu/RSX/VK/vkutils/render_device.h @@ -0,0 +1,51 @@ +#pragma once + +#include "physical_device.h" +#include + +namespace vk +{ + class mem_allocator_base; + + class render_device + { + physical_device* pgpu = nullptr; + memory_type_mapping memory_map{}; + gpu_formats_support m_formats_support{}; + pipeline_binding_table m_pipeline_binding_table{}; + std::unique_ptr m_allocator; + VkDevice dev = VK_NULL_HANDLE; + + public: + // Exported device endpoints + PFN_vkCmdBeginConditionalRenderingEXT cmdBeginConditionalRenderingEXT = nullptr; + PFN_vkCmdEndConditionalRenderingEXT cmdEndConditionalRenderingEXT = nullptr; + + public: + render_device() = default; + ~render_device() = default; + + void create(vk::physical_device& pdev, u32 graphics_queue_idx); + void destroy(); + + const VkFormatProperties get_format_properties(VkFormat format); + + bool get_compatible_memory_type(u32 typeBits, u32 desired_mask, u32* type_index) const; + + const physical_device& gpu() const; + const memory_type_mapping& get_memory_mapping() const; + const gpu_formats_support& get_formats_support() const; + const pipeline_binding_table& get_pipeline_binding_table() const; + const gpu_shader_types_support& get_shader_types_support() const; + + bool get_shader_stencil_export_support() const; + bool get_depth_bounds_support() const; + bool get_alpha_to_one_support() const; + bool get_conditional_render_support() const; + bool get_unrestricted_depth_range_support() const; + + mem_allocator_base* get_allocator() const; + + operator VkDevice() const; + }; +} diff --git a/rpcs3/VKGSRender.vcxproj b/rpcs3/VKGSRender.vcxproj index 03c281dfb5..590bc4144c 100644 --- a/rpcs3/VKGSRender.vcxproj +++ b/rpcs3/VKGSRender.vcxproj @@ -40,7 +40,9 @@ + + @@ -48,6 +50,7 @@ + @@ -73,11 +76,14 @@ + + + diff --git a/rpcs3/VKGSRender.vcxproj.filters b/rpcs3/VKGSRender.vcxproj.filters index 9d4f9b1605..6108efcd49 100644 --- a/rpcs3/VKGSRender.vcxproj.filters +++ b/rpcs3/VKGSRender.vcxproj.filters @@ -44,6 +44,15 @@ vkutils + + vkutils + + + vkutils + + + vkutils + @@ -102,6 +111,15 @@ vkutils + + vkutils + + + vkutils + + + vkutils +