Skip to content

Commit

Permalink
Merge pull request #19487 from hrydgard/msaa-fixes
Browse files Browse the repository at this point in the history
Vulkan loader: Make extension loading take into account that the instance and device API versions can be different
  • Loading branch information
hrydgard authored Sep 25, 2024
2 parents 0b34c3a + 8c8b34a commit ccb9689
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 83 deletions.
12 changes: 6 additions & 6 deletions Common/GPU/D3D11/thin3d_d3d11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ class D3D11DrawContext : public DrawContext {

std::string GetInfoString(InfoField info) const override {
switch (info) {
case APIVERSION: return "Direct3D 11";
case VENDORSTRING: return adapterDesc_;
case VENDOR: return "";
case DRIVER: return "-";
case SHADELANGVERSION:
case InfoField::APIVERSION: return "Direct3D 11";
case InfoField::VENDORSTRING: return adapterDesc_;
case InfoField::VENDOR: return "";
case InfoField::DRIVER: return "-";
case InfoField::SHADELANGVERSION:
switch (featureLevel_) {
case D3D_FEATURE_LEVEL_9_1: return "Feature Level 9.1"; break;
case D3D_FEATURE_LEVEL_9_2: return "Feature Level 9.2"; break;
Expand All @@ -159,7 +159,7 @@ class D3D11DrawContext : public DrawContext {
case D3D_FEATURE_LEVEL_12_1: return "Feature Level 12.1"; break;
}
return "Unknown feature level";
case APINAME: return "Direct3D 11";
case InfoField::APINAME: return "Direct3D 11";
default: return "?";
}
}
Expand Down
12 changes: 6 additions & 6 deletions Common/GPU/D3D9/thin3d_d3d9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,12 +592,12 @@ class D3D9Context : public DrawContext {

std::string GetInfoString(InfoField info) const override {
switch (info) {
case APIVERSION: return "DirectX 9.0";
case VENDORSTRING: return identifier_.Description;
case VENDOR: return "";
case DRIVER: return identifier_.Driver; // eh, sort of
case SHADELANGVERSION: return shadeLangVersion_;
case APINAME: return "Direct3D 9";
case InfoField::APIVERSION: return "DirectX 9.0";
case InfoField::VENDORSTRING: return identifier_.Description;
case InfoField::VENDOR: return "";
case InfoField::DRIVER: return identifier_.Driver; // eh, sort of
case InfoField::SHADELANGVERSION: return shadeLangVersion_;
case InfoField::APINAME: return "Direct3D 9";
default: return "?";
}
}
Expand Down
57 changes: 29 additions & 28 deletions Common/GPU/OpenGL/thin3d_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,34 +442,35 @@ class OpenGLContext : public DrawContext {
std::string GetInfoString(InfoField info) const override {
// TODO: Make these actually query the right information
switch (info) {
case APINAME:
if (gl_extensions.IsGLES) {
return "OpenGL ES";
} else {
return "OpenGL";
}
case VENDORSTRING: return renderManager_.GetGLString(GL_VENDOR);
case VENDOR:
switch (caps_.vendor) {
case GPUVendor::VENDOR_AMD: return "VENDOR_AMD";
case GPUVendor::VENDOR_IMGTEC: return "VENDOR_POWERVR";
case GPUVendor::VENDOR_NVIDIA: return "VENDOR_NVIDIA";
case GPUVendor::VENDOR_INTEL: return "VENDOR_INTEL";
case GPUVendor::VENDOR_QUALCOMM: return "VENDOR_ADRENO";
case GPUVendor::VENDOR_ARM: return "VENDOR_ARM";
case GPUVendor::VENDOR_BROADCOM: return "VENDOR_BROADCOM";
case GPUVendor::VENDOR_VIVANTE: return "VENDOR_VIVANTE";
case GPUVendor::VENDOR_APPLE: return "VENDOR_APPLE";
case GPUVendor::VENDOR_MESA: return "VENDOR_MESA";
case GPUVendor::VENDOR_UNKNOWN:
default:
return "VENDOR_UNKNOWN";
}
break;
case DRIVER: return renderManager_.GetGLString(GL_RENDERER);
case SHADELANGVERSION: return renderManager_.GetGLString(GL_SHADING_LANGUAGE_VERSION);
case APIVERSION: return renderManager_.GetGLString(GL_VERSION);
default: return "?";
case InfoField::APINAME:
if (gl_extensions.IsGLES) {
return "OpenGL ES";
} else {
return "OpenGL";
}
case InfoField::VENDORSTRING:
return renderManager_.GetGLString(GL_VENDOR);
case InfoField::VENDOR:
switch (caps_.vendor) {
case GPUVendor::VENDOR_AMD: return "VENDOR_AMD";
case GPUVendor::VENDOR_IMGTEC: return "VENDOR_POWERVR";
case GPUVendor::VENDOR_NVIDIA: return "VENDOR_NVIDIA";
case GPUVendor::VENDOR_INTEL: return "VENDOR_INTEL";
case GPUVendor::VENDOR_QUALCOMM: return "VENDOR_ADRENO";
case GPUVendor::VENDOR_ARM: return "VENDOR_ARM";
case GPUVendor::VENDOR_BROADCOM: return "VENDOR_BROADCOM";
case GPUVendor::VENDOR_VIVANTE: return "VENDOR_VIVANTE";
case GPUVendor::VENDOR_APPLE: return "VENDOR_APPLE";
case GPUVendor::VENDOR_MESA: return "VENDOR_MESA";
case GPUVendor::VENDOR_UNKNOWN:
default:
return "VENDOR_UNKNOWN";
}
break;
case InfoField::DRIVER: return renderManager_.GetGLString(GL_RENDERER);
case InfoField::SHADELANGVERSION: return renderManager_.GetGLString(GL_SHADING_LANGUAGE_VERSION);
case InfoField::APIVERSION: return renderManager_.GetGLString(GL_VERSION);
default: return "?";
}
}

Expand Down
32 changes: 21 additions & 11 deletions Common/GPU/Vulkan/VulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,13 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {

// Check which Vulkan version we should request.
// Our code is fine with any version from 1.0 to 1.2, we don't know about higher versions.
vulkanApiVersion_ = VK_API_VERSION_1_0;
vulkanInstanceApiVersion_ = VK_API_VERSION_1_0;
if (vkEnumerateInstanceVersion) {
vkEnumerateInstanceVersion(&vulkanApiVersion_);
vulkanApiVersion_ &= 0xFFFFF000; // Remove patch version.
vulkanApiVersion_ = std::min(VK_API_VERSION_1_3, vulkanApiVersion_);
vkEnumerateInstanceVersion(&vulkanInstanceApiVersion_);
vulkanInstanceApiVersion_ &= 0xFFFFF000; // Remove patch version.
vulkanInstanceApiVersion_ = std::min(VK_API_VERSION_1_3, vulkanInstanceApiVersion_);
std::string versionString = FormatAPIVersion(vulkanInstanceApiVersion_);
INFO_LOG(Log::G3D, "Detected Vulkan API version: %s", versionString.c_str());
}

instance_layer_names_.clear();
Expand Down Expand Up @@ -201,7 +203,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
app_info.pEngineName = info.app_name;
// Let's increment this when we make major engine/context changes.
app_info.engineVersion = 2;
app_info.apiVersion = vulkanApiVersion_;
app_info.apiVersion = vulkanInstanceApiVersion_;

VkInstanceCreateInfo inst_info{ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
inst_info.flags = 0;
Expand Down Expand Up @@ -240,7 +242,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
return res;
}

VulkanLoadInstanceFunctions(instance_, extensionsLookup_, vulkanApiVersion_);
VulkanLoadInstanceFunctions(instance_, extensionsLookup_, vulkanInstanceApiVersion_);
if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) {
WARN_LOG(Log::G3D, "CheckLayers for instance failed");
// init_error_ = "Failed to validate instance layers";
Expand Down Expand Up @@ -560,7 +562,7 @@ int VulkanContext::GetBestPhysicalDevice() {
}

bool VulkanContext::EnableDeviceExtension(const char *extension, uint32_t coreVersion) {
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
if (coreVersion != 0 && vulkanDeviceApiVersion_ >= coreVersion) {
return true;
}
for (auto &iter : device_extension_properties_) {
Expand All @@ -573,7 +575,7 @@ bool VulkanContext::EnableDeviceExtension(const char *extension, uint32_t coreVe
}

bool VulkanContext::EnableInstanceExtension(const char *extension, uint32_t coreVersion) {
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
if (coreVersion != 0 && vulkanInstanceApiVersion_ >= coreVersion) {
return true;
}
for (auto &iter : instance_extension_properties_) {
Expand All @@ -589,6 +591,8 @@ VkResult VulkanContext::CreateDevice(int physical_device) {
physical_device_ = physical_device;
INFO_LOG(Log::G3D, "Chose physical device %d: %s", physical_device, physicalDeviceProperties_[physical_device].properties.deviceName);

vulkanDeviceApiVersion_ = physicalDeviceProperties_[physical_device].properties.apiVersion;

GetDeviceLayerProperties();
if (!CheckLayers(device_layer_properties_, device_layer_names_)) {
WARN_LOG(Log::G3D, "CheckLayers for device %d failed", physical_device);
Expand Down Expand Up @@ -668,6 +672,7 @@ VkResult VulkanContext::CreateDevice(int physical_device) {
extensionsLookup_.KHR_maintenance1 = EnableDeviceExtension(VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_API_VERSION_1_1);
extensionsLookup_.KHR_maintenance2 = EnableDeviceExtension(VK_KHR_MAINTENANCE2_EXTENSION_NAME, VK_API_VERSION_1_1);
extensionsLookup_.KHR_maintenance3 = EnableDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME, VK_API_VERSION_1_1);
extensionsLookup_.KHR_maintenance4 = EnableDeviceExtension("VK_KHR_maintenance4", VK_API_VERSION_1_3);
extensionsLookup_.KHR_multiview = EnableDeviceExtension(VK_KHR_MULTIVIEW_EXTENSION_NAME, VK_API_VERSION_1_1);

if (EnableDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_API_VERSION_1_1)) {
Expand Down Expand Up @@ -796,17 +801,17 @@ VkResult VulkanContext::CreateDevice(int physical_device) {
VkResult res = vkCreateDevice(physical_devices_[physical_device_], &device_info, nullptr, &device_);
if (res != VK_SUCCESS) {
init_error_ = "Unable to create Vulkan device";
ERROR_LOG(Log::G3D, "Unable to create Vulkan device");
ERROR_LOG(Log::G3D, "%s", init_error_.c_str());
} else {
VulkanLoadDeviceFunctions(device_, extensionsLookup_, vulkanApiVersion_);
VulkanLoadDeviceFunctions(device_, extensionsLookup_, vulkanDeviceApiVersion_);
}
INFO_LOG(Log::G3D, "Vulkan Device created: %s", physicalDeviceProperties_[physical_device_].properties.deviceName);

// Since we successfully created a device (however we got here, might be interesting in debug), we force the choice to be visible in the menu.
VulkanSetAvailable(true);

VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.vulkanApiVersion = vulkanApiVersion_;
allocatorInfo.vulkanApiVersion = std::min(vulkanDeviceApiVersion_, vulkanInstanceApiVersion_);
allocatorInfo.physicalDevice = physical_devices_[physical_device_];
allocatorInfo.device = device_;
allocatorInfo.instance = instance_;
Expand Down Expand Up @@ -1863,6 +1868,7 @@ bool IsHashMaliDriverVersion(const VkPhysicalDeviceProperties &props) {
return true;
if (branch > 100 || major > 100)
return true;
// Can (in theory) have false negatives!
return false;
}

Expand Down Expand Up @@ -1893,6 +1899,10 @@ std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props) {
return StringFromFormat("%d.%d.%d (%08x)", major, minor, branch, props.driverVersion);
}

std::string FormatAPIVersion(u32 version) {
return StringFromFormat("%d.%d.%d", VK_API_VERSION_MAJOR(version), VK_API_VERSION_MINOR(version), VK_API_VERSION_PATCH(version));
}

// Mainly just the formats seen on gpuinfo.org for swapchains, as this function is only used for listing
// those in the UI. Also depth buffers that we used in one place.
// Might add more in the future if we find more uses for this.
Expand Down
13 changes: 12 additions & 1 deletion Common/GPU/Vulkan/VulkanContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ class VulkanContext {
// out of MAX_INFLIGHT_FRAMES.
return inflightFrames_;
}

// Don't call while a frame is in progress.
void UpdateInflightFrames(int n);

Expand Down Expand Up @@ -414,6 +415,14 @@ class VulkanContext {
return frame_[curFrame_].deleteList.GetLastDeleteCount();
}

u32 InstanceApiVersion() const {
return vulkanInstanceApiVersion_;
}

u32 DeviceApiVersion() const {
return vulkanDeviceApiVersion_;
}

private:
bool ChooseQueue();

Expand Down Expand Up @@ -441,7 +450,8 @@ class VulkanContext {
VkDevice device_ = VK_NULL_HANDLE;
VkQueue gfx_queue_ = VK_NULL_HANDLE;
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
u32 vulkanApiVersion_ = 0;
u32 vulkanInstanceApiVersion_ = 0;
u32 vulkanDeviceApiVersion_ = 0;

std::string init_error_;
std::vector<const char *> instance_layer_names_;
Expand Down Expand Up @@ -528,6 +538,7 @@ const char *VulkanPresentModeToString(VkPresentModeKHR presentMode);
const char *VulkanImageLayoutToString(VkImageLayout imageLayout);

std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props);
std::string FormatAPIVersion(u32 version);

// Simple heuristic.
bool IsHashMaliDriverVersion(const VkPhysicalDeviceProperties &props);
Expand Down
67 changes: 52 additions & 15 deletions Common/GPU/Vulkan/VulkanLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,18 +264,52 @@ static VulkanLibraryHandle vulkanLibrary;
bool g_vulkanAvailabilityChecked = false;
bool g_vulkanMayBeAvailable = false;

#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #x); if (!x) {INFO_LOG(Log::G3D, "Missing (instance): %s", #x);}
static PFN_vkVoidFunction LoadInstanceFunc(VkInstance instance, const char *name) {
PFN_vkVoidFunction funcPtr = vkGetInstanceProcAddr(instance, name);
if (!funcPtr) {
INFO_LOG(Log::G3D, "Missing function (instance): %s", name);
}
return funcPtr;
}
#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)LoadInstanceFunc(instance, #x);

static PFN_vkVoidFunction LoadInstanceFuncCore(VkInstance instance, const char *name, const char *extName, u32 min_core, u32 vulkanInstanceApiVersion) {
PFN_vkVoidFunction funcPtr = vkGetInstanceProcAddr(instance, vulkanInstanceApiVersion >= min_core ? name : extName);
if (vulkanInstanceApiVersion >= min_core && !funcPtr) {
// Try the ext name.
funcPtr = vkGetInstanceProcAddr(instance, extName);
}
if (!funcPtr) {
INFO_LOG(Log::G3D, "Missing (instance): %s (%s)", name, extName);
}
return funcPtr;
}
#define LOAD_INSTANCE_FUNC_CORE(instance, x, ext_x, min_core) \
x = (PFN_ ## x)vkGetInstanceProcAddr(instance, vulkanApiVersion >= min_core ? #x : #ext_x); \
if (vulkanApiVersion >= min_core && !x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #ext_x); \
if (!x) {INFO_LOG(Log::G3D, "Missing (instance): %s (%s)", #x, #ext_x);}
#define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {INFO_LOG(Log::G3D, "Missing (device): %s", #x);}
#define LOAD_DEVICE_FUNC_CORE(instance, x, ext_x, min_core) \
x = (PFN_ ## x)vkGetDeviceProcAddr(instance, vulkanApiVersion >= min_core ? #x : #ext_x); \
if (vulkanApiVersion >= min_core && !x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #ext_x); \
if (!x) {INFO_LOG(Log::G3D, "Missing (device): %s (%s)", #x, #ext_x);}
#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {INFO_LOG(Log::G3D,"Missing (global): %s", #x);}
x = (PFN_ ## x)LoadInstanceFuncCore(instance, #x, #ext_x, min_core, vulkanInstanceApiVersion);

static PFN_vkVoidFunction LoadDeviceFunc(VkDevice device, const char *name) {
PFN_vkVoidFunction funcPtr = vkGetDeviceProcAddr(device, name);
if (!funcPtr) {
INFO_LOG(Log::G3D, "Missing function (device): %s", name);
}
return funcPtr;
}
#define LOAD_DEVICE_FUNC(device, x) x = (PFN_ ## x)LoadDeviceFunc(device, #x);

static PFN_vkVoidFunction LoadDeviceFuncCore(VkDevice device, const char *name, const char *extName, u32 min_core, u32 vulkanDeviceApiVersion) {
PFN_vkVoidFunction funcPtr = vkGetDeviceProcAddr(device, vulkanDeviceApiVersion >= min_core ? name : extName);
if (vulkanDeviceApiVersion >= min_core && !funcPtr) {
funcPtr = vkGetDeviceProcAddr(device, extName);
}
if (!funcPtr) {
INFO_LOG(Log::G3D, "Missing (device): %s (%s)", name, extName);
}
return funcPtr;
}
#define LOAD_DEVICE_FUNC_CORE(device, x, ext_x, min_core) \
x = (PFN_ ## x)LoadDeviceFuncCore(device, #x, #ext_x, min_core, vulkanDeviceApiVersion);

#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {INFO_LOG(Log::G3D,"Missing (global): %s", #x);}
#define LOAD_GLOBAL_FUNC_LOCAL(lib, x) (PFN_ ## x)dlsym(lib, #x);

static const char * const device_name_blacklist[] = {
Expand Down Expand Up @@ -611,8 +645,9 @@ bool VulkanLoad(std::string *errorStr) {
#endif
}

void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion) {
void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions, uint32_t vulkanInstanceApiVersion) {
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
INFO_LOG(Log::G3D, "Loading Vulkan instance functions. Instance API version: %08x (%d.%d.%d)", vulkanInstanceApiVersion, VK_API_VERSION_MAJOR(vulkanInstanceApiVersion), VK_API_VERSION_MINOR(vulkanInstanceApiVersion), VK_API_VERSION_PATCH(vulkanInstanceApiVersion));
// OK, let's use the above functions to get the rest.
LOAD_INSTANCE_FUNC(instance, vkDestroyInstance);
LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices);
Expand Down Expand Up @@ -686,9 +721,9 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &en
// On some implementations, loading functions (that have Device as their first parameter) via vkGetDeviceProcAddr may
// increase performance - but then these function pointers will only work on that specific device. Thus, this loader is not very
// good for multi-device - not likely we'll ever try that anyway though.
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions, uint32_t vulkanApiVersion) {
void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions, uint32_t vulkanDeviceApiVersion) {
#if !PPSSPP_PLATFORM(IOS_APP_STORE)
INFO_LOG(Log::G3D, "Vulkan device functions loaded.");
INFO_LOG(Log::G3D, "Loading Vulkan device functions. Device API version: %08x (%d.%d.%d)", vulkanDeviceApiVersion, VK_API_VERSION_MAJOR(vulkanDeviceApiVersion), VK_API_VERSION_MINOR(vulkanDeviceApiVersion), VK_API_VERSION_PATCH(vulkanDeviceApiVersion));

LOAD_DEVICE_FUNC(device, vkQueueSubmit);
LOAD_DEVICE_FUNC(device, vkQueueWaitIdle);
Expand All @@ -705,10 +740,8 @@ void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledE
LOAD_DEVICE_FUNC(device, vkBindImageMemory2);
LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements);
LOAD_DEVICE_FUNC(device, vkGetBufferMemoryRequirements2);
LOAD_DEVICE_FUNC(device, vkGetDeviceBufferMemoryRequirements);
LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements);
LOAD_DEVICE_FUNC(device, vkGetImageMemoryRequirements2);
LOAD_DEVICE_FUNC(device, vkGetDeviceImageMemoryRequirements);
LOAD_DEVICE_FUNC(device, vkCreateFence);
LOAD_DEVICE_FUNC(device, vkDestroyFence);
LOAD_DEVICE_FUNC(device, vkResetFences);
Expand Down Expand Up @@ -826,6 +859,10 @@ void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledE
if (enabledExtensions.KHR_create_renderpass2) {
LOAD_DEVICE_FUNC_CORE(device, vkCreateRenderPass2, vkCreateRenderPass2KHR, VK_API_VERSION_1_2);
}
if (enabledExtensions.KHR_maintenance4) {
LOAD_DEVICE_FUNC_CORE(device, vkGetDeviceBufferMemoryRequirements, vkGetDeviceBufferMemoryRequirementsKHR, VK_API_VERSION_1_3);
LOAD_DEVICE_FUNC_CORE(device, vkGetDeviceImageMemoryRequirements, vkGetDeviceImageMemoryRequirementsKHR, VK_API_VERSION_1_3);
}
#endif
}

Expand Down
1 change: 1 addition & 0 deletions Common/GPU/Vulkan/VulkanLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ struct VulkanExtensions {
bool KHR_maintenance1; // required for KHR_create_renderpass2
bool KHR_maintenance2;
bool KHR_maintenance3;
bool KHR_maintenance4;
bool KHR_multiview; // required for KHR_create_renderpass2
bool KHR_get_memory_requirements2;
bool KHR_dedicated_allocation;
Expand Down
Loading

0 comments on commit ccb9689

Please sign in to comment.