Settings: Add option to disable DSB/fbfetch

This commit is contained in:
Stenzek 2023-11-28 14:08:29 +10:00
parent 7fe3bfece0
commit e382f2b64a
No known key found for this signature in database
19 changed files with 106 additions and 59 deletions

View File

@ -71,11 +71,11 @@ if(WIN32)
endif()
if(MSVC)
if(${CPU_ARCH} STREQUAL "x64")
if(CPU_ARCH_X64)
enable_language(ASM_MASM)
target_sources(common PRIVATE fastjmp_x86.asm)
set_source_files_properties(fastjmp_x86.asm PROPERTIES COMPILE_FLAGS "/D_M_X86_64")
elseif(${CPU_ARCH} STREQUAL "aarch32" OR ${CPU_ARCH} STREQUAL "aarch64")
elseif(CPU_ARCH_ARM32 OR CPU_ARCH_ARM64)
enable_language(ASM_MARMASM)
target_sources(common PRIVATE fastjmp_arm.asm)
endif()

View File

@ -241,13 +241,19 @@ bool Host::CreateGPUDevice(RenderAPI api)
Log_InfoPrintf("Trying to create a %s GPU device...", GPUDevice::RenderAPIToString(api));
g_gpu_device = GPUDevice::CreateDeviceForAPI(api);
u32 disabled_features = 0;
if (g_settings.gpu_disable_dual_source_blend)
disabled_features |= GPUDevice::FEATURE_MASK_DUAL_SOURCE_BLEND;
if (g_settings.gpu_disable_framebuffer_fetch)
disabled_features |= GPUDevice::FEATURE_MASK_FRAMEBUFFER_FETCH;
// TODO: FSUI should always use vsync..
const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled;
if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter,
g_settings.gpu_disable_shader_cache ? std::string_view() :
std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync,
g_settings.gpu_threaded_presentation))
if (!g_gpu_device || !g_gpu_device->Create(
g_settings.gpu_adapter,
g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync,
g_settings.gpu_threaded_presentation, static_cast<GPUDevice::FeatureMask>(disabled_features)))
{
Log_ErrorPrintf("Failed to create GPU device.");
if (g_gpu_device)

View File

@ -181,6 +181,8 @@ void Settings::Load(SettingsInterface& si)
gpu_multisamples = static_cast<u32>(si.GetIntValue("GPU", "Multisamples", 1));
gpu_use_debug_device = si.GetBoolValue("GPU", "UseDebugDevice", false);
gpu_disable_shader_cache = si.GetBoolValue("GPU", "DisableShaderCache", false);
gpu_disable_dual_source_blend = si.GetBoolValue("GPU", "DisableDualSourceBlend", false);
gpu_disable_framebuffer_fetch = si.GetBoolValue("GPU", "DisableFramebufferFetch", false);
gpu_per_sample_shading = si.GetBoolValue("GPU", "PerSampleShading", false);
gpu_use_thread = si.GetBoolValue("GPU", "UseThread", true);
gpu_use_software_renderer_for_readbacks = si.GetBoolValue("GPU", "UseSoftwareRendererForReadbacks", false);
@ -437,6 +439,8 @@ void Settings::Save(SettingsInterface& si) const
si.SetIntValue("GPU", "Multisamples", static_cast<long>(gpu_multisamples));
si.SetBoolValue("GPU", "UseDebugDevice", gpu_use_debug_device);
si.SetBoolValue("GPU", "DisableShaderCache", gpu_disable_shader_cache);
si.SetBoolValue("GPU", "DisableDualSourceBlend", gpu_disable_dual_source_blend);
si.SetBoolValue("GPU", "DisableFramebufferFetch", gpu_disable_framebuffer_fetch);
si.SetBoolValue("GPU", "PerSampleShading", gpu_per_sample_shading);
si.SetBoolValue("GPU", "UseThread", gpu_use_thread);
si.SetBoolValue("GPU", "ThreadedPresentation", gpu_threaded_presentation);

View File

@ -100,6 +100,8 @@ struct Settings
bool gpu_threaded_presentation = true;
bool gpu_use_debug_device = false;
bool gpu_disable_shader_cache = false;
bool gpu_disable_dual_source_blend = false;
bool gpu_disable_framebuffer_fetch = false;
bool gpu_per_sample_shading = false;
bool gpu_true_color = true;
bool gpu_scaled_dithering = true;

View File

@ -3525,11 +3525,18 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
{
if (IsValid() && (g_settings.gpu_renderer != old_settings.gpu_renderer ||
g_settings.gpu_use_debug_device != old_settings.gpu_use_debug_device ||
g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation))
g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation ||
g_settings.gpu_disable_shader_cache != old_settings.gpu_disable_shader_cache ||
g_settings.gpu_disable_dual_source_blend != old_settings.gpu_disable_dual_source_blend ||
g_settings.gpu_disable_framebuffer_fetch != old_settings.gpu_disable_framebuffer_fetch))
{
// if debug device/threaded presentation change, we need to recreate the whole display
const bool recreate_device = (g_settings.gpu_use_debug_device != old_settings.gpu_use_debug_device ||
g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation);
const bool recreate_device =
(g_settings.gpu_use_debug_device != old_settings.gpu_use_debug_device ||
g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation ||
g_settings.gpu_disable_shader_cache != old_settings.gpu_disable_shader_cache ||
g_settings.gpu_disable_dual_source_blend != old_settings.gpu_disable_dual_source_blend ||
g_settings.gpu_disable_framebuffer_fetch != old_settings.gpu_disable_framebuffer_fetch);
Host::AddIconOSDMessage("RendererSwitch", ICON_FA_PAINT_ROLLER,
fmt::format(TRANSLATE_FS("OSDMessage", "Switching to {}{} GPU renderer."),

View File

@ -340,6 +340,10 @@ void AdvancedSettingsWidget::addTweakOptions()
false);
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Shader Cache"), "GPU", "DisableShaderCache",
false);
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Dual-Source Blend"), "GPU",
"DisableDualSourceBlend", false);
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Framebuffer Fetch"), "GPU",
"DisableFramebufferFetch", false);
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Stretch Display Vertically"), "Display",
"StretchVertically", false);
@ -401,6 +405,8 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
static_cast<int>(Settings::DEFAULT_GPU_MAX_RUN_AHEAD)); // GPU max run-ahead
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Use debug host GPU device
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Shader Cache
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Dual-Source Blend
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Framebuffer Fetch
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Stretch Display Vertically
setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Increase Timer Resolution
setChoiceTweakOption(m_ui.tweakOptionTable, i++,
@ -447,6 +453,9 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
sif->DeleteValue("Hacks", "GPUFIFOSize");
sif->DeleteValue("Hacks", "GPUMaxRunAhead");
sif->DeleteValue("GPU", "UseDebugDevice");
sif->DeleteValue("GPU", "DisableShaderCache");
sif->DeleteValue("GPU", "DisableDualSourceBlend");
sif->DeleteValue("GPU", "DisableFramebufferFetch");
sif->DeleteValue("Display", "StretchVertically");
sif->DeleteValue("Main", "IncreaseTimerResolution");
sif->DeleteValue("CDROM", "MechaconVersion");

View File

@ -63,7 +63,8 @@ bool D3D11Device::HasSurface() const
return static_cast<bool>(m_swap_chain);
}
bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation)
bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features)
{
std::unique_lock lock(s_instance_mutex);
@ -131,7 +132,7 @@ bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_pr
sizeof(allow_tearing_supported));
m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE);
SetFeatures();
SetFeatures(disabled_features);
if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain())
return false;
@ -152,7 +153,7 @@ void D3D11Device::DestroyDevice()
m_device.Reset();
}
void D3D11Device::SetFeatures()
void D3D11Device::SetFeatures(FeatureMask disabled_features)
{
const D3D_FEATURE_LEVEL feature_level = m_device->GetFeatureLevel();
@ -169,13 +170,13 @@ void D3D11Device::SetFeatures()
}
}
m_features.dual_source_blend = true;
m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND);
m_features.framebuffer_fetch = false;
m_features.per_sample_shading = (feature_level >= D3D_FEATURE_LEVEL_10_1);
m_features.noperspective_interpolation = true;
m_features.supports_texture_buffers = true;
m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS);
m_features.texture_buffers_emulated_with_ssbo = false;
m_features.geometry_shaders = true;
m_features.geometry_shaders = !(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS);
m_features.partial_msaa_resolve = false;
m_features.gpu_timing = true;
m_features.shader_cache = true;

