Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vulkan: Use VK_EXT_provoking_vertex, when available, to get OpenGL/PSP behavior for flat shading #19331

Merged
merged 3 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 71 additions & 56 deletions Common/GPU/Vulkan/VulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,33 @@ int VulkanContext::GetBestPhysicalDevice() {
return best;
}

void VulkanContext::ChooseDevice(int physical_device) {
bool VulkanContext::EnableDeviceExtension(const char *extension, uint32_t coreVersion) {
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
return true;
}
for (auto &iter : device_extension_properties_) {
if (!strcmp(iter.extensionName, extension)) {
device_extensions_enabled_.push_back(extension);
return true;
}
}
return false;
}

bool VulkanContext::EnableInstanceExtension(const char *extension, uint32_t coreVersion) {
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
return true;
}
for (auto &iter : instance_extension_properties_) {
if (!strcmp(iter.extensionName, extension)) {
instance_extensions_enabled_.push_back(extension);
return true;
}
}
return false;
}

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);

Expand Down Expand Up @@ -615,61 +641,10 @@ void VulkanContext::ChooseDevice(int physical_device) {
(memory_properties_.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "HOST_COHERENT " : "");
}

// Optional features
if (extensionsLookup_.KHR_get_physical_device_properties2 && vkGetPhysicalDeviceFeatures2) {
VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR};
// Add to chain even if not supported, GetPhysicalDeviceFeatures is supposed to ignore unknown structs.
VkPhysicalDeviceMultiviewFeatures multiViewFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES };
VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR };
VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR };

features2.pNext = &multiViewFeatures;
multiViewFeatures.pNext = &presentWaitFeatures;
presentWaitFeatures.pNext = &presentIdFeatures;
presentIdFeatures.pNext = nullptr;

vkGetPhysicalDeviceFeatures2(physical_devices_[physical_device_], &features2);
deviceFeatures_.available.standard = features2.features;
deviceFeatures_.available.multiview = multiViewFeatures;
deviceFeatures_.available.presentWait = presentWaitFeatures;
deviceFeatures_.available.presentId = presentIdFeatures;
} else {
vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard);
deviceFeatures_.available.multiview = {};
}

GetDeviceLayerExtensionList(nullptr, device_extension_properties_);

device_extensions_enabled_.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}

bool VulkanContext::EnableDeviceExtension(const char *extension, uint32_t coreVersion) {
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
return true;
}
for (auto &iter : device_extension_properties_) {
if (!strcmp(iter.extensionName, extension)) {
device_extensions_enabled_.push_back(extension);
return true;
}
}
return false;
}

bool VulkanContext::EnableInstanceExtension(const char *extension, uint32_t coreVersion) {
if (coreVersion != 0 && vulkanApiVersion_ >= coreVersion) {
return true;
}
for (auto &iter : instance_extension_properties_) {
if (!strcmp(iter.extensionName, extension)) {
instance_extensions_enabled_.push_back(extension);
return true;
}
}
return false;
}

VkResult VulkanContext::CreateDevice() {
if (!init_error_.empty() || physical_device_ < 0) {
ERROR_LOG(Log::G3D, "Vulkan init failed: %s", init_error_.c_str());
return VK_ERROR_INITIALIZATION_FAILED;
Expand Down Expand Up @@ -716,6 +691,37 @@ VkResult VulkanContext::CreateDevice() {
extensionsLookup_.KHR_present_wait = EnableDeviceExtension(VK_KHR_PRESENT_WAIT_EXTENSION_NAME, 0);
}

extensionsLookup_.EXT_provoking_vertex = EnableDeviceExtension(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, 0);

// Optional features
if (extensionsLookup_.KHR_get_physical_device_properties2 && vkGetPhysicalDeviceFeatures2) {
VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR };
// Add to chain even if not supported, GetPhysicalDeviceFeatures is supposed to ignore unknown structs.
VkPhysicalDeviceMultiviewFeatures multiViewFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES };
VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR };
VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR };
VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertexFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT };

