mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-14 01:27:00 +00:00
VK: refactoring part 1
This commit is contained in:
parent
f8589de476
commit
d9eb31000d
@ -435,6 +435,13 @@ target_sources(rpcs3_emu PRIVATE
|
||||
|
||||
if(TARGET 3rdparty_vulkan)
|
||||
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/VKCommonDecompiler.cpp
|
||||
RSX/VK/VKDMA.cpp
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "util/types.hpp"
|
||||
#include "Utilities/address_range.h"
|
||||
#include "gcm_enums.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "stdafx.h"
|
||||
#include "VKCommandStream.h"
|
||||
#include "helpers/fence.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "Emu/RSX/RSXOffload.h"
|
||||
|
||||
namespace vk
|
||||
|
@ -1,9 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "VKHelpers.h"
|
||||
#include "VulkanAPI.h"
|
||||
|
||||
namespace vk
|
||||
{
|
||||
struct fence;
|
||||
|
||||
enum // callback commands
|
||||
{
|
||||
rctrl_queue_submit = 0x80000000
|
||||
};
|
||||
|
||||
struct submit_packet
|
||||
{
|
||||
// Core components
|
||||
|
@ -1,8 +1,16 @@
|
||||
#pragma once
|
||||
#include "VKHelpers.h"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class address_range;
|
||||
}
|
||||
|
||||
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);
|
||||
void load_dma(u32 local_address, u32 length);
|
||||
void flush_dma(u32 local_address, u32 length);
|
||||
|
@ -1,47 +1,9 @@
|
||||
#include "stdafx.h"
|
||||
#include "VKFormats.h"
|
||||
#include "VKHelpers.h"
|
||||
|
||||
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)
|
||||
{
|
||||
switch (format)
|
||||
|
@ -1,9 +1,13 @@
|
||||
#pragma once
|
||||
#include "VKHelpers.h"
|
||||
#include "VulkanAPI.h"
|
||||
#include "../gcm_enums.h"
|
||||
#include <tuple>
|
||||
|
||||
namespace vk
|
||||
{
|
||||
class image;
|
||||
struct gpu_formats_support;
|
||||
|
||||
struct minification_filter
|
||||
{
|
||||
VkFilter filter;
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include "../Common/GLSLTypes.h"
|
||||
#include "Emu/RSX/RSXFragmentProgram.h"
|
||||
#include "VulkanAPI.h"
|
||||
#include "VKHelpers.h"
|
||||
#include "VKProgramPipeline.h"
|
||||
#include "helpers/pipeline_binding_table.h"
|
||||
|
||||
namespace vk
|
||||
{
|
||||
|
@ -17,55 +17,7 @@
|
||||
|
||||
namespace vk
|
||||
{
|
||||
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;
|
||||
}();
|
||||
extern chip_class g_chip_class;
|
||||
|
||||
const context* g_current_vulkan_ctx = nullptr;
|
||||
const render_device* g_current_renderer;
|
||||
@ -87,7 +39,6 @@ namespace vk
|
||||
// Driver compatibility workarounds
|
||||
VkFlags g_heap_compatible_buffer_types = 0;
|
||||
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_sanitize_fp_values = false;
|
||||
bool g_drv_disable_fence_reset = false;
|
||||
@ -179,81 +130,6 @@ namespace vk
|
||||
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 callbacks;
|
||||
@ -469,12 +345,6 @@ namespace vk
|
||||
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)
|
||||
{
|
||||
g_current_vulkan_ctx = &ctx;
|
||||
@ -577,11 +447,6 @@ namespace vk
|
||||
return g_driver_vendor;
|
||||
}
|
||||
|
||||
chip_class get_chip_family()
|
||||
{
|
||||
return g_chip_class;
|
||||
}
|
||||
|
||||
bool emulate_primitive_restart(rsx::primitive_type type)
|
||||
{
|
||||
if (g_drv_no_primitive_restart)
|
||||
@ -1023,134 +888,6 @@ namespace vk
|
||||
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,
|
||||
u64 srcObject, usz location, s32 msgCode,
|
||||
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 "VKRenderPass.h"
|
||||
#include "VKPipelineCompiler.h"
|
||||
#include "helpers/sampler.h"
|
||||
|
||||
#include "../Overlays/overlays.h"
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "VKPipelineCompiler.h"
|
||||
#include "VKRenderPass.h"
|
||||
#include "VKHelpers.h"
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
#include <thread>
|
||||
|
@ -1,11 +1,14 @@
|
||||
#pragma once
|
||||
#include "VKHelpers.h"
|
||||
#include "../rsx_utils.h"
|
||||
#include "Utilities/hash.h"
|
||||
#include "Utilities/lockless.h"
|
||||
#include "VKProgramPipeline.h"
|
||||
#include "helpers/graphics_pipeline_state.h"
|
||||
|
||||
namespace vk
|
||||
{
|
||||
class render_device;
|
||||
|
||||
struct pipeline_props
|
||||
{
|
||||
graphics_pipeline_state state;
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "VKFragmentProgram.h"
|
||||
#include "../Common/ProgramStateCache.h"
|
||||
#include "Utilities/hash.h"
|
||||
#include "VKHelpers.h"
|
||||
#include "VKRenderPass.h"
|
||||
#include "VKPipelineCompiler.h"
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "VKProgramPipeline.h"
|
||||
#include "VKHelpers.h"
|
||||
|
||||
#include <string>
|
||||
@ -9,6 +10,66 @@ namespace vk
|
||||
{
|
||||
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()
|
||||
{
|
||||
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
|
||||
#include "VKHelpers.h"
|
||||
#include "VulkanAPI.h"
|
||||
#include <deque>
|
||||
|
||||
namespace vk
|
||||
{
|
||||
class command_buffer;
|
||||
class query_pool;
|
||||
class render_device;
|
||||
|
||||
class query_pool_manager
|
||||
{
|
||||
struct query_slot_info
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "Utilities/mutex.h"
|
||||
#include "VKRenderPass.h"
|
||||
#include "VKHelpers.h"
|
||||
|
||||
namespace vk
|
||||
{
|
||||
|
@ -1,9 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "VKHelpers.h"
|
||||
#include "VulkanAPI.h"
|
||||
#include "Utilities/geometry.h"
|
||||
|
||||
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 previous_key);
|
||||
u64 get_renderpass_key(VkFormat surface_format);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include "VKHelpers.h"
|
||||
#include "helpers/query_pool.h"
|
||||
#include "helpers/sampler.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <deque>
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "VKProgramBuffer.h"
|
||||
#include "VKHelpers.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace vk
|
||||
|
@ -3,7 +3,8 @@
|
||||
#include "Emu/RSX/RSXVertexProgram.h"
|
||||
#include "Utilities/Thread.h"
|
||||
#include "VulkanAPI.h"
|
||||
#include "../VK/VKHelpers.h"
|
||||
#include "VKProgramPipeline.h"
|
||||
#include "helpers/pipeline_binding_table.h"
|
||||
|
||||
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>
|
||||
</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\VKCommonDecompiler.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKCompute.h" />
|
||||
@ -31,6 +42,7 @@
|
||||
<ClInclude Include="Emu\RSX\VK\VKOverlays.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKPipelineCompiler.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\VKRenderPass.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKRenderTargets.h" />
|
||||
@ -43,6 +55,13 @@
|
||||
<ClInclude Include="Emu\RSX\VK\VulkanAPI.h" />
|
||||
</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\VKCommonDecompiler.cpp" />
|
||||
<ClCompile Include="Emu\RSX\VK\VKDMA.cpp" />
|
||||
|
@ -23,6 +23,27 @@
|
||||
<ClCompile Include="Emu\RSX\VK\VKCommandStream.cpp" />
|
||||
<ClCompile Include="Emu\RSX\VK\VKQueryPool.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>
|
||||
<ClInclude Include="Emu\RSX\VK\VKCommonDecompiler.h" />
|
||||
@ -47,5 +68,44 @@
|
||||
<ClInclude Include="Emu\RSX\VK\VKCommandStream.h" />
|
||||
<ClInclude Include="Emu\RSX\VK\VKQueryPool.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>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user