View File

@ -111,7 +111,7 @@ public:
static AdapterAndModeList StaticGetAdapterAndModeList();
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override;
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) override;
void DestroyDevice() override;
private:
@ -129,7 +129,7 @@ private:
static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory);
void SetFeatures();
void SetFeatures(FeatureMask disabled_features);
bool CheckStagingBufferSize(u32 width, u32 height, DXGI_FORMAT format);
void DestroyStagingBuffer();

View File

@ -116,7 +116,7 @@ D3D12Device::ComPtr<ID3D12RootSignature> D3D12Device::CreateRootSignature(const
return rs;
}
bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation)
bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features)
{
std::unique_lock lock(s_instance_mutex);
@ -223,7 +223,7 @@ bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_pr
return false;
}
SetFeatures();
SetFeatures(disabled_features);
if (!CreateCommandLists() || !CreateDescriptorHeaps())
return false;
@ -1156,7 +1156,7 @@ void D3D12Device::InsertDebugMessage(const char* msg)
#endif
}
void D3D12Device::SetFeatures()
void D3D12Device::SetFeatures(FeatureMask disabled_features)
{
m_max_texture_size = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
m_max_multisamples = 1;
@ -1172,13 +1172,13 @@ void D3D12Device::SetFeatures()
}
}
m_features.dual_source_blend = true;
m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND);
m_features.framebuffer_fetch = false;
m_features.noperspective_interpolation = true;
m_features.per_sample_shading = true;
m_features.supports_texture_buffers = true;
m_features.noperspective_interpolation = true;
m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS);
m_features.texture_buffers_emulated_with_ssbo = false;
m_features.geometry_shaders = true;
m_features.geometry_shaders = !(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS);
m_features.partial_msaa_resolve = true;
m_features.gpu_timing = true;
m_features.shader_cache = true;