features2.pNext = &multiViewFeatures;
multiViewFeatures.pNext = &presentWaitFeatures;
presentWaitFeatures.pNext = &presentIdFeatures;
if (extensionsLookup_.EXT_provoking_vertex) {
presentIdFeatures.pNext = &provokingVertexFeatures;
provokingVertexFeatures.pNext = nullptr;
} else {
presentIdFeatures.pNext = nullptr;
}
vkGetPhysicalDeviceFeatures2(physical_devices_[physical_device_], &features2);
deviceFeatures_.available.standard = features2.features;
deviceFeatures_.available.multiview = multiViewFeatures;
deviceFeatures_.available.presentWait = presentWaitFeatures;
deviceFeatures_.available.presentId = presentIdFeatures;
deviceFeatures_.available.provokingVertex = provokingVertexFeatures;
} else {
vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard);
deviceFeatures_.available.multiview = {};
}

deviceFeatures_.enabled = {};
// Enable a few safe ones if they are available.
deviceFeatures_.enabled.standard.dualSrcBlend = deviceFeatures_.available.standard.dualSrcBlend;
Expand Down Expand Up @@ -746,6 +752,11 @@ VkResult VulkanContext::CreateDevice() {
if (extensionsLookup_.KHR_present_wait) {
deviceFeatures_.enabled.presentWait.presentWait = deviceFeatures_.available.presentWait.presentWait;
}
deviceFeatures_.enabled.provokingVertex = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT };
if (extensionsLookup_.EXT_provoking_vertex) {
deviceFeatures_.enabled.provokingVertex.provokingVertexLast = true;
}

// deviceFeatures_.enabled.multiview.multiviewGeometryShader = deviceFeatures_.available.multiview.multiviewGeometryShader;

VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
Expand All @@ -764,7 +775,13 @@ VkResult VulkanContext::CreateDevice() {
features2.pNext = &deviceFeatures_.enabled.multiview;
deviceFeatures_.enabled.multiview.pNext = &deviceFeatures_.enabled.presentWait;
deviceFeatures_.enabled.presentWait.pNext = &deviceFeatures_.enabled.presentId;
deviceFeatures_.enabled.presentId.pNext = nullptr;
if (extensionsLookup_.EXT_provoking_vertex) {
// TODO: Write some proper chaining thing.
deviceFeatures_.enabled.presentId.pNext = &deviceFeatures_.enabled.provokingVertex;
deviceFeatures_.enabled.provokingVertex.pNext = nullptr;
} else {
deviceFeatures_.enabled.presentId.pNext = nullptr;
}
} else {
device_info.pEnabledFeatures = &deviceFeatures_.enabled.standard;
}
Expand Down Expand Up @@ -871,10 +888,8 @@ bool VulkanContext::CreateInstanceAndDevice(const CreateInfo &info) {
return false;
}

ChooseDevice(physicalDevice);

