mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-03 21:41:26 +12:00
VK: refactoring part 1
This commit is contained in:
parent
f8589de476
commit
d9eb31000d
42 changed files with 1849 additions and 1509 deletions
|
@ -435,6 +435,13 @@ target_sources(rpcs3_emu PRIVATE
|
||||||
|
|
||||||
if(TARGET 3rdparty_vulkan)
|
if(TARGET 3rdparty_vulkan)
|
||||||
target_sources(rpcs3_emu PRIVATE
|
target_sources(rpcs3_emu PRIVATE
|
||||||
|
RSX/VK/helpers/chip_class.cpp
|
||||||
|
RSX/VK/helpers/fence.cpp
|
||||||
|
RSX/VK/helpers/mem_allocator.cpp
|
||||||
|
RSX/VK/helpers/memory_block.cpp
|
||||||
|
RSX/VK/helpers/physical_device.cpp
|
||||||
|
RSX/VK/helpers/sampler.cpp
|
||||||
|
RSX/VK/helpers/shared.cpp
|
||||||
RSX/VK/VKCommandStream.cpp
|
RSX/VK/VKCommandStream.cpp
|
||||||
RSX/VK/VKCommonDecompiler.cpp
|
RSX/VK/VKCommonDecompiler.cpp
|
||||||
RSX/VK/VKDMA.cpp
|
RSX/VK/VKDMA.cpp
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "util/types.hpp"
|
#include "util/types.hpp"
|
||||||
#include "Utilities/address_range.h"
|
#include "Utilities/address_range.h"
|
||||||
|
#include "gcm_enums.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "VKCommandStream.h"
|
#include "VKCommandStream.h"
|
||||||
|
#include "helpers/fence.h"
|
||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
|
#include "Emu/system_config.h"
|
||||||
#include "Emu/RSX/RSXOffload.h"
|
#include "Emu/RSX/RSXOffload.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "VKHelpers.h"
|
#include "VulkanAPI.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
struct fence;
|
||||||
|
|
||||||
|
enum // callback commands
|
||||||
|
{
|
||||||
|
rctrl_queue_submit = 0x80000000
|
||||||
|
};
|
||||||
|
|
||||||
struct submit_packet
|
struct submit_packet
|
||||||
{
|
{
|
||||||
// Core components
|
// Core components
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "VKHelpers.h"
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
class address_range;
|
||||||
|
}
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
struct buffer;
|
||||||
|
class command_buffer;
|
||||||
|
class render_device;
|
||||||
|
|
||||||
std::pair<u32, vk::buffer*> map_dma(command_buffer& cmd, u32 local_address, u32 length);
|
std::pair<u32, vk::buffer*> map_dma(command_buffer& cmd, u32 local_address, u32 length);
|
||||||
void load_dma(u32 local_address, u32 length);
|
void load_dma(u32 local_address, u32 length);
|
||||||
void flush_dma(u32 local_address, u32 length);
|
void flush_dma(u32 local_address, u32 length);
|
||||||
|
|
|
@ -1,47 +1,9 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "VKFormats.h"
|
#include "VKFormats.h"
|
||||||
|
#include "VKHelpers.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
gpu_formats_support get_optimal_tiling_supported_formats(const physical_device& dev)
|
|
||||||
{
|
|
||||||
gpu_formats_support result = {};
|
|
||||||
|
|
||||||
VkFormatProperties props;
|
|
||||||
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_D24_UNORM_S8_UINT, &props);
|
|
||||||
|
|
||||||
result.d24_unorm_s8 = !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
|
|
||||||
&& !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
|
||||||
&& !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)
|
|
||||||
&& !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
|
|
||||||
|
|
||||||
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_D32_SFLOAT_S8_UINT, &props);
|
|
||||||
result.d32_sfloat_s8 = !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
|
|
||||||
&& !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
|
||||||
&& !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
|
|
||||||
|
|
||||||
// Hide d24_s8 if force high precision z buffer is enabled
|
|
||||||
if (g_cfg.video.force_high_precision_z_buffer && result.d32_sfloat_s8)
|
|
||||||
result.d24_unorm_s8 = false;
|
|
||||||
|
|
||||||
// Checks if BGRA8 images can be used for blitting
|
|
||||||
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_B8G8R8A8_UNORM, &props);
|
|
||||||
result.bgra8_linear = !!(props.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
|
|
||||||
|
|
||||||
// Check if device supports RGBA8 format
|
|
||||||
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_R8G8B8A8_UNORM, &props);
|
|
||||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) ||
|
|
||||||
!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ||
|
|
||||||
!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT))
|
|
||||||
{
|
|
||||||
// Non-fatal. Most games use BGRA layout due to legacy reasons as old GPUs typically supported BGRA and RGBA was emulated.
|
|
||||||
rsx_log.error("Your GPU and/or driver does not support RGBA8 format. This can cause problems in some rare games that use this memory layout.");
|
|
||||||
}
|
|
||||||
|
|
||||||
result.argb8_linear = !!(props.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFormat get_compatible_depth_surface_format(const gpu_formats_support &support, rsx::surface_depth_format2 format)
|
VkFormat get_compatible_depth_surface_format(const gpu_formats_support &support, rsx::surface_depth_format2 format)
|
||||||
{
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "VKHelpers.h"
|
#include "VulkanAPI.h"
|
||||||
|
#include "../gcm_enums.h"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
class image;
|
||||||
|
struct gpu_formats_support;
|
||||||
|
|
||||||
struct minification_filter
|
struct minification_filter
|
||||||
{
|
{
|
||||||
VkFilter filter;
|
VkFilter filter;
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
#include "../Common/GLSLTypes.h"
|
#include "../Common/GLSLTypes.h"
|
||||||
#include "Emu/RSX/RSXFragmentProgram.h"
|
#include "Emu/RSX/RSXFragmentProgram.h"
|
||||||
#include "VulkanAPI.h"
|
#include "VulkanAPI.h"
|
||||||
#include "VKHelpers.h"
|
#include "VKProgramPipeline.h"
|
||||||
|
#include "helpers/pipeline_binding_table.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,55 +17,7 @@
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
static chip_family_table s_AMD_family_tree = []()
|
extern chip_class g_chip_class;
|
||||||
{
|
|
||||||
chip_family_table table;
|
|
||||||
table.default_ = chip_class::AMD_gcn_generic;
|
|
||||||
|
|
||||||
// AMD cards. See https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
|
||||||
table.add(0x67C0, 0x67FF, chip_class::AMD_polaris);
|
|
||||||
table.add(0x6FDF, chip_class::AMD_polaris); // RX580 2048SP
|
|
||||||
table.add(0x6980, 0x699F, chip_class::AMD_polaris); // Polaris12
|
|
||||||
table.add(0x694C, 0x694F, chip_class::AMD_vega); // VegaM
|
|
||||||
table.add(0x6860, 0x686F, chip_class::AMD_vega); // VegaPro
|
|
||||||
table.add(0x687F, chip_class::AMD_vega); // Vega56/64
|
|
||||||
table.add(0x69A0, 0x69AF, chip_class::AMD_vega); // Vega12
|
|
||||||
table.add(0x66A0, 0x66AF, chip_class::AMD_vega); // Vega20
|
|
||||||
table.add(0x15DD, chip_class::AMD_vega); // Raven Ridge
|
|
||||||
table.add(0x15D8, chip_class::AMD_vega); // Raven Ridge
|
|
||||||
table.add(0x7310, 0x731F, chip_class::AMD_navi1x); // Navi10
|
|
||||||
table.add(0x7340, 0x734F, chip_class::AMD_navi1x); // Navi14
|
|
||||||
table.add(0x73A0, 0x73BF, chip_class::AMD_navi2x); // Sienna cichlid
|
|
||||||
|
|
||||||
return table;
|
|
||||||
}();
|
|
||||||
|
|
||||||
static chip_family_table s_NV_family_tree = []()
|
|
||||||
{
|
|
||||||
chip_family_table table;
|
|
||||||
table.default_ = chip_class::NV_generic;
|
|
||||||
|
|
||||||
// NV cards. See https://envytools.readthedocs.io/en/latest/hw/pciid.html
|
|
||||||
// NOTE: Since NV device IDs are linearly incremented per generation, there is no need to carefully check all the ranges
|
|
||||||
table.add(0x1180, 0x11fa, chip_class::NV_kepler); // GK104, 106
|
|
||||||
table.add(0x0FC0, 0x0FFF, chip_class::NV_kepler); // GK107
|
|
||||||
table.add(0x1003, 0x1028, chip_class::NV_kepler); // GK110
|
|
||||||
table.add(0x1280, 0x12BA, chip_class::NV_kepler); // GK208
|
|
||||||
table.add(0x1381, 0x13B0, chip_class::NV_maxwell); // GM107
|
|
||||||
table.add(0x1340, 0x134D, chip_class::NV_maxwell); // GM108
|
|
||||||
table.add(0x13C0, 0x13D9, chip_class::NV_maxwell); // GM204
|
|
||||||
table.add(0x1401, 0x1427, chip_class::NV_maxwell); // GM206
|
|
||||||
table.add(0x15F7, 0x15F9, chip_class::NV_pascal); // GP100 (Tesla P100)
|
|
||||||
table.add(0x1B00, 0x1D80, chip_class::NV_pascal);
|
|
||||||
table.add(0x1D81, 0x1DBA, chip_class::NV_volta);
|
|
||||||
table.add(0x1E02, 0x1F54, chip_class::NV_turing); // TU102, TU104, TU106, TU106M, TU106GL (RTX 20 series)
|
|
||||||
table.add(0x1F82, 0x1FB9, chip_class::NV_turing); // TU117, TU117M, TU117GL
|
|
||||||
table.add(0x2182, 0x21D1, chip_class::NV_turing); // TU116, TU116M, TU116GL
|
|
||||||
table.add(0x20B0, 0x20BE, chip_class::NV_ampere); // GA100
|
|
||||||
table.add(0x2204, 0x25AF, chip_class::NV_ampere); // GA10x (RTX 30 series)
|
|
||||||
|
|
||||||
return table;
|
|
||||||
}();
|
|
||||||
|
|
||||||
const context* g_current_vulkan_ctx = nullptr;
|
const context* g_current_vulkan_ctx = nullptr;
|
||||||
const render_device* g_current_renderer;
|
const render_device* g_current_renderer;
|
||||||
|
@ -87,7 +39,6 @@ namespace vk
|
||||||
// Driver compatibility workarounds
|
// Driver compatibility workarounds
|
||||||
VkFlags g_heap_compatible_buffer_types = 0;
|
VkFlags g_heap_compatible_buffer_types = 0;
|
||||||
driver_vendor g_driver_vendor = driver_vendor::unknown;
|
driver_vendor g_driver_vendor = driver_vendor::unknown;
|
||||||
chip_class g_chip_class = chip_class::unknown;
|
|
||||||
bool g_drv_no_primitive_restart = false;
|
bool g_drv_no_primitive_restart = false;
|
||||||
bool g_drv_sanitize_fp_values = false;
|
bool g_drv_sanitize_fp_values = false;
|
||||||
bool g_drv_disable_fence_reset = false;
|
bool g_drv_disable_fence_reset = false;
|
||||||
|
@ -179,81 +130,6 @@ namespace vk
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_type_mapping get_memory_mapping(const vk::physical_device& dev)
|
|
||||||
{
|
|
||||||
VkPhysicalDevice pdev = dev;
|
|
||||||
VkPhysicalDeviceMemoryProperties memory_properties;
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(pdev, &memory_properties);
|
|
||||||
|
|
||||||
memory_type_mapping result;
|
|
||||||
result.device_local = VK_MAX_MEMORY_TYPES;
|
|
||||||
result.host_visible_coherent = VK_MAX_MEMORY_TYPES;
|
|
||||||
|
|
||||||
bool host_visible_cached = false;
|
|
||||||
VkDeviceSize host_visible_vram_size = 0;
|
|
||||||
VkDeviceSize device_local_vram_size = 0;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < memory_properties.memoryTypeCount; i++)
|
|
||||||
{
|
|
||||||
VkMemoryHeap &heap = memory_properties.memoryHeaps[memory_properties.memoryTypes[i].heapIndex];
|
|
||||||
|
|
||||||
bool is_device_local = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
||||||
if (is_device_local)
|
|
||||||
{
|
|
||||||
if (device_local_vram_size < heap.size)
|
|
||||||
{
|
|
||||||
result.device_local = i;
|
|
||||||
device_local_vram_size = heap.size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_host_visible = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
|
||||||
bool is_host_coherent = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
||||||
bool is_cached = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
|
|
||||||
|
|
||||||
if (is_host_coherent && is_host_visible)
|
|
||||||
{
|
|
||||||
if ((is_cached && !host_visible_cached) ||
|
|
||||||
(host_visible_vram_size < heap.size))
|
|
||||||
{
|
|
||||||
result.host_visible_coherent = i;
|
|
||||||
host_visible_vram_size = heap.size;
|
|
||||||
host_visible_cached = is_cached;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.device_local == VK_MAX_MEMORY_TYPES) fmt::throw_exception("GPU doesn't support device local memory");
|
|
||||||
if (result.host_visible_coherent == VK_MAX_MEMORY_TYPES) fmt::throw_exception("GPU doesn't support host coherent device local memory");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline_binding_table get_pipeline_binding_table(const vk::physical_device& dev)
|
|
||||||
{
|
|
||||||
pipeline_binding_table result{};
|
|
||||||
|
|
||||||
// Need to check how many samplers are supported by the driver
|
|
||||||
const auto usable_samplers = std::min(dev.get_limits().maxPerStageDescriptorSampledImages, 32u);
|
|
||||||
result.vertex_textures_first_bind_slot = result.textures_first_bind_slot + usable_samplers;
|
|
||||||
result.total_descriptor_bindings = result.vertex_textures_first_bind_slot + 4;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
chip_class get_chip_family(u32 vendor_id, u32 device_id)
|
|
||||||
{
|
|
||||||
if (vendor_id == 0x10DE)
|
|
||||||
{
|
|
||||||
return s_NV_family_tree.find(device_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vendor_id == 0x1002)
|
|
||||||
{
|
|
||||||
return s_AMD_family_tree.find(device_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return chip_class::unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkAllocationCallbacks default_callbacks()
|
VkAllocationCallbacks default_callbacks()
|
||||||
{
|
{
|
||||||
VkAllocationCallbacks callbacks;
|
VkAllocationCallbacks callbacks;
|
||||||
|
@ -469,12 +345,6 @@ namespace vk
|
||||||
g_overlay_passes.clear();
|
g_overlay_passes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::mem_allocator_base* get_current_mem_allocator()
|
|
||||||
{
|
|
||||||
ensure(g_current_renderer);
|
|
||||||
return g_current_renderer->get_allocator();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_current_thread_ctx(const vk::context &ctx)
|
void set_current_thread_ctx(const vk::context &ctx)
|
||||||
{
|
{
|
||||||
g_current_vulkan_ctx = &ctx;
|
g_current_vulkan_ctx = &ctx;
|
||||||
|
@ -577,11 +447,6 @@ namespace vk
|
||||||
return g_driver_vendor;
|
return g_driver_vendor;
|
||||||
}
|
}
|
||||||
|
|
||||||
chip_class get_chip_family()
|
|
||||||
{
|
|
||||||
return g_chip_class;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool emulate_primitive_restart(rsx::primitive_type type)
|
bool emulate_primitive_restart(rsx::primitive_type type)
|
||||||
{
|
{
|
||||||
if (g_drv_no_primitive_restart)
|
if (g_drv_no_primitive_restart)
|
||||||
|
@ -1023,134 +888,6 @@ namespace vk
|
||||||
renderer->emergency_query_cleanup(&cmd);
|
renderer->emergency_query_cleanup(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void die_with_error(VkResult error_code,
|
|
||||||
const char* file,
|
|
||||||
const char* func,
|
|
||||||
u32 line,
|
|
||||||
u32 col)
|
|
||||||
{
|
|
||||||
std::string error_message;
|
|
||||||
int severity = 0; //0 - die, 1 - warn, 2 - nothing
|
|
||||||
|
|
||||||
switch (error_code)
|
|
||||||
{
|
|
||||||
case VK_SUCCESS:
|
|
||||||
case VK_EVENT_SET:
|
|
||||||
case VK_EVENT_RESET:
|
|
||||||
case VK_INCOMPLETE:
|
|
||||||
return;
|
|
||||||
case VK_SUBOPTIMAL_KHR:
|
|
||||||
error_message = "Present surface is suboptimal (VK_SUBOPTIMAL_KHR)";
|
|
||||||
severity = 1;
|
|
||||||
break;
|
|
||||||
case VK_NOT_READY:
|
|
||||||
error_message = "Device or resource busy (VK_NOT_READY)";
|
|
||||||
break;
|
|
||||||
case VK_TIMEOUT:
|
|
||||||
error_message = "Timeout event (VK_TIMEOUT)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
|
||||||
error_message = "Out of host memory (system RAM) (VK_ERROR_OUT_OF_HOST_MEMORY)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
|
||||||
error_message = "Out of video memory (VRAM) (VK_ERROR_OUT_OF_DEVICE_MEMORY)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_INITIALIZATION_FAILED:
|
|
||||||
error_message = "Initialization failed (VK_ERROR_INITIALIZATION_FAILED)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_DEVICE_LOST:
|
|
||||||
error_message = "Device lost (Driver crashed with unspecified error or stopped responding and recovered) (VK_ERROR_DEVICE_LOST)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_MEMORY_MAP_FAILED:
|
|
||||||
error_message = "Memory map failed (VK_ERROR_MEMORY_MAP_FAILED)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_LAYER_NOT_PRESENT:
|
|
||||||
error_message = "Requested layer is not available (Try disabling debug output or install vulkan SDK) (VK_ERROR_LAYER_NOT_PRESENT)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
|
||||||
error_message = "Requested extension not available (VK_ERROR_EXTENSION_NOT_PRESENT)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_FEATURE_NOT_PRESENT:
|
|
||||||
error_message = "Requested feature not available (VK_ERROR_FEATURE_NOT_PRESENT)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
|
||||||
error_message = "Incompatible driver (VK_ERROR_INCOMPATIBLE_DRIVER)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_TOO_MANY_OBJECTS:
|
|
||||||
error_message = "Too many objects created (Out of handles) (VK_ERROR_TOO_MANY_OBJECTS)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_FORMAT_NOT_SUPPORTED:
|
|
||||||
error_message = "Format not supported (VK_ERROR_FORMAT_NOT_SUPPORTED)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_FRAGMENTED_POOL:
|
|
||||||
error_message = "Fragmented pool (VK_ERROR_FRAGMENTED_POOL)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_SURFACE_LOST_KHR:
|
|
||||||
error_message = "Surface lost (VK_ERROR_SURFACE_LOST)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
|
||||||
error_message = "Native window in use (VK_ERROR_NATIVE_WINDOW_IN_USE_KHR)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_OUT_OF_DATE_KHR:
|
|
||||||
error_message = "Present surface is out of date (VK_ERROR_OUT_OF_DATE_KHR)";
|
|
||||||
severity = 1;
|
|
||||||
break;
|
|
||||||
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
|
|
||||||
error_message = "Incompatible display (VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_VALIDATION_FAILED_EXT:
|
|
||||||
error_message = "Validation failed (VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_INVALID_SHADER_NV:
|
|
||||||
error_message = "Invalid shader code (VK_ERROR_INVALID_SHADER_NV)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_OUT_OF_POOL_MEMORY_KHR:
|
|
||||||
error_message = "Out of pool memory (VK_ERROR_OUT_OF_POOL_MEMORY_KHR)";
|
|
||||||
break;
|
|
||||||
case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR:
|
|
||||||
error_message = "Invalid external handle (VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR)";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error_message = fmt::format("Unknown Code (%Xh, %d)%s", static_cast<s32>(error_code), static_cast<s32>(error_code), src_loc{line, col, file, func});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (severity)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case 0:
|
|
||||||
fmt::throw_exception("Assertion Failed! Vulkan API call failed with unrecoverable error: %s%s", error_message, src_loc{line, col, file, func});
|
|
||||||
case 1:
|
|
||||||
rsx_log.error("Vulkan API call has failed with an error but will continue: %s%s", error_message, src_loc{line, col, file, func});
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VKAPI_ATTR VkBool32 VKAPI_CALL dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
|
|
||||||
u64 srcObject, usz location, s32 msgCode,
|
|
||||||
const char *pLayerPrefix, const char *pMsg, void *pUserData)
|
|
||||||
{
|
|
||||||
if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
|
|
||||||
{
|
|
||||||
if (strstr(pMsg, "IMAGE_VIEW_TYPE_1D")) return false;
|
|
||||||
|
|
||||||
rsx_log.error("ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
|
|
||||||
}
|
|
||||||
else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
|
|
||||||
{
|
|
||||||
rsx_log.warning("WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Let the app crash..
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkBool32 BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
|
VkBool32 BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
|
||||||
u64 srcObject, usz location, s32 msgCode,
|
u64 srcObject, usz location, s32 msgCode,
|
||||||
const char *pLayerPrefix, const char *pMsg, void *pUserData)
|
const char *pLayerPrefix, const char *pMsg, void *pUserData)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,6 +7,7 @@
|
||||||
#include "VKResourceManager.h"
|
#include "VKResourceManager.h"
|
||||||
#include "VKRenderPass.h"
|
#include "VKRenderPass.h"
|
||||||
#include "VKPipelineCompiler.h"
|
#include "VKPipelineCompiler.h"
|
||||||
|
#include "helpers/sampler.h"
|
||||||
|
|
||||||
#include "../Overlays/overlays.h"
|
#include "../Overlays/overlays.h"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "VKPipelineCompiler.h"
|
#include "VKPipelineCompiler.h"
|
||||||
#include "VKRenderPass.h"
|
#include "VKRenderPass.h"
|
||||||
|
#include "VKHelpers.h"
|
||||||
#include "Utilities/Thread.h"
|
#include "Utilities/Thread.h"
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "VKHelpers.h"
|
|
||||||
#include "../rsx_utils.h"
|
#include "../rsx_utils.h"
|
||||||
#include "Utilities/hash.h"
|
#include "Utilities/hash.h"
|
||||||
#include "Utilities/lockless.h"
|
#include "Utilities/lockless.h"
|
||||||
|
#include "VKProgramPipeline.h"
|
||||||
|
#include "helpers/graphics_pipeline_state.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
class render_device;
|
||||||
|
|
||||||
struct pipeline_props
|
struct pipeline_props
|
||||||
{
|
{
|
||||||
graphics_pipeline_state state;
|
graphics_pipeline_state state;
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#include "VKFragmentProgram.h"
|
#include "VKFragmentProgram.h"
|
||||||
#include "../Common/ProgramStateCache.h"
|
#include "../Common/ProgramStateCache.h"
|
||||||
#include "Utilities/hash.h"
|
#include "Utilities/hash.h"
|
||||||
#include "VKHelpers.h"
|
|
||||||
#include "VKRenderPass.h"
|
#include "VKRenderPass.h"
|
||||||
#include "VKPipelineCompiler.h"
|
#include "VKPipelineCompiler.h"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include "VKProgramPipeline.h"
|
||||||
#include "VKHelpers.h"
|
#include "VKHelpers.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -9,6 +10,66 @@ namespace vk
|
||||||
{
|
{
|
||||||
using namespace ::glsl;
|
using namespace ::glsl;
|
||||||
|
|
||||||
|
void shader::create(::glsl::program_domain domain, const std::string& source)
|
||||||
|
{
|
||||||
|
type = domain;
|
||||||
|
m_source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule shader::compile()
|
||||||
|
{
|
||||||
|
ensure(m_handle == VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
if (!vk::compile_glsl_to_spv(m_source, type, m_compiled))
|
||||||
|
{
|
||||||
|
const std::string shader_type = type == ::glsl::program_domain::glsl_vertex_program ? "vertex" :
|
||||||
|
type == ::glsl::program_domain::glsl_fragment_program ? "fragment" : "compute";
|
||||||
|
|
||||||
|
rsx_log.notice("%s", m_source);
|
||||||
|
fmt::throw_exception("Failed to compile %s shader", shader_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModuleCreateInfo vs_info;
|
||||||
|
vs_info.codeSize = m_compiled.size() * sizeof(u32);
|
||||||
|
vs_info.pNext = nullptr;
|
||||||
|
vs_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
vs_info.pCode = m_compiled.data();
|
||||||
|
vs_info.flags = 0;
|
||||||
|
|
||||||
|
VkDevice dev = *vk::get_current_renderer();
|
||||||
|
vkCreateShaderModule(dev, &vs_info, nullptr, &m_handle);
|
||||||
|
|
||||||
|
return m_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shader::destroy()
|
||||||
|
{
|
||||||
|
m_source.clear();
|
||||||
|
m_compiled.clear();
|
||||||
|
|
||||||
|
if (m_handle)
|
||||||
|
{
|
||||||
|
VkDevice dev = *vk::get_current_renderer();
|
||||||
|
vkDestroyShaderModule(dev, m_handle, nullptr);
|
||||||
|
m_handle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& shader::get_source() const
|
||||||
|
{
|
||||||
|
return m_source;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<u32> shader::get_compiled() const
|
||||||
|
{
|
||||||
|
return m_compiled;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkShaderModule shader::get_handle() const
|
||||||
|
{
|
||||||
|
return m_handle;
|
||||||
|
}
|
||||||
|
|
||||||
void program::create_impl()
|
void program::create_impl()
|
||||||
{
|
{
|
||||||
linked = false;
|
linked = false;
|
||||||
|
|
112
rpcs3/Emu/RSX/VK/VKProgramPipeline.h
Normal file
112
rpcs3/Emu/RSX/VK/VKProgramPipeline.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VulkanAPI.h"
|
||||||
|
#include "VKCommonDecompiler.h"
|
||||||
|
#include "../Common/GLSLTypes.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
namespace glsl
|
||||||
|
{
|
||||||
|
enum program_input_type : u32
|
||||||
|
{
|
||||||
|
input_type_uniform_buffer = 0,
|
||||||
|
input_type_texel_buffer = 1,
|
||||||
|
input_type_texture = 2,
|
||||||
|
input_type_storage_buffer = 3,
|
||||||
|
|
||||||
|
input_type_max_enum = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bound_sampler
|
||||||
|
{
|
||||||
|
VkFormat format;
|
||||||
|
VkImage image;
|
||||||
|
VkComponentMapping mapping;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bound_buffer
|
||||||
|
{
|
||||||
|
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||||
|
VkBuffer buffer = nullptr;
|
||||||
|
u64 offset = 0;
|
||||||
|
u64 size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct program_input
|
||||||
|
{
|
||||||
|
::glsl::program_domain domain;
|
||||||
|
program_input_type type;
|
||||||
|
|
||||||
|
bound_buffer as_buffer;
|
||||||
|
bound_sampler as_sampler;
|
||||||
|
|
||||||
|
u32 location;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class shader
|
||||||
|
{
|
||||||
|
::glsl::program_domain type = ::glsl::program_domain::glsl_vertex_program;
|
||||||
|
VkShaderModule m_handle = VK_NULL_HANDLE;
|
||||||
|
std::string m_source;
|
||||||
|
std::vector<u32> m_compiled;
|
||||||
|
|
||||||
|
public:
|
||||||
|
shader() = default;
|
||||||
|
~shader() = default;
|
||||||
|
|
||||||
|
void create(::glsl::program_domain domain, const std::string& source);
|
||||||
|
|
||||||
|
VkShaderModule compile();
|
||||||
|
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
const std::string& get_source() const;
|
||||||
|
const std::vector<u32> get_compiled() const;
|
||||||
|
|
||||||
|
VkShaderModule get_handle() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class program
|
||||||
|
{
|
||||||
|
std::array<std::vector<program_input>, input_type_max_enum> uniforms;
|
||||||
|
VkDevice m_device;
|
||||||
|
|
||||||
|
std::array<u32, 16> fs_texture_bindings;
|
||||||
|
std::array<u32, 16> fs_texture_mirror_bindings;
|
||||||
|
std::array<u32, 4> vs_texture_bindings;
|
||||||
|
bool linked;
|
||||||
|
|
||||||
|
void create_impl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
VkPipeline pipeline;
|
||||||
|
VkPipelineLayout pipeline_layout;
|
||||||
|
u64 attribute_location_mask;
|
||||||
|
u64 vertex_attributes_mask;
|
||||||
|
|
||||||
|
program(VkDevice dev, VkPipeline p, VkPipelineLayout layout, const std::vector<program_input> &vertex_input, const std::vector<program_input>& fragment_inputs);
|
||||||
|
program(VkDevice dev, VkPipeline p, VkPipelineLayout layout);
|
||||||
|
program(const program&) = delete;
|
||||||
|
program(program&& other) = delete;
|
||||||
|
~program();
|
||||||
|
|
||||||
|
program& load_uniforms(const std::vector<program_input>& inputs);
|
||||||
|
program& link();
|
||||||
|
|
||||||
|
bool has_uniform(program_input_type type, const std::string &uniform_name);
|
||||||
|
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, const std::string &uniform_name, VkDescriptorType type, VkDescriptorSet &descriptor_set);
|
||||||
|
void bind_uniform(const VkDescriptorImageInfo &image_descriptor, int texture_unit, ::glsl::program_domain domain, VkDescriptorSet &descriptor_set, bool is_stencil_mirror = false);
|
||||||
|
void bind_uniform(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorSet &descriptor_set);
|
||||||
|
void bind_uniform(const VkBufferView &buffer_view, u32 binding_point, VkDescriptorSet &descriptor_set);
|
||||||
|
void bind_uniform(const VkBufferView &buffer_view, program_input_type type, const std::string &binding_name, VkDescriptorSet &descriptor_set);
|
||||||
|
|
||||||
|
void bind_buffer(const VkDescriptorBufferInfo &buffer_descriptor, u32 binding_point, VkDescriptorType type, VkDescriptorSet &descriptor_set);
|
||||||
|
void bind_descriptor_set(const VkCommandBuffer cmd, VkDescriptorSet descriptor_set);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "VKHelpers.h"
|
#include "VulkanAPI.h"
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
class command_buffer;
|
||||||
|
class query_pool;
|
||||||
|
class render_device;
|
||||||
|
|
||||||
class query_pool_manager
|
class query_pool_manager
|
||||||
{
|
{
|
||||||
struct query_slot_info
|
struct query_slot_info
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "Utilities/mutex.h"
|
#include "Utilities/mutex.h"
|
||||||
#include "VKRenderPass.h"
|
#include "VKRenderPass.h"
|
||||||
|
#include "VKHelpers.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "VKHelpers.h"
|
#include "VulkanAPI.h"
|
||||||
|
#include "Utilities/geometry.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
class image;
|
||||||
|
|
||||||
u64 get_renderpass_key(const std::vector<vk::image*>& images);
|
u64 get_renderpass_key(const std::vector<vk::image*>& images);
|
||||||
u64 get_renderpass_key(const std::vector<vk::image*>& images, u64 previous_key);
|
u64 get_renderpass_key(const std::vector<vk::image*>& images, u64 previous_key);
|
||||||
u64 get_renderpass_key(VkFormat surface_format);
|
u64 get_renderpass_key(VkFormat surface_format);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "VKHelpers.h"
|
#include "VKHelpers.h"
|
||||||
|
#include "helpers/query_pool.h"
|
||||||
|
#include "helpers/sampler.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "VKProgramBuffer.h"
|
#include "VKProgramBuffer.h"
|
||||||
|
#include "VKHelpers.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
#include "Emu/RSX/RSXVertexProgram.h"
|
#include "Emu/RSX/RSXVertexProgram.h"
|
||||||
#include "Utilities/Thread.h"
|
#include "Utilities/Thread.h"
|
||||||
#include "VulkanAPI.h"
|
#include "VulkanAPI.h"
|
||||||
#include "../VK/VKHelpers.h"
|
#include "VKProgramPipeline.h"
|
||||||
|
#include "helpers/pipeline_binding_table.h"
|
||||||
|
|
||||||
namespace vk
|
namespace vk
|
||||||
{
|
{
|
||||||
|
|
51
rpcs3/Emu/RSX/VK/helpers/chip_class.cpp
Normal file
51
rpcs3/Emu/RSX/VK/helpers/chip_class.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#include "chip_class.h"
|
||||||
|
#include "util/logs.hpp"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
chip_class g_chip_class = chip_class::unknown;
|
||||||
|
|
||||||
|
chip_class get_chip_family()
|
||||||
|
{
|
||||||
|
return g_chip_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip_class get_chip_family(u32 vendor_id, u32 device_id)
|
||||||
|
{
|
||||||
|
if (vendor_id == 0x10DE)
|
||||||
|
{
|
||||||
|
return s_NV_family_tree.find(device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vendor_id == 0x1002)
|
||||||
|
{
|
||||||
|
return s_AMD_family_tree.find(device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chip_class::unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chip_family_table::add(u32 first, u32 last, chip_class family)
|
||||||
|
{
|
||||||
|
for (auto i = first; i <= last; ++i)
|
||||||
|
{
|
||||||
|
lut[i] = family;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void chip_family_table::add(u32 id, chip_class family)
|
||||||
|
{
|
||||||
|
lut[id] = family;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip_class chip_family_table::find(u32 device_id)
|
||||||
|
{
|
||||||
|
if (auto found = lut.find(device_id); found != lut.end())
|
||||||
|
{
|
||||||
|
return found->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
rsx_log.warning("Unknown chip with device ID 0x%x", device_id);
|
||||||
|
return default_;
|
||||||
|
}
|
||||||
|
}
|
98
rpcs3/Emu/RSX/VK/helpers/chip_class.h
Normal file
98
rpcs3/Emu/RSX/VK/helpers/chip_class.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/types.hpp"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
// Chip classes grouped by vendor in order of release
|
||||||
|
enum class chip_class
|
||||||
|
{
|
||||||
|
unknown,
|
||||||
|
AMD_gcn_generic,
|
||||||
|
AMD_polaris,
|
||||||
|
AMD_vega,
|
||||||
|
AMD_navi1x,
|
||||||
|
AMD_navi2x,
|
||||||
|
NV_generic,
|
||||||
|
NV_kepler,
|
||||||
|
NV_maxwell,
|
||||||
|
NV_pascal,
|
||||||
|
NV_volta,
|
||||||
|
NV_turing,
|
||||||
|
NV_ampere
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class driver_vendor
|
||||||
|
{
|
||||||
|
unknown,
|
||||||
|
AMD,
|
||||||
|
NVIDIA,
|
||||||
|
RADV,
|
||||||
|
INTEL
|
||||||
|
};
|
||||||
|
|
||||||
|
struct chip_family_table
|
||||||
|
{
|
||||||
|
chip_class default_ = chip_class::unknown;
|
||||||
|
std::unordered_map<u32, chip_class> lut;
|
||||||
|
|
||||||
|
void add(u32 first, u32 last, chip_class family);
|
||||||
|
void add(u32 id, chip_class family);
|
||||||
|
|
||||||
|
chip_class find(u32 device_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
static chip_family_table s_AMD_family_tree = []()
|
||||||
|
{
|
||||||
|
chip_family_table table;
|
||||||
|
table.default_ = chip_class::AMD_gcn_generic;
|
||||||
|
|
||||||
|
// AMD cards. See https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
||||||
|
table.add(0x67C0, 0x67FF, chip_class::AMD_polaris);
|
||||||
|
table.add(0x6FDF, chip_class::AMD_polaris); // RX580 2048SP
|
||||||
|
table.add(0x6980, 0x699F, chip_class::AMD_polaris); // Polaris12
|
||||||
|
table.add(0x694C, 0x694F, chip_class::AMD_vega); // VegaM
|
||||||
|
table.add(0x6860, 0x686F, chip_class::AMD_vega); // VegaPro
|
||||||
|
table.add(0x687F, chip_class::AMD_vega); // Vega56/64
|
||||||
|
table.add(0x69A0, 0x69AF, chip_class::AMD_vega); // Vega12
|
||||||
|
table.add(0x66A0, 0x66AF, chip_class::AMD_vega); // Vega20
|
||||||
|
table.add(0x15DD, chip_class::AMD_vega); // Raven Ridge
|
||||||
|
table.add(0x15D8, chip_class::AMD_vega); // Raven Ridge
|
||||||
|
table.add(0x7310, 0x731F, chip_class::AMD_navi1x); // Navi10
|
||||||
|
table.add(0x7340, 0x734F, chip_class::AMD_navi1x); // Navi14
|
||||||
|
table.add(0x73A0, 0x73BF, chip_class::AMD_navi2x); // Sienna cichlid
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}();
|
||||||
|
|
||||||
|
static chip_family_table s_NV_family_tree = []()
|
||||||
|
{
|
||||||
|
chip_family_table table;
|
||||||
|
table.default_ = chip_class::NV_generic;
|
||||||
|
|
||||||
|
// NV cards. See https://envytools.readthedocs.io/en/latest/hw/pciid.html
|
||||||
|
// NOTE: Since NV device IDs are linearly incremented per generation, there is no need to carefully check all the ranges
|
||||||
|
table.add(0x1180, 0x11fa, chip_class::NV_kepler); // GK104, 106
|
||||||
|
table.add(0x0FC0, 0x0FFF, chip_class::NV_kepler); // GK107
|
||||||
|
table.add(0x1003, 0x1028, chip_class::NV_kepler); // GK110
|
||||||
|
table.add(0x1280, 0x12BA, chip_class::NV_kepler); // GK208
|
||||||
|
table.add(0x1381, 0x13B0, chip_class::NV_maxwell); // GM107
|
||||||
|
table.add(0x1340, 0x134D, chip_class::NV_maxwell); // GM108
|
||||||
|
table.add(0x13C0, 0x13D9, chip_class::NV_maxwell); // GM204
|
||||||
|
table.add(0x1401, 0x1427, chip_class::NV_maxwell); // GM206
|
||||||
|
table.add(0x15F7, 0x15F9, chip_class::NV_pascal); // GP100 (Tesla P100)
|
||||||
|
table.add(0x1B00, 0x1D80, chip_class::NV_pascal);
|
||||||
|
table.add(0x1D81, 0x1DBA, chip_class::NV_volta);
|
||||||
|
table.add(0x1E02, 0x1F54, chip_class::NV_turing); // TU102, TU104, TU106, TU106M, TU106GL (RTX 20 series)
|
||||||
|
table.add(0x1F82, 0x1FB9, chip_class::NV_turing); // TU117, TU117M, TU117GL
|
||||||
|
table.add(0x2182, 0x21D1, chip_class::NV_turing); // TU116, TU116M, TU116GL
|
||||||
|
table.add(0x20B0, 0x20BE, chip_class::NV_ampere); // GA100
|
||||||
|
table.add(0x2204, 0x25AF, chip_class::NV_ampere); // GA10x (RTX 30 series)
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}();
|
||||||
|
|
||||||
|
chip_class get_chip_family();
|
||||||
|
chip_class get_chip_family(u32 vendor_id, u32 device_id);
|
||||||
|
}
|
56
rpcs3/Emu/RSX/VK/helpers/fence.cpp
Normal file
56
rpcs3/Emu/RSX/VK/helpers/fence.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fence.h"
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
extern "C" void _mm_pause();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fence::fence(VkDevice dev)
|
||||||
|
{
|
||||||
|
owner = dev;
|
||||||
|
VkFenceCreateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
CHECK_RESULT(vkCreateFence(dev, &info, nullptr, &handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
fence::~fence()
|
||||||
|
{
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
vkDestroyFence(owner, handle, nullptr);
|
||||||
|
handle = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fence::reset()
|
||||||
|
{
|
||||||
|
vkResetFences(owner, 1, &handle);
|
||||||
|
flushed.release(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fence::signal_flushed()
|
||||||
|
{
|
||||||
|
flushed.release(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fence::wait_flush()
|
||||||
|
{
|
||||||
|
while (!flushed)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
_mm_pause();
|
||||||
|
#else
|
||||||
|
__builtin_ia32_pause();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fence::operator bool() const
|
||||||
|
{
|
||||||
|
return (handle != VK_NULL_HANDLE);
|
||||||
|
}
|
||||||
|
}
|
23
rpcs3/Emu/RSX/VK/helpers/fence.h
Normal file
23
rpcs3/Emu/RSX/VK/helpers/fence.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VulkanAPI.h"
|
||||||
|
#include "util/atomic.hpp"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
struct fence
|
||||||
|
{
|
||||||
|
atomic_t<bool> flushed = false;
|
||||||
|
VkFence handle = VK_NULL_HANDLE;
|
||||||
|
VkDevice owner = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
fence(VkDevice dev);
|
||||||
|
~fence();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void signal_flushed();
|
||||||
|
void wait_flush();
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
};
|
||||||
|
}
|
219
rpcs3/Emu/RSX/VK/helpers/graphics_pipeline_state.h
Normal file
219
rpcs3/Emu/RSX/VK/helpers/graphics_pipeline_state.h
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VulkanAPI.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
class graphics_pipeline_state
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo ia;
|
||||||
|
VkPipelineDepthStencilStateCreateInfo ds;
|
||||||
|
VkPipelineColorBlendAttachmentState att_state[4];
|
||||||
|
VkPipelineColorBlendStateCreateInfo cs;
|
||||||
|
VkPipelineRasterizationStateCreateInfo rs;
|
||||||
|
VkPipelineMultisampleStateCreateInfo ms;
|
||||||
|
|
||||||
|
struct extra_parameters
|
||||||
|
{
|
||||||
|
VkSampleMask msaa_sample_mask;
|
||||||
|
}
|
||||||
|
temp_storage;
|
||||||
|
|
||||||
|
graphics_pipeline_state()
|
||||||
|
{
|
||||||
|
// NOTE: Vk** structs have padding bytes
|
||||||
|
memset(this, 0, sizeof(graphics_pipeline_state));
|
||||||
|
|
||||||
|
ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
cs.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rs.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rs.cullMode = VK_CULL_MODE_NONE;
|
||||||
|
rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||||
|
rs.lineWidth = 1.f;
|
||||||
|
|
||||||
|
ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
temp_storage.msaa_sample_mask = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics_pipeline_state(const graphics_pipeline_state& other)
|
||||||
|
{
|
||||||
|
// NOTE: Vk** structs have padding bytes
|
||||||
|
memcpy(this, &other, sizeof(graphics_pipeline_state));
|
||||||
|
|
||||||
|
if (other.cs.pAttachments == other.att_state)
|
||||||
|
{
|
||||||
|
// Rebase pointer
|
||||||
|
cs.pAttachments = att_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~graphics_pipeline_state() = default;
|
||||||
|
|
||||||
|
graphics_pipeline_state& operator = (const graphics_pipeline_state& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
// NOTE: Vk** structs have padding bytes
|
||||||
|
memcpy(this, &other, sizeof(graphics_pipeline_state));
|
||||||
|
|
||||||
|
if (other.cs.pAttachments == other.att_state)
|
||||||
|
{
|
||||||
|
// Rebase pointer
|
||||||
|
cs.pAttachments = att_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_primitive_type(VkPrimitiveTopology type)
|
||||||
|
{
|
||||||
|
ia.topology = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_primitive_restart(bool enable = true)
|
||||||
|
{
|
||||||
|
ia.primitiveRestartEnable = enable? VK_TRUE : VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_color_mask(int index, bool r, bool g, bool b, bool a)
|
||||||
|
{
|
||||||
|
VkColorComponentFlags mask = 0;
|
||||||
|
if (a) mask |= VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
if (b) mask |= VK_COLOR_COMPONENT_B_BIT;
|
||||||
|
if (g) mask |= VK_COLOR_COMPONENT_G_BIT;
|
||||||
|
if (r) mask |= VK_COLOR_COMPONENT_R_BIT;
|
||||||
|
|
||||||
|
att_state[index].colorWriteMask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_depth_mask(bool enable)
|
||||||
|
{
|
||||||
|
ds.depthWriteEnable = enable ? VK_TRUE : VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_stencil_mask(u32 mask)
|
||||||
|
{
|
||||||
|
ds.front.writeMask = mask;
|
||||||
|
ds.back.writeMask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_stencil_mask_separate(int face, u32 mask)
|
||||||
|
{
|
||||||
|
if (!face)
|
||||||
|
ds.front.writeMask = mask;
|
||||||
|
else
|
||||||
|
ds.back.writeMask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_depth_test(VkCompareOp op)
|
||||||
|
{
|
||||||
|
ds.depthTestEnable = VK_TRUE;
|
||||||
|
ds.depthCompareOp = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_depth_clamp(bool enable = true)
|
||||||
|
{
|
||||||
|
rs.depthClampEnable = enable ? VK_TRUE : VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_depth_bias(bool enable = true)
|
||||||
|
{
|
||||||
|
rs.depthBiasEnable = enable ? VK_TRUE : VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_depth_bounds_test(bool enable = true)
|
||||||
|
{
|
||||||
|
ds.depthBoundsTestEnable = enable? VK_TRUE : VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_blend(int mrt_index, VkBlendFactor src_factor_rgb, VkBlendFactor src_factor_a,
|
||||||
|
VkBlendFactor dst_factor_rgb, VkBlendFactor dst_factor_a,
|
||||||
|
VkBlendOp equation_rgb, VkBlendOp equation_a)
|
||||||
|
{
|
||||||
|
att_state[mrt_index].srcColorBlendFactor = src_factor_rgb;
|
||||||
|
att_state[mrt_index].srcAlphaBlendFactor = src_factor_a;
|
||||||
|
att_state[mrt_index].dstColorBlendFactor = dst_factor_rgb;
|
||||||
|
att_state[mrt_index].dstAlphaBlendFactor = dst_factor_a;
|
||||||
|
att_state[mrt_index].colorBlendOp = equation_rgb;
|
||||||
|
att_state[mrt_index].alphaBlendOp = equation_a;
|
||||||
|
att_state[mrt_index].blendEnable = VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_stencil_test(VkStencilOp fail, VkStencilOp zfail, VkStencilOp pass,
|
||||||
|
VkCompareOp func, u32 func_mask, u32 ref)
|
||||||
|
{
|
||||||
|
ds.front.failOp = fail;
|
||||||
|
ds.front.passOp = pass;
|
||||||
|
ds.front.depthFailOp = zfail;
|
||||||
|
ds.front.compareOp = func;
|
||||||
|
ds.front.compareMask = func_mask;
|
||||||
|
ds.front.reference = ref;
|
||||||
|
ds.back = ds.front;
|
||||||
|
|
||||||
|
ds.stencilTestEnable = VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_stencil_test_separate(int face, VkStencilOp fail, VkStencilOp zfail, VkStencilOp pass,
|
||||||
|
VkCompareOp func, u32 func_mask, u32 ref)
|
||||||
|
{
|
||||||
|
auto& face_props = (face ? ds.back : ds.front);
|
||||||
|
face_props.failOp = fail;
|
||||||
|
face_props.passOp = pass;
|
||||||
|
face_props.depthFailOp = zfail;
|
||||||
|
face_props.compareOp = func;
|
||||||
|
face_props.compareMask = func_mask;
|
||||||
|
face_props.reference = ref;
|
||||||
|
|
||||||
|
ds.stencilTestEnable = VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_logic_op(VkLogicOp op)
|
||||||
|
{
|
||||||
|
cs.logicOpEnable = VK_TRUE;
|
||||||
|
cs.logicOp = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_cull_face(VkCullModeFlags cull_mode)
|
||||||
|
{
|
||||||
|
rs.cullMode = cull_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_front_face(VkFrontFace face)
|
||||||
|
{
|
||||||
|
rs.frontFace = face;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_attachment_count(u32 count)
|
||||||
|
{
|
||||||
|
cs.attachmentCount = count;
|
||||||
|
cs.pAttachments = att_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_multisample_state(u8 sample_count, u32 sample_mask, bool msaa_enabled, bool alpha_to_coverage, bool alpha_to_one)
|
||||||
|
{
|
||||||
|
temp_storage.msaa_sample_mask = sample_mask;
|
||||||
|
|
||||||
|
ms.rasterizationSamples = static_cast<VkSampleCountFlagBits>(sample_count);
|
||||||
|
ms.alphaToCoverageEnable = alpha_to_coverage;
|
||||||
|
ms.alphaToOneEnable = alpha_to_one;
|
||||||
|
|
||||||
|
if (!msaa_enabled)
|
||||||
|
{
|
||||||
|
// This register is likely glMinSampleShading but in reverse; probably sets max sample shading rate of 1
|
||||||
|
// I (kd-11) suspect its what the control panel setting affects when MSAA is set to disabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_multisample_shading_rate(float shading_rate)
|
||||||
|
{
|
||||||
|
ms.sampleShadingEnable = VK_TRUE;
|
||||||
|
ms.minSampleShading = shading_rate;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
186
rpcs3/Emu/RSX/VK/helpers/mem_allocator.cpp
Normal file
186
rpcs3/Emu/RSX/VK/helpers/mem_allocator.cpp
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
#include "mem_allocator.h"
|
||||||
|
#include "util/logs.hpp"
|
||||||
|
#include "../VKHelpers.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
extern const render_device* g_current_renderer;
|
||||||
|
|
||||||
|
mem_allocator_vma::mem_allocator_vma(VkDevice dev, VkPhysicalDevice pdev) : mem_allocator_base(dev, pdev)
|
||||||
|
{
|
||||||
|
// Initialize stats pool
|
||||||
|
std::fill(stats.begin(), stats.end(), VmaBudget{});
|
||||||
|
|
||||||
|
VmaAllocatorCreateInfo allocatorInfo = {};
|
||||||
|
allocatorInfo.physicalDevice = pdev;
|
||||||
|
allocatorInfo.device = dev;
|
||||||
|
|
||||||
|
vmaCreateAllocator(&allocatorInfo, &m_allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_allocator_vma::destroy()
|
||||||
|
{
|
||||||
|
vmaDestroyAllocator(m_allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_allocator_vk::mem_handle_t mem_allocator_vma::alloc(u64 block_sz, u64 alignment, u32 memory_type_index)
|
||||||
|
{
|
||||||
|
VmaAllocation vma_alloc;
|
||||||
|
VkMemoryRequirements mem_req = {};
|
||||||
|
VmaAllocationCreateInfo create_info = {};
|
||||||
|
|
||||||
|
mem_req.memoryTypeBits = 1u << memory_type_index;
|
||||||
|
mem_req.size = block_sz;
|
||||||
|
mem_req.alignment = alignment;
|
||||||
|
create_info.memoryTypeBits = 1u << memory_type_index;
|
||||||
|
|
||||||
|
if (VkResult result = vmaAllocateMemory(m_allocator, &mem_req, &create_info, &vma_alloc, nullptr);
|
||||||
|
result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY &&
|
||||||
|
vmm_handle_memory_pressure(rsx::problem_severity::fatal))
|
||||||
|
{
|
||||||
|
// If we just ran out of VRAM, attempt to release resources and try again
|
||||||
|
result = vmaAllocateMemory(m_allocator, &mem_req, &create_info, &vma_alloc, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
die_with_error(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rsx_log.warning("Renderer ran out of video memory but successfully recovered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vmm_notify_memory_allocated(vma_alloc, memory_type_index, block_sz);
|
||||||
|
return vma_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_allocator_vma::free(mem_handle_t mem_handle)
|
||||||
|
{
|
||||||
|
vmm_notify_memory_freed(mem_handle);
|
||||||
|
vmaFreeMemory(m_allocator, static_cast<VmaAllocation>(mem_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mem_allocator_vma::map(mem_handle_t mem_handle, u64 offset, u64 /*size*/)
|
||||||
|
{
|
||||||
|
void *data = nullptr;
|
||||||
|
|
||||||
|
CHECK_RESULT(vmaMapMemory(m_allocator, static_cast<VmaAllocation>(mem_handle), &data));
|
||||||
|
|
||||||
|
// Add offset
|
||||||
|
data = static_cast<u8 *>(data) + offset;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_allocator_vma::unmap(mem_handle_t mem_handle)
|
||||||
|
{
|
||||||
|
vmaUnmapMemory(m_allocator, static_cast<VmaAllocation>(mem_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceMemory mem_allocator_vma::get_vk_device_memory(mem_handle_t mem_handle)
|
||||||
|
{
|
||||||
|
VmaAllocationInfo alloc_info;
|
||||||
|
|
||||||
|
vmaGetAllocationInfo(m_allocator, static_cast<VmaAllocation>(mem_handle), &alloc_info);
|
||||||
|
return alloc_info.deviceMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 mem_allocator_vma::get_vk_device_memory_offset(mem_handle_t mem_handle)
|
||||||
|
{
|
||||||
|
VmaAllocationInfo alloc_info;
|
||||||
|
|
||||||
|
vmaGetAllocationInfo(m_allocator, static_cast<VmaAllocation>(mem_handle), &alloc_info);
|
||||||
|
return alloc_info.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 mem_allocator_vma::get_memory_usage()
|
||||||
|
{
|
||||||
|
vmaGetBudget(m_allocator, stats.data());
|
||||||
|
|
||||||
|
float max_usage = 0.f;
|
||||||
|
for (const auto& info : stats)
|
||||||
|
{
|
||||||
|
if (!info.budget)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float this_usage = (info.usage * 100.f) / info.budget;
|
||||||
|
max_usage = std::max(max_usage, this_usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_allocator_vk::mem_handle_t mem_allocator_vk::alloc(u64 block_sz, u64 /*alignment*/, u32 memory_type_index)
|
||||||
|
{
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
VkMemoryAllocateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
info.allocationSize = block_sz;
|
||||||
|
info.memoryTypeIndex = memory_type_index;
|
||||||
|
|
||||||
|
if (VkResult result = vkAllocateMemory(m_device, &info, nullptr, &memory); result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
if (result == VK_ERROR_OUT_OF_DEVICE_MEMORY && vmm_handle_memory_pressure(rsx::problem_severity::fatal))
|
||||||
|
{
|
||||||
|
// If we just ran out of VRAM, attempt to release resources and try again
|
||||||
|
result = vkAllocateMemory(m_device, &info, nullptr, &memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
die_with_error(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rsx_log.warning("Renderer ran out of video memory but successfully recovered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vmm_notify_memory_allocated(memory, memory_type_index, block_sz);
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_allocator_vk::free(mem_handle_t mem_handle)
|
||||||
|
{
|
||||||
|
vmm_notify_memory_freed(mem_handle);
|
||||||
|
vkFreeMemory(m_device, static_cast<VkDeviceMemory>(mem_handle), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* mem_allocator_vk::map(mem_handle_t mem_handle, u64 offset, u64 size)
|
||||||
|
{
|
||||||
|
void* data = nullptr;
|
||||||
|
CHECK_RESULT(vkMapMemory(m_device, static_cast<VkDeviceMemory>(mem_handle), offset, std::max<u64>(size, 1u), 0, &data));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_allocator_vk::unmap(mem_handle_t mem_handle)
|
||||||
|
{
|
||||||
|
vkUnmapMemory(m_device, static_cast<VkDeviceMemory>(mem_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceMemory mem_allocator_vk::get_vk_device_memory(mem_handle_t mem_handle)
|
||||||
|
{
|
||||||
|
return static_cast<VkDeviceMemory>(mem_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 mem_allocator_vk::get_vk_device_memory_offset(mem_handle_t /*mem_handle*/)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 mem_allocator_vk::get_memory_usage()
|
||||||
|
{
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_allocator_base* get_current_mem_allocator()
|
||||||
|
{
|
||||||
|
ensure(g_current_renderer);
|
||||||
|
return g_current_renderer->get_allocator();
|
||||||
|
}
|
||||||
|
}
|
91
rpcs3/Emu/RSX/VK/helpers/mem_allocator.h
Normal file
91
rpcs3/Emu/RSX/VK/helpers/mem_allocator.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VulkanAPI.h"
|
||||||
|
#include "../../rsx_utils.h"
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
#include "3rdparty/GPUOpen/include/vk_mem_alloc.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
// Memory Allocator - base class
|
||||||
|
|
||||||
|
class mem_allocator_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using mem_handle_t = void *;
|
||||||
|
|
||||||
|
mem_allocator_base(VkDevice dev, VkPhysicalDevice /*pdev*/) : m_device(dev) {}
|
||||||
|
virtual ~mem_allocator_base() = default;
|
||||||
|
|
||||||
|
virtual void destroy() = 0;
|
||||||
|
|
||||||
|
virtual mem_handle_t alloc(u64 block_sz, u64 alignment, u32 memory_type_index) = 0;
|
||||||
|
virtual void free(mem_handle_t mem_handle) = 0;
|
||||||
|
virtual void *map(mem_handle_t mem_handle, u64 offset, u64 size) = 0;
|
||||||
|
virtual void unmap(mem_handle_t mem_handle) = 0;
|
||||||
|
virtual VkDeviceMemory get_vk_device_memory(mem_handle_t mem_handle) = 0;
|
||||||
|
virtual u64 get_vk_device_memory_offset(mem_handle_t mem_handle) = 0;
|
||||||
|
virtual f32 get_memory_usage() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
VkDevice m_device;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Memory Allocator - Vulkan Memory Allocator
|
||||||
|
// https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
|
||||||
|
|
||||||
|
class mem_allocator_vma : public mem_allocator_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
mem_allocator_vma(VkDevice dev, VkPhysicalDevice pdev);
|
||||||
|
~mem_allocator_vma() override = default;
|
||||||
|
|
||||||
|
void destroy() override;
|
||||||
|
|
||||||
|
mem_handle_t alloc(u64 block_sz, u64 alignment, u32 memory_type_index) override;
|
||||||
|
|
||||||
|
void free(mem_handle_t mem_handle) override;
|
||||||
|
void* map(mem_handle_t mem_handle, u64 offset, u64 /*size*/) override;
|
||||||
|
void unmap(mem_handle_t mem_handle) override;
|
||||||
|
|
||||||
|
VkDeviceMemory get_vk_device_memory(mem_handle_t mem_handle) override;
|
||||||
|
u64 get_vk_device_memory_offset(mem_handle_t mem_handle) override;
|
||||||
|
f32 get_memory_usage() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VmaAllocator m_allocator;
|
||||||
|
std::array<VmaBudget, VK_MAX_MEMORY_HEAPS> stats;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Memory Allocator - built-in Vulkan device memory allocate/free
|
||||||
|
|
||||||
|
class mem_allocator_vk : public mem_allocator_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
mem_allocator_vk(VkDevice dev, VkPhysicalDevice pdev) : mem_allocator_base(dev, pdev) {}
|
||||||
|
~mem_allocator_vk() override = default;
|
||||||
|
|
||||||
|
void destroy() override {}
|
||||||
|
|
||||||
|
mem_handle_t alloc(u64 block_sz, u64 /*alignment*/, u32 memory_type_index) override;
|
||||||
|
|
||||||
|
void free(mem_handle_t mem_handle) override;
|
||||||
|
void* map(mem_handle_t mem_handle, u64 offset, u64 size) override;
|
||||||
|
void unmap(mem_handle_t mem_handle) override;
|
||||||
|
|
||||||
|
VkDeviceMemory get_vk_device_memory(mem_handle_t mem_handle) override;
|
||||||
|
u64 get_vk_device_memory_offset(mem_handle_t /*mem_handle*/) override;
|
||||||
|
f32 get_memory_usage() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
void vmm_notify_memory_allocated(void* handle, u32 memory_type, u64 memory_size);
|
||||||
|
void vmm_notify_memory_freed(void* handle);
|
||||||
|
void vmm_reset();
|
||||||
|
void vmm_check_memory_usage();
|
||||||
|
bool vmm_handle_memory_pressure(rsx::problem_severity severity);
|
||||||
|
|
||||||
|
mem_allocator_base* get_current_mem_allocator();
|
||||||
|
}
|
36
rpcs3/Emu/RSX/VK/helpers/memory_block.cpp
Normal file
36
rpcs3/Emu/RSX/VK/helpers/memory_block.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include "memory_block.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
memory_block::memory_block(VkDevice dev, u64 block_sz, u64 alignment, u32 memory_type_index)
|
||||||
|
: m_device(dev)
|
||||||
|
{
|
||||||
|
m_mem_allocator = get_current_mem_allocator();
|
||||||
|
m_mem_handle = m_mem_allocator->alloc(block_sz, alignment, memory_type_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_block::~memory_block()
|
||||||
|
{
|
||||||
|
m_mem_allocator->free(m_mem_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceMemory memory_block::get_vk_device_memory()
|
||||||
|
{
|
||||||
|
return m_mem_allocator->get_vk_device_memory(m_mem_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 memory_block::get_vk_device_memory_offset()
|
||||||
|
{
|
||||||
|
return m_mem_allocator->get_vk_device_memory_offset(m_mem_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memory_block::map(u64 offset, u64 size)
|
||||||
|
{
|
||||||
|
return m_mem_allocator->map(m_mem_handle, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void memory_block::unmap()
|
||||||
|
{
|
||||||
|
m_mem_allocator->unmap(m_mem_handle);
|
||||||
|
}
|
||||||
|
}
|
27
rpcs3/Emu/RSX/VK/helpers/memory_block.h
Normal file
27
rpcs3/Emu/RSX/VK/helpers/memory_block.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VulkanAPI.h"
|
||||||
|
#include "mem_allocator.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
struct memory_block
|
||||||
|
{
|
||||||
|
memory_block(VkDevice dev, u64 block_sz, u64 alignment, u32 memory_type_index);
|
||||||
|
~memory_block();
|
||||||
|
|
||||||
|
VkDeviceMemory get_vk_device_memory();
|
||||||
|
u64 get_vk_device_memory_offset();
|
||||||
|
|
||||||
|
void* map(u64 offset, u64 size);
|
||||||
|
void unmap();
|
||||||
|
|
||||||
|
memory_block(const memory_block&) = delete;
|
||||||
|
memory_block(memory_block&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDevice m_device;
|
||||||
|
vk::mem_allocator_base* m_mem_allocator;
|
||||||
|
mem_allocator_base::mem_handle_t m_mem_handle;
|
||||||
|
};
|
||||||
|
}
|
320
rpcs3/Emu/RSX/VK/helpers/physical_device.cpp
Normal file
320
rpcs3/Emu/RSX/VK/helpers/physical_device.cpp
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
#include "physical_device.h"
|
||||||
|
#include "supported_extensions.h"
|
||||||
|
#include "util/logs.hpp"
|
||||||
|
#include "Emu/system_config.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
void physical_device::get_physical_device_features(bool allow_extensions)
|
||||||
|
{
|
||||||
|
if (!allow_extensions)
|
||||||
|
{
|
||||||
|
vkGetPhysicalDeviceFeatures(dev, &features);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
supported_extensions instance_extensions(supported_extensions::instance);
|
||||||
|
supported_extensions device_extensions(supported_extensions::device, nullptr, dev);
|
||||||
|
|
||||||
|
if (!instance_extensions.is_supported(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
vkGetPhysicalDeviceFeatures(dev, &features);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VkPhysicalDeviceFeatures2KHR features2;
|
||||||
|
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||||
|
features2.pNext = nullptr;
|
||||||
|
|
||||||
|
VkPhysicalDeviceFloat16Int8FeaturesKHR shader_support_info{};
|
||||||
|
|
||||||
|
if (device_extensions.is_supported(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
shader_support_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR;
|
||||||
|
features2.pNext = &shader_support_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device_extensions.is_supported(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME))
|
||||||
|
{
|
||||||
|
driver_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
|
||||||
|
driver_properties.pNext = features2.pNext;
|
||||||
|
features2.pNext = &driver_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto getPhysicalDeviceFeatures2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(vkGetInstanceProcAddr(parent, "vkGetPhysicalDeviceFeatures2KHR"));
|
||||||
|
ensure(getPhysicalDeviceFeatures2KHR); // "vkGetInstanceProcAddress failed to find entry point!"
|
||||||
|
getPhysicalDeviceFeatures2KHR(dev, &features2);
|
||||||
|
|
||||||
|
shader_types_support.allow_float64 = !!features2.features.shaderFloat64;
|
||||||
|
shader_types_support.allow_float16 = !!shader_support_info.shaderFloat16;
|
||||||
|
shader_types_support.allow_int8 = !!shader_support_info.shaderInt8;
|
||||||
|
features = features2.features;
|
||||||
|
}
|
||||||
|
|
||||||
|
stencil_export_support = device_extensions.is_supported(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME);
|
||||||
|
conditional_render_support = device_extensions.is_supported(VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME);
|
||||||
|
unrestricted_depth_range_support = device_extensions.is_supported(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void physical_device::create(VkInstance context, VkPhysicalDevice pdev, bool allow_extensions)
|
||||||
|
{
|
||||||
|
dev = pdev;
|
||||||
|
parent = context;
|
||||||
|
vkGetPhysicalDeviceProperties(pdev, &props);
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(pdev, &memory_properties);
|
||||||
|
get_physical_device_features(allow_extensions);
|
||||||
|
|
||||||
|
rsx_log.always("Found vulkan-compatible GPU: '%s' running on driver %s", get_name(), get_driver_version());
|
||||||
|
|
||||||
|
if (get_driver_vendor() == driver_vendor::RADV && get_name().find("LLVM 8.0.0") != umax)
|
||||||
|
{
|
||||||
|
// Serious driver bug causing black screens
|
||||||
|
// See https://bugs.freedesktop.org/show_bug.cgi?id=110970
|
||||||
|
rsx_log.fatal("RADV drivers have a major driver bug with LLVM 8.0.0 resulting in no visual output. Upgrade to LLVM version 8.0.1 or greater to avoid this issue.");
|
||||||
|
}
|
||||||
|
else if (get_driver_vendor() == driver_vendor::NVIDIA)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
// SPIRV bugs were fixed in 452.28 for windows
|
||||||
|
const u32 threshold_version = (452u >> 22) | (28 >> 14);
|
||||||
|
#else
|
||||||
|
// SPIRV bugs were fixed in 450.56 for linux/BSD
|
||||||
|
const u32 threshold_version = (450u >> 22) | (56 >> 14);
|
||||||
|
#endif
|
||||||
|
const auto current_version = props.driverVersion & ~0x3fffu; // Clear patch and revision fields
|
||||||
|
if (current_version < threshold_version)
|
||||||
|
{
|
||||||
|
rsx_log.error("Your current NVIDIA graphics driver version %s has known issues and is unsupported. Update to the latest NVIDIA driver.", get_driver_version());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_chip_class() == chip_class::AMD_vega)
|
||||||
|
{
|
||||||
|
// Disable fp16 if driver uses LLVM emitter. It does fine with AMD proprietary drivers though.
|
||||||
|
shader_types_support.allow_float16 = (driver_properties.driverID == VK_DRIVER_ID_AMD_PROPRIETARY_KHR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string physical_device::get_name() const
|
||||||
|
{
|
||||||
|
return props.deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
driver_vendor physical_device::get_driver_vendor() const
|
||||||
|
{
|
||||||
|
if (!driver_properties.driverID)
|
||||||
|
{
|
||||||
|
const auto gpu_name = get_name();
|
||||||
|
if (gpu_name.find("Radeon") != umax)
|
||||||
|
{
|
||||||
|
return driver_vendor::AMD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpu_name.find("NVIDIA") != umax || gpu_name.find("GeForce") != umax || gpu_name.find("Quadro") != umax)
|
||||||
|
{
|
||||||
|
return driver_vendor::NVIDIA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpu_name.find("RADV") != umax)
|
||||||
|
{
|
||||||
|
return driver_vendor::RADV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpu_name.find("Intel") != umax)
|
||||||
|
{
|
||||||
|
return driver_vendor::INTEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return driver_vendor::unknown;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (driver_properties.driverID)
|
||||||
|
{
|
||||||
|
case VK_DRIVER_ID_AMD_PROPRIETARY_KHR:
|
||||||
|
case VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR:
|
||||||
|
return driver_vendor::AMD;
|
||||||
|
case VK_DRIVER_ID_MESA_RADV_KHR:
|
||||||
|
return driver_vendor::RADV;
|
||||||
|
case VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR:
|
||||||
|
return driver_vendor::NVIDIA;
|
||||||
|
case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR:
|
||||||
|
case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR:
|
||||||
|
return driver_vendor::INTEL;
|
||||||
|
default:
|
||||||
|
// Mobile
|
||||||
|
return driver_vendor::unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string physical_device::get_driver_version() const
|
||||||
|
{
|
||||||
|
switch (get_driver_vendor())
|
||||||
|
{
|
||||||
|
case driver_vendor::NVIDIA:
|
||||||
|
{
|
||||||
|
// 10 + 8 + 8 + 6
|
||||||
|
const auto major_version = props.driverVersion >> 22;
|
||||||
|
const auto minor_version = (props.driverVersion >> 14) & 0xff;
|
||||||
|
const auto patch = (props.driverVersion >> 6) & 0xff;
|
||||||
|
const auto revision = (props.driverVersion & 0x3f);
|
||||||
|
|
||||||
|
return fmt::format("%u.%u.%u.%u", major_version, minor_version, patch, revision);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// 10 + 10 + 12 (standard vulkan encoding created with VK_MAKE_VERSION)
|
||||||
|
return fmt::format("%u.%u.%u", (props.driverVersion >> 22), (props.driverVersion >> 12) & 0x3ff, (props.driverVersion) & 0x3ff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chip_class physical_device::get_chip_class() const
|
||||||
|
{
|
||||||
|
return get_chip_family(props.vendorID, props.deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 physical_device::get_queue_count() const
|
||||||
|
{
|
||||||
|
if (!queue_props.empty())
|
||||||
|
return ::size32(queue_props);
|
||||||
|
|
||||||
|
u32 count = 0;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, nullptr);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkQueueFamilyProperties physical_device::get_queue_properties(u32 queue)
|
||||||
|
{
|
||||||
|
if (queue_props.empty())
|
||||||
|
{
|
||||||
|
u32 count = 0;
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, nullptr);
|
||||||
|
|
||||||
|
queue_props.resize(count);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, queue_props.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue >= queue_props.size())
|
||||||
|
fmt::throw_exception("Bad queue index passed to get_queue_properties (%u)", queue);
|
||||||
|
return queue_props[queue];
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPhysicalDeviceMemoryProperties physical_device::get_memory_properties() const
|
||||||
|
{
|
||||||
|
return memory_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPhysicalDeviceLimits physical_device::get_limits() const
|
||||||
|
{
|
||||||
|
return props.limits;
|
||||||
|
}
|
||||||
|
|
||||||
|
physical_device::operator VkPhysicalDevice() const
|
||||||
|
{
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
physical_device::operator VkInstance() const
|
||||||
|
{
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_type_mapping get_memory_mapping(const vk::physical_device& dev)
|
||||||
|
{
|
||||||
|
VkPhysicalDevice pdev = dev;
|
||||||
|
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(pdev, &memory_properties);
|
||||||
|
|
||||||
|
memory_type_mapping result;
|
||||||
|
result.device_local = VK_MAX_MEMORY_TYPES;
|
||||||
|
result.host_visible_coherent = VK_MAX_MEMORY_TYPES;
|
||||||
|
|
||||||
|
bool host_visible_cached = false;
|
||||||
|
VkDeviceSize host_visible_vram_size = 0;
|
||||||
|
VkDeviceSize device_local_vram_size = 0;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < memory_properties.memoryTypeCount; i++)
|
||||||
|
{
|
||||||
|
VkMemoryHeap& heap = memory_properties.memoryHeaps[memory_properties.memoryTypes[i].heapIndex];
|
||||||
|
|
||||||
|
bool is_device_local = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
if (is_device_local)
|
||||||
|
{
|
||||||
|
if (device_local_vram_size < heap.size)
|
||||||
|
{
|
||||||
|
result.device_local = i;
|
||||||
|
device_local_vram_size = heap.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_host_visible = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||||
|
bool is_host_coherent = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
|
bool is_cached = !!(memory_properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
|
||||||
|
|
||||||
|
if (is_host_coherent && is_host_visible)
|
||||||
|
{
|
||||||
|
if ((is_cached && !host_visible_cached) || (host_visible_vram_size < heap.size))
|
||||||
|
{
|
||||||
|
result.host_visible_coherent = i;
|
||||||
|
host_visible_vram_size = heap.size;
|
||||||
|
host_visible_cached = is_cached;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.device_local == VK_MAX_MEMORY_TYPES)
|
||||||
|
fmt::throw_exception("GPU doesn't support device local memory");
|
||||||
|
if (result.host_visible_coherent == VK_MAX_MEMORY_TYPES)
|
||||||
|
fmt::throw_exception("GPU doesn't support host coherent device local memory");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu_formats_support get_optimal_tiling_supported_formats(const physical_device& dev)
|
||||||
|
{
|
||||||
|
gpu_formats_support result = {};
|
||||||
|
|
||||||
|
VkFormatProperties props;
|
||||||
|
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_D24_UNORM_S8_UINT, &props);
|
||||||
|
|
||||||
|
result.d24_unorm_s8 = !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
|
||||||
|
!!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) && !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
|
||||||
|
|
||||||
|
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_D32_SFLOAT_S8_UINT, &props);
|
||||||
|
result.d32_sfloat_s8 = !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && !!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
|
||||||
|
!!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
|
||||||
|
|
||||||
|
// Hide d24_s8 if force high precision z buffer is enabled
|
||||||
|
if (g_cfg.video.force_high_precision_z_buffer && result.d32_sfloat_s8)
|
||||||
|
result.d24_unorm_s8 = false;
|
||||||
|
|
||||||
|
// Checks if BGRA8 images can be used for blitting
|
||||||
|
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_B8G8R8A8_UNORM, &props);
|
||||||
|
result.bgra8_linear = !!(props.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
|
||||||
|
|
||||||
|
// Check if device supports RGBA8 format
|
||||||
|
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_R8G8B8A8_UNORM, &props);
|
||||||
|
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) || !(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ||
|
||||||
|
!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT))
|
||||||
|
{
|
||||||
|
// Non-fatal. Most games use BGRA layout due to legacy reasons as old GPUs typically supported BGRA and RGBA was emulated.
|
||||||
|
rsx_log.error("Your GPU and/or driver does not support RGBA8 format. This can cause problems in some rare games that use this memory layout.");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.argb8_linear = !!(props.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline_binding_table get_pipeline_binding_table(const vk::physical_device& dev)
|
||||||
|
{
|
||||||
|
pipeline_binding_table result{};
|
||||||
|
|
||||||
|
// Need to check how many samplers are supported by the driver
|
||||||
|
const auto usable_samplers = std::min(dev.get_limits().maxPerStageDescriptorSampledImages, 32u);
|
||||||
|
result.vertex_textures_first_bind_slot = result.textures_first_bind_slot + usable_samplers;
|
||||||
|
result.total_descriptor_bindings = result.vertex_textures_first_bind_slot + 4;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
80
rpcs3/Emu/RSX/VK/helpers/physical_device.h
Normal file
80
rpcs3/Emu/RSX/VK/helpers/physical_device.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VulkanAPI.h"
|
||||||
|
#include "chip_class.h"
|
||||||
|
#include "pipeline_binding_table.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
struct gpu_formats_support
|
||||||
|
{
|
||||||
|
bool d24_unorm_s8;
|
||||||
|
bool d32_sfloat_s8;
|
||||||
|
bool bgra8_linear;
|
||||||
|
bool argb8_linear;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gpu_shader_types_support
|
||||||
|
{
|
||||||
|
bool allow_float64;
|
||||||
|
bool allow_float16;
|
||||||
|
bool allow_int8;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct memory_type_mapping
|
||||||
|
{
|
||||||
|
u32 host_visible_coherent;
|
||||||
|
u32 device_local;
|
||||||
|
};
|
||||||
|
|
||||||
|
class physical_device
|
||||||
|
{
|
||||||
|
VkInstance parent = VK_NULL_HANDLE;
|
||||||
|
VkPhysicalDevice dev = VK_NULL_HANDLE;
|
||||||
|
VkPhysicalDeviceProperties props;
|
||||||
|
VkPhysicalDeviceFeatures features;
|
||||||
|
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||||
|
std::vector<VkQueueFamilyProperties> queue_props;
|
||||||
|
|
||||||
|
std::unordered_map<VkFormat, VkFormatProperties> format_properties;
|
||||||
|
gpu_shader_types_support shader_types_support{};
|
||||||
|
VkPhysicalDeviceDriverPropertiesKHR driver_properties{};
|
||||||
|
|
||||||
|
bool stencil_export_support = false;
|
||||||
|
bool conditional_render_support = false;
|
||||||
|
bool unrestricted_depth_range_support = false;
|
||||||
|
|
||||||
|
friend class render_device;
|
||||||
|
private:
|
||||||
|
void get_physical_device_features(bool allow_extensions);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
physical_device() = default;
|
||||||
|
~physical_device() = default;
|
||||||
|
|
||||||
|
void create(VkInstance context, VkPhysicalDevice pdev, bool allow_extensions);
|
||||||
|
|
||||||
|
std::string get_name() const;
|
||||||
|
|
||||||
|
driver_vendor get_driver_vendor() const;
|
||||||
|
std::string get_driver_version() const;
|
||||||
|
chip_class get_chip_class() const;
|
||||||
|
|
||||||
|
u32 get_queue_count() const;
|
||||||
|
|
||||||
|
VkQueueFamilyProperties get_queue_properties(u32 queue);
|
||||||
|
VkPhysicalDeviceMemoryProperties get_memory_properties() const;
|
||||||
|
VkPhysicalDeviceLimits get_limits() const;
|
||||||
|
|
||||||
|
operator VkPhysicalDevice() const;
|
||||||
|
operator VkInstance() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
memory_type_mapping get_memory_mapping(const physical_device& dev);
|
||||||
|
gpu_formats_support get_optimal_tiling_supported_formats(const physical_device& dev);
|
||||||
|
pipeline_binding_table get_pipeline_binding_table(const physical_device& dev);
|
||||||
|
}
|
21
rpcs3/Emu/RSX/VK/helpers/pipeline_binding_table.h
Normal file
21
rpcs3/Emu/RSX/VK/helpers/pipeline_binding_table.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/types.hpp"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
struct pipeline_binding_table
|
||||||
|
{
|
||||||
|
u8 vertex_params_bind_slot = 0;
|
||||||
|
u8 vertex_constant_buffers_bind_slot = 1;
|
||||||
|
u8 fragment_constant_buffers_bind_slot = 2;
|
||||||
|
u8 fragment_state_bind_slot = 3;
|
||||||
|
u8 fragment_texture_params_bind_slot = 4;
|
||||||
|
u8 vertex_buffers_first_bind_slot = 5;
|
||||||
|
u8 conditional_render_predicate_slot = 8;
|
||||||
|
u8 rasterizer_env_bind_slot = 9;
|
||||||
|
u8 textures_first_bind_slot = 10;
|
||||||
|
u8 vertex_textures_first_bind_slot = 10; // Invalid, has to be initialized properly
|
||||||
|
u8 total_descriptor_bindings = vertex_textures_first_bind_slot; // Invalid, has to be initialized properly
|
||||||
|
};
|
||||||
|
}
|
38
rpcs3/Emu/RSX/VK/helpers/query_pool.h
Normal file
38
rpcs3/Emu/RSX/VK/helpers/query_pool.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VulkanAPI.h"
|
||||||
|
#include "../../rsx_utils.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
class query_pool : public rsx::ref_counted
|
||||||
|
{
|
||||||
|
VkQueryPool m_query_pool;
|
||||||
|
VkDevice m_device;
|
||||||
|
|
||||||
|
public:
|
||||||
|
query_pool(VkDevice dev, VkQueryType type, u32 size)
|
||||||
|
: m_query_pool(VK_NULL_HANDLE)
|
||||||
|
, m_device(dev)
|
||||||
|
{
|
||||||
|
VkQueryPoolCreateInfo info{};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
|
||||||
|
info.queryType = type;
|
||||||
|
info.queryCount = size;
|
||||||
|
vkCreateQueryPool(dev, &info, nullptr, &m_query_pool);
|
||||||
|
|
||||||
|
// Take 'size' references on this object
|
||||||
|
ref_count.release(static_cast<s32>(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
~query_pool()
|
||||||
|
{
|
||||||
|
vkDestroyQueryPool(m_device, m_query_pool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator VkQueryPool()
|
||||||
|
{
|
||||||
|
return m_query_pool;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
52
rpcs3/Emu/RSX/VK/helpers/sampler.cpp
Normal file
52
rpcs3/Emu/RSX/VK/helpers/sampler.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include "sampler.h"
|
||||||
|
#include "../../rsx_utils.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
sampler::sampler(VkDevice dev, VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w,
|
||||||
|
VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod,
|
||||||
|
VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, VkBorderColor border_color,
|
||||||
|
VkBool32 depth_compare, VkCompareOp depth_compare_mode)
|
||||||
|
: m_device(dev)
|
||||||
|
{
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
info.addressModeU = clamp_u;
|
||||||
|
info.addressModeV = clamp_v;
|
||||||
|
info.addressModeW = clamp_w;
|
||||||
|
info.anisotropyEnable = VK_TRUE;
|
||||||
|
info.compareEnable = depth_compare;
|
||||||
|
info.unnormalizedCoordinates = unnormalized_coordinates;
|
||||||
|
info.mipLodBias = mipLodBias;
|
||||||
|
info.maxAnisotropy = max_anisotropy;
|
||||||
|
info.maxLod = max_lod;
|
||||||
|
info.minLod = min_lod;
|
||||||
|
info.magFilter = mag_filter;
|
||||||
|
info.minFilter = min_filter;
|
||||||
|
info.mipmapMode = mipmap_mode;
|
||||||
|
info.compareOp = depth_compare_mode;
|
||||||
|
info.borderColor = border_color;
|
||||||
|
|
||||||
|
CHECK_RESULT(vkCreateSampler(m_device, &info, nullptr, &value));
|
||||||
|
}
|
||||||
|
|
||||||
|
sampler::~sampler()
|
||||||
|
{
|
||||||
|
vkDestroySampler(m_device, value, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sampler::matches(VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w,
|
||||||
|
VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod,
|
||||||
|
VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, VkBorderColor border_color,
|
||||||
|
VkBool32 depth_compare, VkCompareOp depth_compare_mode)
|
||||||
|
{
|
||||||
|
if (info.magFilter != mag_filter || info.minFilter != min_filter || info.mipmapMode != mipmap_mode ||
|
||||||
|
info.addressModeU != clamp_u || info.addressModeV != clamp_v || info.addressModeW != clamp_w ||
|
||||||
|
info.compareEnable != depth_compare || info.unnormalizedCoordinates != unnormalized_coordinates ||
|
||||||
|
!rsx::fcmp(info.maxLod, max_lod) || !rsx::fcmp(info.mipLodBias, mipLodBias) || !rsx::fcmp(info.minLod, min_lod) ||
|
||||||
|
!rsx::fcmp(info.maxAnisotropy, max_anisotropy) ||
|
||||||
|
info.compareOp != depth_compare_mode || info.borderColor != border_color)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
29
rpcs3/Emu/RSX/VK/helpers/sampler.h
Normal file
29
rpcs3/Emu/RSX/VK/helpers/sampler.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
struct sampler
|
||||||
|
{
|
||||||
|
VkSampler value;
|
||||||
|
VkSamplerCreateInfo info = {};
|
||||||
|
|
||||||
|
sampler(VkDevice dev, VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w,
|
||||||
|
VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod,
|
||||||
|
VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, VkBorderColor border_color,
|
||||||
|
VkBool32 depth_compare = false, VkCompareOp depth_compare_mode = VK_COMPARE_OP_NEVER);
|
||||||
|
|
||||||
|
~sampler();
|
||||||
|
|
||||||
|
bool matches(VkSamplerAddressMode clamp_u, VkSamplerAddressMode clamp_v, VkSamplerAddressMode clamp_w,
|
||||||
|
VkBool32 unnormalized_coordinates, float mipLodBias, float max_anisotropy, float min_lod, float max_lod,
|
||||||
|
VkFilter min_filter, VkFilter mag_filter, VkSamplerMipmapMode mipmap_mode, VkBorderColor border_color,
|
||||||
|
VkBool32 depth_compare = false, VkCompareOp depth_compare_mode = VK_COMPARE_OP_NEVER);
|
||||||
|
|
||||||
|
sampler(const sampler&) = delete;
|
||||||
|
sampler(sampler&&) = delete;
|
||||||
|
private:
|
||||||
|
VkDevice m_device;
|
||||||
|
};
|
||||||
|
}
|
134
rpcs3/Emu/RSX/VK/helpers/shared.cpp
Normal file
134
rpcs3/Emu/RSX/VK/helpers/shared.cpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#include "shared.h"
|
||||||
|
#include "util/logs.hpp"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
void die_with_error(VkResult error_code,
|
||||||
|
const char* file,
|
||||||
|
const char* func,
|
||||||
|
u32 line,
|
||||||
|
u32 col)
|
||||||
|
{
|
||||||
|
std::string error_message;
|
||||||
|
int severity = 0; // 0 - die, 1 - warn, 2 - nothing
|
||||||
|
|
||||||
|
switch (error_code)
|
||||||
|
{
|
||||||
|
case VK_SUCCESS:
|
||||||
|
case VK_EVENT_SET:
|
||||||
|
case VK_EVENT_RESET:
|
||||||
|
case VK_INCOMPLETE:
|
||||||
|
return;
|
||||||
|
case VK_SUBOPTIMAL_KHR:
|
||||||
|
error_message = "Present surface is suboptimal (VK_SUBOPTIMAL_KHR)";
|
||||||
|
severity = 1;
|
||||||
|
break;
|
||||||
|
case VK_NOT_READY:
|
||||||
|
error_message = "Device or resource busy (VK_NOT_READY)";
|
||||||
|
break;
|
||||||
|
case VK_TIMEOUT:
|
||||||
|
error_message = "Timeout event (VK_TIMEOUT)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||||
|
error_message = "Out of host memory (system RAM) (VK_ERROR_OUT_OF_HOST_MEMORY)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
||||||
|
error_message = "Out of video memory (VRAM) (VK_ERROR_OUT_OF_DEVICE_MEMORY)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_INITIALIZATION_FAILED:
|
||||||
|
error_message = "Initialization failed (VK_ERROR_INITIALIZATION_FAILED)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_DEVICE_LOST:
|
||||||
|
error_message = "Device lost (Driver crashed with unspecified error or stopped responding and recovered) (VK_ERROR_DEVICE_LOST)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_MEMORY_MAP_FAILED:
|
||||||
|
error_message = "Memory map failed (VK_ERROR_MEMORY_MAP_FAILED)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_LAYER_NOT_PRESENT:
|
||||||
|
error_message = "Requested layer is not available (Try disabling debug output or install vulkan SDK) (VK_ERROR_LAYER_NOT_PRESENT)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||||
|
error_message = "Requested extension not available (VK_ERROR_EXTENSION_NOT_PRESENT)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_FEATURE_NOT_PRESENT:
|
||||||
|
error_message = "Requested feature not available (VK_ERROR_FEATURE_NOT_PRESENT)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
||||||
|
error_message = "Incompatible driver (VK_ERROR_INCOMPATIBLE_DRIVER)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_TOO_MANY_OBJECTS:
|
||||||
|
error_message = "Too many objects created (Out of handles) (VK_ERROR_TOO_MANY_OBJECTS)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_FORMAT_NOT_SUPPORTED:
|
||||||
|
error_message = "Format not supported (VK_ERROR_FORMAT_NOT_SUPPORTED)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_FRAGMENTED_POOL:
|
||||||
|
error_message = "Fragmented pool (VK_ERROR_FRAGMENTED_POOL)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_SURFACE_LOST_KHR:
|
||||||
|
error_message = "Surface lost (VK_ERROR_SURFACE_LOST)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
|
||||||
|
error_message = "Native window in use (VK_ERROR_NATIVE_WINDOW_IN_USE_KHR)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||||
|
error_message = "Present surface is out of date (VK_ERROR_OUT_OF_DATE_KHR)";
|
||||||
|
severity = 1;
|
||||||
|
break;
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
|
||||||
|
error_message = "Incompatible display (VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_VALIDATION_FAILED_EXT:
|
||||||
|
error_message = "Validation failed (VK_ERROR_INCOMPATIBLE_DISPLAY_KHR)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_INVALID_SHADER_NV:
|
||||||
|
error_message = "Invalid shader code (VK_ERROR_INVALID_SHADER_NV)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_OUT_OF_POOL_MEMORY_KHR:
|
||||||
|
error_message = "Out of pool memory (VK_ERROR_OUT_OF_POOL_MEMORY_KHR)";
|
||||||
|
break;
|
||||||
|
case VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR:
|
||||||
|
error_message = "Invalid external handle (VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR)";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_message = fmt::format("Unknown Code (%Xh, %d)%s", static_cast<s32>(error_code), static_cast<s32>(error_code), src_loc{line, col, file, func});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (severity)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case 0:
|
||||||
|
fmt::throw_exception("Assertion Failed! Vulkan API call failed with unrecoverable error: %s%s", error_message, src_loc{line, col, file, func});
|
||||||
|
case 1:
|
||||||
|
rsx_log.error("Vulkan API call has failed with an error but will continue: %s%s", error_message, src_loc{line, col, file, func});
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
|
||||||
|
u64 srcObject, usz location, s32 msgCode,
|
||||||
|
const char* pLayerPrefix, const char* pMsg, void* pUserData)
|
||||||
|
{
|
||||||
|
if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
|
||||||
|
{
|
||||||
|
if (strstr(pMsg, "IMAGE_VIEW_TYPE_1D"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rsx_log.error("ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
|
||||||
|
}
|
||||||
|
else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
|
||||||
|
{
|
||||||
|
rsx_log.warning("WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let the app crash..
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
18
rpcs3/Emu/RSX/VK/helpers/shared.h
Normal file
18
rpcs3/Emu/RSX/VK/helpers/shared.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VulkanAPI.h"
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
#define CHECK_RESULT(expr) { VkResult _res = (expr); if (_res != VK_SUCCESS) vk::die_with_error(_res); }
|
||||||
|
|
||||||
|
void die_with_error(VkResult error_code,
|
||||||
|
const char* file = __builtin_FILE(),
|
||||||
|
const char* func = __builtin_FUNCTION(),
|
||||||
|
u32 line = __builtin_LINE(),
|
||||||
|
u32 col = __builtin_COLUMN());
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
|
||||||
|
u64 srcObject, usz location, s32 msgCode,
|
||||||
|
const char *pLayerPrefix, const char *pMsg, void *pUserData);
|
||||||
|
}
|
52
rpcs3/Emu/RSX/VK/helpers/supported_extensions.h
Normal file
52
rpcs3/Emu/RSX/VK/helpers/supported_extensions.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../VulkanAPI.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace vk
|
||||||
|
{
|
||||||
|
class supported_extensions
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector<VkExtensionProperties> m_vk_exts;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum enumeration_class
|
||||||
|
{
|
||||||
|
instance = 0,
|
||||||
|
device = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
supported_extensions(enumeration_class _class, const char* layer_name = nullptr, VkPhysicalDevice pdev = VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
u32 count;
|
||||||
|
if (_class == enumeration_class::instance)
|
||||||
|
{
|
||||||
|
if (vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr) != VK_SUCCESS)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ensure(pdev);
|
||||||
|
if (vkEnumerateDeviceExtensionProperties(pdev, layer_name, &count, nullptr) != VK_SUCCESS)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vk_exts.resize(count);
|
||||||
|
if (_class == enumeration_class::instance)
|
||||||
|
{
|
||||||
|
vkEnumerateInstanceExtensionProperties(layer_name, &count, m_vk_exts.data());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vkEnumerateDeviceExtensionProperties(pdev, layer_name, &count, m_vk_exts.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_supported(const char* ext)
|
||||||
|
{
|
||||||
|
return std::any_of(m_vk_exts.cbegin(), m_vk_exts.cend(), [&](const VkExtensionProperties& p) { return std::strcmp(p.extensionName, ext) == 0; });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -19,6 +19,17 @@
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\chip_class.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\fence.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\graphics_pipeline_state.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\memory_block.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\mem_allocator.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\physical_device.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\pipeline_binding_table.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\query_pool.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\sampler.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\shared.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\supported_extensions.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKCommandStream.h" />
|
<ClInclude Include="Emu\RSX\VK\VKCommandStream.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKCommonDecompiler.h" />
|
<ClInclude Include="Emu\RSX\VK\VKCommonDecompiler.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKCompute.h" />
|
<ClInclude Include="Emu\RSX\VK\VKCompute.h" />
|
||||||
|
@ -31,6 +42,7 @@
|
||||||
<ClInclude Include="Emu\RSX\VK\VKOverlays.h" />
|
<ClInclude Include="Emu\RSX\VK\VKOverlays.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKPipelineCompiler.h" />
|
<ClInclude Include="Emu\RSX\VK\VKPipelineCompiler.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKProgramBuffer.h" />
|
<ClInclude Include="Emu\RSX\VK\VKProgramBuffer.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\VKProgramPipeline.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKQueryPool.h" />
|
<ClInclude Include="Emu\RSX\VK\VKQueryPool.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKRenderPass.h" />
|
<ClInclude Include="Emu\RSX\VK\VKRenderPass.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKRenderTargets.h" />
|
<ClInclude Include="Emu\RSX\VK\VKRenderTargets.h" />
|
||||||
|
@ -43,6 +55,13 @@
|
||||||
<ClInclude Include="Emu\RSX\VK\VulkanAPI.h" />
|
<ClInclude Include="Emu\RSX\VK\VulkanAPI.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\chip_class.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\fence.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\memory_block.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\mem_allocator.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\physical_device.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\sampler.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\shared.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\VK\VKCommandStream.cpp" />
|
<ClCompile Include="Emu\RSX\VK\VKCommandStream.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\VK\VKCommonDecompiler.cpp" />
|
<ClCompile Include="Emu\RSX\VK\VKCommonDecompiler.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\VK\VKDMA.cpp" />
|
<ClCompile Include="Emu\RSX\VK\VKDMA.cpp" />
|
||||||
|
|
|
@ -23,6 +23,27 @@
|
||||||
<ClCompile Include="Emu\RSX\VK\VKCommandStream.cpp" />
|
<ClCompile Include="Emu\RSX\VK\VKCommandStream.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\VK\VKQueryPool.cpp" />
|
<ClCompile Include="Emu\RSX\VK\VKQueryPool.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\VK\VKPipelineCompiler.cpp" />
|
<ClCompile Include="Emu\RSX\VK\VKPipelineCompiler.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\chip_class.cpp">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\fence.cpp">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\mem_allocator.cpp">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\memory_block.cpp">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\physical_device.cpp">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\sampler.cpp">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\RSX\VK\helpers\shared.cpp">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Emu\RSX\VK\VKCommonDecompiler.h" />
|
<ClInclude Include="Emu\RSX\VK\VKCommonDecompiler.h" />
|
||||||
|
@ -47,5 +68,44 @@
|
||||||
<ClInclude Include="Emu\RSX\VK\VKCommandStream.h" />
|
<ClInclude Include="Emu\RSX\VK\VKCommandStream.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKQueryPool.h" />
|
<ClInclude Include="Emu\RSX\VK\VKQueryPool.h" />
|
||||||
<ClInclude Include="Emu\RSX\VK\VKPipelineCompiler.h" />
|
<ClInclude Include="Emu\RSX\VK\VKPipelineCompiler.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\VKProgramPipeline.h" />
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\chip_class.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\fence.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\graphics_pipeline_state.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\mem_allocator.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\memory_block.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\physical_device.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\pipeline_binding_table.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\query_pool.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\sampler.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\shared.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\VK\helpers\supported_extensions.h">
|
||||||
|
<Filter>helpers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="helpers">
|
||||||
|
<UniqueIdentifier>{2c6cb5a5-ed99-44fe-a0b6-7ba1949c8b29}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Add table
Add a link
Reference in a new issue