View File

@ -179,7 +179,8 @@ public:
void UnbindTextureBuffer(D3D12TextureBuffer* buf);
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override;
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features) override;
void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override;
@ -215,7 +216,7 @@ private:
static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory);
void SetFeatures();
void SetFeatures(FeatureMask disabled_features);
bool CreateSwapChain();
bool CreateSwapChainRTV();

View File

@ -223,7 +223,8 @@ bool GPUDevice::IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs)
}
bool GPUDevice::Create(const std::string_view& adapter, const std::string_view& shader_cache_path,
u32 shader_cache_version, bool debug_device, bool vsync, bool threaded_presentation)
u32 shader_cache_version, bool debug_device, bool vsync, bool threaded_presentation,
FeatureMask disabled_features)
{
m_vsync_enabled = vsync;
m_debug_device = debug_device;
@ -234,7 +235,7 @@ bool GPUDevice::Create(const std::string_view& adapter, const std::string_view&
return false;
}
if (!CreateDevice(adapter, threaded_presentation))
if (!CreateDevice(adapter, threaded_presentation, disabled_features))
{
Log_ErrorPrintf("Failed to create device.");
return false;

View File

@ -443,6 +443,14 @@ public:
// TODO: gpu crash handling on present
using DrawIndex = u16;
enum FeatureMask : u32
{
FEATURE_MASK_DUAL_SOURCE_BLEND = (1 << 0),
FEATURE_MASK_FRAMEBUFFER_FETCH = (1 << 1),
FEATURE_MASK_TEXTURE_BUFFERS = (1 << 2),
FEATURE_MASK_GEOMETRY_SHADERS = (1 << 3),
};
struct Features
{
bool dual_source_blend : 1;
@ -531,7 +539,7 @@ public:
virtual RenderAPI GetRenderAPI() const = 0;
bool Create(const std::string_view& adapter, const std::string_view& shader_cache_path, u32 shader_cache_version,
bool debug_device, bool vsync, bool threaded_presentation);
bool debug_device, bool vsync, bool threaded_presentation, FeatureMask disabled_features);
void Destroy();
virtual bool HasSurface() const = 0;
@ -636,7 +644,7 @@ public:
virtual float GetAndResetAccumulatedGPUTime();
protected:
virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) = 0;
virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) = 0;
virtual void DestroyDevice() = 0;
std::string GetShaderCacheBaseName(const std::string_view& type) const;

View File

@ -283,7 +283,7 @@ public:
static AdapterAndModeList StaticGetAdapterAndModeList();
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override;
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) override;
void DestroyDevice() override;
private:
@ -298,7 +298,7 @@ private:
ALWAYS_INLINE NSView* GetWindowView() const { return (__bridge NSView*)m_window_info.window_handle; }
void SetFeatures();
void SetFeatures(FeatureMask disabled_features);
bool LoadShaders();
id<MTLFunction> GetFunctionFromLibrary(id<MTLLibrary> library, NSString* name);