INFO_LOG(Log::G3D, "Creating Vulkan device (flags: %08x)", info.flags);
if (CreateDevice() != VK_SUCCESS) {
if (CreateDevice(physicalDevice) != VK_SUCCESS) {
INFO_LOG(Log::G3D, "Failed to create vulkan device: %s", InitError().c_str());
DestroyInstance();
return false;
Expand Down
5 changes: 3 additions & 2 deletions Common/GPU/Vulkan/VulkanContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ class VulkanContext {

int GetBestPhysicalDevice();
int GetPhysicalDeviceByName(const std::string &name);
void ChooseDevice(int physical_device);

// Convenience method to avoid code duplication.
// If it returns false, delete the context.
Expand All @@ -191,7 +190,8 @@ class VulkanContext {
bool EnableInstanceExtension(const char *extension, uint32_t coreVersion);
bool EnableDeviceExtension(const char *extension, uint32_t coreVersion);

VkResult CreateDevice();
// Was previously two functions, ChooseDevice and CreateDevice.
VkResult CreateDevice(int physical_device);

const std::string &InitError() const { return init_error_; }

Expand Down Expand Up @@ -279,6 +279,7 @@ class VulkanContext {
VkPhysicalDeviceMultiviewFeatures multiview;
VkPhysicalDevicePresentWaitFeaturesKHR presentWait;
VkPhysicalDevicePresentIdFeaturesKHR presentId;
VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertex;
};

const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const {
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 @@ -268,6 +268,7 @@ struct VulkanExtensions {
bool KHR_present_id; // Should probably check the feature flags instead.
bool KHR_present_wait; // Same
bool GOOGLE_display_timing;
bool EXT_provoking_vertex;
// bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers.
};

Expand Down
1 change: 1 addition & 0 deletions Common/GPU/Vulkan/VulkanQueueRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ enum class PipelineFlags : u8 {
USES_GEOMETRY_SHADER = (1 << 3),
USES_MULTIVIEW = (1 << 4), // Inherited from the render pass it was created with.
USES_DISCARD = (1 << 5),
USES_FLAT_SHADING = (1 << 6),
};
ENUM_CLASS_BITOPS(PipelineFlags);

Expand Down
1 change: 1 addition & 0 deletions Common/GPU/Vulkan/VulkanRenderManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class VKRGraphicsPipelineDesc : public Draw::RefCountedObject {
VkDynamicState dynamicStates[6]{};
VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT rs_provoking{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT };

// Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish.
Promise<VkShaderModule> *vertexShader = nullptr;
Expand Down
8 changes: 6 additions & 2 deletions Common/GPU/Vulkan/thin3d_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1221,8 +1221,6 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char

gDesc.dss = depth->info;

raster->ToVulkan(&gDesc.rs);

// Copy bindings from input layout.
gDesc.topology = primToVK[(int)desc.prim];

Expand All @@ -1244,6 +1242,11 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
raster->ToVulkan(&gDesc.rs);

if (renderManager_.GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
gDesc.rs.pNext = &gDesc.rs_provoking;
gDesc.rs_provoking.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
}

pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, false, tag ? tag : "thin3d");

if (desc.uniformDesc) {
Expand Down Expand Up @@ -1564,6 +1567,7 @@ std::vector<std::string> VKContext::GetFeatureList() const {
AddFeature(features, "multiviewGeometryShader", vulkan_->GetDeviceFeatures().available.multiview.multiviewGeometryShader, vulkan_->GetDeviceFeatures().enabled.multiview.multiviewGeometryShader);
AddFeature(features, "presentId", vulkan_->GetDeviceFeatures().available.presentId.presentId, vulkan_->GetDeviceFeatures().enabled.presentId.presentId);
AddFeature(features, "presentWait", vulkan_->GetDeviceFeatures().available.presentWait.presentWait, vulkan_->GetDeviceFeatures().enabled.presentWait.presentWait);
AddFeature(features, "provokingVertexLast", vulkan_->GetDeviceFeatures().available.provokingVertex.provokingVertexLast, vulkan_->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast);

features.emplace_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat));

Expand Down
4 changes: 2 additions & 2 deletions Common/VR/VRRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ void VR_GetResolution(engine_t* engine, int *pWidth, int *pHeight) {
*pHeight = height;
}

*pWidth *= VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING);
*pHeight *= VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING);
*pWidth = (int)(*pWidth * VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING));
*pHeight = (int)(*pHeight * VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING));
}