View File

@ -123,7 +123,7 @@ void MetalDevice::SetVSync(bool enabled)
[m_layer setDisplaySyncEnabled:enabled];
}
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation)
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features)
{
@autoreleasepool
{
@ -166,7 +166,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr
m_queue = [queue retain];
Log_InfoPrintf("Metal Device: %s", [[m_device name] UTF8String]);
SetFeatures();
SetFeatures(disabled_features);
if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateLayer())
return false;
@ -190,7 +190,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr
}
}
void MetalDevice::SetFeatures()
void MetalDevice::SetFeatures(FeatureMask disabled_features)
{
// https://gist.github.com/kylehowells/63d0723abc9588eb734cade4b7df660d
if ([m_device supportsFamily:MTLGPUFamilyMacCatalyst1] || [m_device supportsFamily:MTLGPUFamilyMac1] ||
@ -211,11 +211,11 @@ void MetalDevice::SetFeatures()
m_max_multisamples = multisamples;
}
m_features.dual_source_blend = true;
m_features.framebuffer_fetch = false; // TODO
m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND);
m_features.framebuffer_fetch = !(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && false; // TODO
m_features.per_sample_shading = true;
m_features.noperspective_interpolation = true;
m_features.supports_texture_buffers = true;
m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS);
m_features.texture_buffers_emulated_with_ssbo = true;
m_features.geometry_shaders = false;
m_features.partial_msaa_resolve = false;

View File

@ -299,7 +299,8 @@ bool OpenGLDevice::HasSurface() const
return m_window_info.type != WindowInfo::Type::Surfaceless;
}
bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation)
bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features)
{
m_gl_context = GL::Context::Create(m_window_info);
if (!m_gl_context)
@ -348,7 +349,7 @@ bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
}
bool buggy_pbo;
if (!CheckFeatures(&buggy_pbo))
if (!CheckFeatures(&buggy_pbo, disabled_features))
return false;
if (!CreateBuffers(buggy_pbo))
@ -360,7 +361,7 @@ bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
return true;
}
bool OpenGLDevice::CheckFeatures(bool* buggy_pbo)
bool OpenGLDevice::CheckFeatures(bool* buggy_pbo, FeatureMask disabled_features)
{
const bool is_gles = m_gl_context->IsGLES();
@ -427,16 +428,18 @@ bool OpenGLDevice::CheckFeatures(bool* buggy_pbo)
GLint max_dual_source_draw_buffers = 0;
glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max_dual_source_draw_buffers);
m_features.dual_source_blend =
(max_dual_source_draw_buffers > 0) &&
!(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && (max_dual_source_draw_buffers > 0) &&
(GLAD_GL_VERSION_3_3 || GLAD_GL_ARB_blend_func_extended || GLAD_GL_EXT_blend_func_extended);
m_features.framebuffer_fetch = (GLAD_GL_EXT_shader_framebuffer_fetch || GLAD_GL_ARM_shader_framebuffer_fetch);
m_features.framebuffer_fetch = !(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) &&
(GLAD_GL_EXT_shader_framebuffer_fetch || GLAD_GL_ARM_shader_framebuffer_fetch);
#ifdef __APPLE__
// Partial texture buffer uploads appear to be broken in macOS's OpenGL driver.
m_features.supports_texture_buffers = false;
#else
m_features.supports_texture_buffers = (GLAD_GL_VERSION_3_1 || GLAD_GL_ES_VERSION_3_2);
m_features.supports_texture_buffers =
!(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS) && (GLAD_GL_VERSION_3_1 || GLAD_GL_ES_VERSION_3_2);
// And Samsung's ANGLE/GLES driver?
if (std::strstr(reinterpret_cast<const char*>(glGetString(GL_RENDERER)), "ANGLE"))
@ -493,7 +496,8 @@ bool OpenGLDevice::CheckFeatures(bool* buggy_pbo)
// noperspective is not supported in GLSL ES.
m_features.noperspective_interpolation = !is_gles;
m_features.geometry_shaders = GLAD_GL_VERSION_3_2 || GLAD_GL_ES_VERSION_3_2;
m_features.geometry_shaders =
!(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && (GLAD_GL_VERSION_3_2 || GLAD_GL_ES_VERSION_3_2);
m_features.gpu_timing = !(m_gl_context->IsGLES() &&
(!GLAD_GL_EXT_disjoint_timer_query || !glGetQueryObjectivEXT || !glGetQueryObjectui64vEXT));

View File

@ -122,7 +122,7 @@ public:
void UnbindPipeline(const OpenGLPipeline* pl);
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override;
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation, FeatureMask disabled_features) override;
void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override;
@ -138,7 +138,7 @@ private:
static constexpr u32 UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024;
static constexpr u32 TEXTURE_STREAM_BUFFER_SIZE = 16 * 1024 * 1024;
bool CheckFeatures(bool* buggy_pbo);
bool CheckFeatures(bool* buggy_pbo, FeatureMask disabled_features);
bool CreateBuffers(bool buggy_pbo);
void DestroyBuffers();

View File

@ -1601,7 +1601,8 @@ bool VulkanDevice::HasSurface() const
return static_cast<bool>(m_swap_chain);
}
bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation)
bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features)
{
std::unique_lock lock(s_instance_mutex);
bool enable_debug_utils = m_debug_device;
@ -1704,7 +1705,7 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
if (!CreateDevice(surface, enable_validation_layer))
return false;
if (!CheckFeatures())
if (!CheckFeatures(disabled_features))
{
Host::ReportErrorAsync("Error", "Your GPU does not support the required Vulkan features.");
return false;
@ -2163,7 +2164,7 @@ void VulkanDevice::InsertDebugMessage(const char* msg)
#endif
}
bool VulkanDevice::CheckFeatures()
bool VulkanDevice::CheckFeatures(FeatureMask disabled_features)
{
m_max_texture_size = m_device_properties.limits.maxImageDimension2D;
@ -2193,15 +2194,16 @@ bool VulkanDevice::CheckFeatures()
else
m_max_multisamples = 1;
m_features.dual_source_blend = m_device_features.dualSrcBlend; // TODO: Option to disable
m_features.framebuffer_fetch = false; // TODO: Option to disable
m_features.dual_source_blend =
!(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND) && m_device_features.dualSrcBlend;
m_features.framebuffer_fetch = /*!(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && */false;
if (!m_features.dual_source_blend)
Log_WarningPrintf("Vulkan driver is missing dual-source blending. This will have an impact on performance.");
m_features.noperspective_interpolation = true;
m_features.per_sample_shading = m_device_features.sampleRateShading;
m_features.supports_texture_buffers = true;
m_features.supports_texture_buffers = !(disabled_features & FEATURE_MASK_TEXTURE_BUFFERS);
#ifdef __APPLE__
// Partial texture buffer uploads appear to be broken in macOS/MoltenVK.
@ -2218,7 +2220,8 @@ bool VulkanDevice::CheckFeatures()
if (m_features.texture_buffers_emulated_with_ssbo)
Log_WarningPrintf("Emulating texture buffers with SSBOs.");
m_features.geometry_shaders = m_device_features.geometryShader;
m_features.geometry_shaders =
!(disabled_features & FEATURE_MASK_GEOMETRY_SHADERS) && m_device_features.geometryShader;
m_features.partial_msaa_resolve = true;
m_features.shader_cache = true;

View File

@ -220,7 +220,8 @@ public:
void UnbindTextureBuffer(VulkanTextureBuffer* buf);
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation) override;
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features) override;
void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override;
@ -305,7 +306,7 @@ private:
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer);
void ProcessDeviceExtensions();
bool CheckFeatures();
bool CheckFeatures(FeatureMask disabled_features);
bool CreateAllocator();
void DestroyAllocator();

View File

@ -139,8 +139,8 @@ std::unique_ptr<GPUPipeline> VulkanDevice::CreatePipeline(const GPUPipeline::Gra
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, // InvSrcAlpha1
VK_BLEND_FACTOR_DST_ALPHA, // DstAlpha
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, // InvDstAlpha
VK_BLEND_FACTOR_CONSTANT_ALPHA, // ConstantAlpha
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, // InvConstantAlpha
VK_BLEND_FACTOR_CONSTANT_COLOR, // ConstantAlpha
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, // InvConstantAlpha
}};
static constexpr std::array<VkBlendOp, static_cast<u32>(GPUPipeline::BlendOp::MaxCount)> op_mapping = {{