void VR_Recenter(engine_t* engine) {
Expand Down
4 changes: 4 additions & 0 deletions GPU/Common/FragmentShaderGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled;

bool doFlatShading = id.Bit(FS_BIT_FLATSHADE) && !flatBug;
if (doFlatShading) {
*fragmentShaderFlags |= FragmentShaderFlags::USES_FLAT_SHADING;
}

ShaderDepalMode shaderDepalMode = (ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2);
if (texture3D) {
shaderDepalMode = ShaderDepalMode::OFF;
Expand Down
1 change: 1 addition & 0 deletions GPU/Common/FragmentShaderGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct FShaderID;
// Can technically be deduced from the fragment shader ID, but this is safer.
enum class FragmentShaderFlags : u32 {
USES_DISCARD = 2,
USES_FLAT_SHADING = 4,
};
ENUM_CLASS_BITOPS(FragmentShaderFlags);

Expand Down
15 changes: 12 additions & 3 deletions GPU/Vulkan/DrawEngineVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,12 +229,17 @@ void DrawEngineVulkan::DoFlush() {

GEPrimitiveType prim = prevPrim_;

// Always use software for flat shading to fix the provoking index.
bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);
// Always use software for flat shading to fix the provoking index
// if the provoking vertex extension is not available.
bool provokingVertexOk = (tess || gstate.getShadeMode() != GE_SHADE_FLAT);
if (renderManager->GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
provokingVertexOk = true;
}
bool useHWTransform = CanUseHardwareTransform(prim) && provokingVertexOk;

uint32_t ibOffset;
uint32_t vbOffset;

// The optimization to avoid indexing isn't really worth it on Vulkan since it means creating more pipelines.
// This could be avoided with the new dynamic state extensions, but not available enough on mobile.
const bool forceIndexed = draw_->GetDeviceCaps().verySlowShaderCompiler;
Expand Down Expand Up @@ -399,6 +404,10 @@ void DrawEngineVulkan::DoFlush() {
params.allowClear = framebufferManager_->UseBufferedRendering();
params.allowSeparateAlphaClear = false;
params.provokeFlatFirst = true;
if (renderManager->GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
// We can get the OpenGL behavior, no need for workarounds.
params.provokeFlatFirst = false;
}
params.flippedY = true;
params.usesHalfZ = true;

Expand Down
8 changes: 8 additions & 0 deletions GPU/Vulkan/PipelineManagerVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
rs.polygonMode = VK_POLYGON_MODE_FILL;
rs.depthClampEnable = key.depthClampEnable;

if (renderManager->GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
rs.pNext = &desc->rs_provoking;
desc->rs_provoking.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
}

desc->fragmentShaderSource = fs->GetShaderString(SHADER_STRING_SOURCE_CODE);
desc->vertexShaderSource = vs->GetShaderString(SHADER_STRING_SOURCE_CODE);
if (gs) {
Expand Down Expand Up @@ -376,6 +381,9 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
if (fs->Flags() & FragmentShaderFlags::USES_DISCARD) {
pipelineFlags |= PipelineFlags::USES_DISCARD;
}
if (fs->Flags() & FragmentShaderFlags::USES_FLAT_SHADING) {
pipelineFlags |= PipelineFlags::USES_FLAT_SHADING;
}
if (vs->Flags() & VertexShaderFlags::MULTI_VIEW) {
pipelineFlags |= PipelineFlags::USES_MULTIVIEW;
}
Expand Down
1 change: 1 addition & 0 deletions GPU/Vulkan/PipelineManagerVulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct VulkanPipeline {
bool UsesDepthStencil() const { return (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) != 0; }
bool UsesGeometryShader() const { return (pipelineFlags & PipelineFlags::USES_GEOMETRY_SHADER) != 0; }
bool UsesDiscard() const { return (pipelineFlags & PipelineFlags::USES_DISCARD) != 0; }
bool UsesFlatShading() const { return (pipelineFlags & PipelineFlags::USES_FLAT_SHADING) != 0; }

u32 GetVariantsBitmask() const;
};
Expand Down
3 changes: 1 addition & 2 deletions SDL/SDLVulkanGraphicsContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int w, in
g_Config.sVulkanDevice = vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName;
}

vulkan_->ChooseDevice(deviceNum);
if (vulkan_->CreateDevice() != VK_SUCCESS) {
if (vulkan_->CreateDevice(deviceNum) != VK_SUCCESS) {
*error_message = vulkan_->InitError();
delete vulkan_;
vulkan_ = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion UI/GPUDriverTestScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ void GPUDriverTestScreen::ShaderTest(UIContext &dc) {
// Draw rectangle that should be flat shaded
dc.BeginPipeline(flatShadingPipeline_, samplerNearest_);
// There is a "provoking vertex" difference here between GL and Vulkan when using flat shading. One gets one color, one gets the other.
// Wherever possible we should reconfigure the GL provoking vertex to match Vulkan, probably.
// However, we now use the VK_EXT_provoking_vertex extension to make it match up (and match with the PSP).
dc.DrawImageVGradient(ImageID("I_ICON"), 0xFFFFFFFF, 0xFF808080, bounds);
dc.Flush();

Expand Down
3 changes: 1 addition & 2 deletions Windows/GPU/WindowsVulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
g_Config.sVulkanDevice = vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName;
}

vulkan_->ChooseDevice(deviceNum);
if (vulkan_->CreateDevice() != VK_SUCCESS) {
if (vulkan_->CreateDevice(deviceNum) != VK_SUCCESS) {
*error_message = vulkan_->InitError();
delete vulkan_;
vulkan_ = nullptr;
Expand Down
3 changes: 1 addition & 2 deletions libretro/LibretroVulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ static bool create_device(retro_vulkan_context *context, VkInstance instance, Vk
physical_device = vk->GetBestPhysicalDevice();
}

vk->ChooseDevice(physical_device);
vk->CreateDevice();
vk->CreateDevice(physical_device);
#ifdef _WIN32
vk->InitSurface(WINDOWSYSTEM_WIN32, nullptr, nullptr);
#elif defined(__ANDROID__)
Expand Down
Loading