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() endif()
if(MSVC) if(MSVC)
if(${CPU_ARCH} STREQUAL "x64") if(CPU_ARCH_X64)
enable_language(ASM_MASM) enable_language(ASM_MASM)
target_sources(common PRIVATE fastjmp_x86.asm) target_sources(common PRIVATE fastjmp_x86.asm)
set_source_files_properties(fastjmp_x86.asm PROPERTIES COMPILE_FLAGS "/D_M_X86_64") 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) enable_language(ASM_MARMASM)
target_sources(common PRIVATE fastjmp_arm.asm) target_sources(common PRIVATE fastjmp_arm.asm)
endif() endif()

View File

@ -241,13 +241,19 @@ bool Host::CreateGPUDevice(RenderAPI api)
Log_InfoPrintf("Trying to create a %s GPU device...", GPUDevice::RenderAPIToString(api)); Log_InfoPrintf("Trying to create a %s GPU device...", GPUDevice::RenderAPIToString(api));
g_gpu_device = GPUDevice::CreateDeviceForAPI(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.. // TODO: FSUI should always use vsync..
const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled; const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled;
if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter, if (!g_gpu_device || !g_gpu_device->Create(
g_settings.gpu_disable_shader_cache ? std::string_view() : g_settings.gpu_adapter,
std::string_view(EmuFolders::Cache), g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync, SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync,
g_settings.gpu_threaded_presentation)) g_settings.gpu_threaded_presentation, static_cast<GPUDevice::FeatureMask>(disabled_features)))
{ {
Log_ErrorPrintf("Failed to create GPU device."); Log_ErrorPrintf("Failed to create GPU device.");
if (g_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_multisamples = static_cast<u32>(si.GetIntValue("GPU", "Multisamples", 1));
gpu_use_debug_device = si.GetBoolValue("GPU", "UseDebugDevice", false); gpu_use_debug_device = si.GetBoolValue("GPU", "UseDebugDevice", false);
gpu_disable_shader_cache = si.GetBoolValue("GPU", "DisableShaderCache", 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_per_sample_shading = si.GetBoolValue("GPU", "PerSampleShading", false);
gpu_use_thread = si.GetBoolValue("GPU", "UseThread", true); gpu_use_thread = si.GetBoolValue("GPU", "UseThread", true);
gpu_use_software_renderer_for_readbacks = si.GetBoolValue("GPU", "UseSoftwareRendererForReadbacks", false); 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.SetIntValue("GPU", "Multisamples", static_cast<long>(gpu_multisamples));
si.SetBoolValue("GPU", "UseDebugDevice", gpu_use_debug_device); si.SetBoolValue("GPU", "UseDebugDevice", gpu_use_debug_device);
si.SetBoolValue("GPU", "DisableShaderCache", gpu_disable_shader_cache); 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", "PerSampleShading", gpu_per_sample_shading);
si.SetBoolValue("GPU", "UseThread", gpu_use_thread); si.SetBoolValue("GPU", "UseThread", gpu_use_thread);
si.SetBoolValue("GPU", "ThreadedPresentation", gpu_threaded_presentation); si.SetBoolValue("GPU", "ThreadedPresentation", gpu_threaded_presentation);

View File

@ -100,6 +100,8 @@ struct Settings
bool gpu_threaded_presentation = true; bool gpu_threaded_presentation = true;
bool gpu_use_debug_device = false; bool gpu_use_debug_device = false;
bool gpu_disable_shader_cache = 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_per_sample_shading = false;
bool gpu_true_color = true; bool gpu_true_color = true;
bool gpu_scaled_dithering = 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 || 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_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 // 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 || const bool recreate_device =
g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation); (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, Host::AddIconOSDMessage("RendererSwitch", ICON_FA_PAINT_ROLLER,
fmt::format(TRANSLATE_FS("OSDMessage", "Switching to {}{} GPU renderer."), fmt::format(TRANSLATE_FS("OSDMessage", "Switching to {}{} GPU renderer."),

View File

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

View File

@ -63,7 +63,8 @@ bool D3D11Device::HasSurface() const
return static_cast<bool>(m_swap_chain); 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); 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)); sizeof(allow_tearing_supported));
m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE); m_allow_tearing_supported = (SUCCEEDED(hr) && allow_tearing_supported == TRUE);
SetFeatures(); SetFeatures(disabled_features);
if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain()) if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain())
return false; return false;
@ -152,7 +153,7 @@ void D3D11Device::DestroyDevice()
m_device.Reset(); m_device.Reset();
} }
void D3D11Device::SetFeatures() void D3D11Device::SetFeatures(FeatureMask disabled_features)
{ {
const D3D_FEATURE_LEVEL feature_level = m_device->GetFeatureLevel(); 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.framebuffer_fetch = false;
m_features.per_sample_shading = (feature_level >= D3D_FEATURE_LEVEL_10_1); m_features.per_sample_shading = (feature_level >= D3D_FEATURE_LEVEL_10_1);
m_features.noperspective_interpolation = 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 = false; 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.partial_msaa_resolve = false;
m_features.gpu_timing = true; m_features.gpu_timing = true;
m_features.shader_cache = true; m_features.shader_cache = true;

View File

@ -111,7 +111,7 @@ public:
static AdapterAndModeList StaticGetAdapterAndModeList(); static AdapterAndModeList StaticGetAdapterAndModeList();
protected: 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; void DestroyDevice() override;
private: private:
@ -129,7 +129,7 @@ private:
static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory); static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory);
void SetFeatures(); void SetFeatures(FeatureMask disabled_features);
bool CheckStagingBufferSize(u32 width, u32 height, DXGI_FORMAT format); bool CheckStagingBufferSize(u32 width, u32 height, DXGI_FORMAT format);
void DestroyStagingBuffer(); void DestroyStagingBuffer();

View File

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

View File

@ -179,7 +179,8 @@ public:
void UnbindTextureBuffer(D3D12TextureBuffer* buf); void UnbindTextureBuffer(D3D12TextureBuffer* buf);
protected: 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; void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override; bool ReadPipelineCache(const std::string& filename) override;
@ -215,7 +216,7 @@ private:
static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory); static void GetAdapterAndModeList(AdapterAndModeList* ret, IDXGIFactory5* factory);
void SetFeatures(); void SetFeatures(FeatureMask disabled_features);
bool CreateSwapChain(); bool CreateSwapChain();
bool CreateSwapChainRTV(); 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, 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_vsync_enabled = vsync;
m_debug_device = debug_device; m_debug_device = debug_device;
@ -234,7 +235,7 @@ bool GPUDevice::Create(const std::string_view& adapter, const std::string_view&
return false; return false;
} }
if (!CreateDevice(adapter, threaded_presentation)) if (!CreateDevice(adapter, threaded_presentation, disabled_features))
{ {
Log_ErrorPrintf("Failed to create device."); Log_ErrorPrintf("Failed to create device.");
return false; return false;

View File

@ -443,6 +443,14 @@ public:
// TODO: gpu crash handling on present // TODO: gpu crash handling on present
using DrawIndex = u16; 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 struct Features
{ {
bool dual_source_blend : 1; bool dual_source_blend : 1;
@ -531,7 +539,7 @@ public:
virtual RenderAPI GetRenderAPI() const = 0; virtual RenderAPI GetRenderAPI() const = 0;
bool Create(const std::string_view& adapter, const std::string_view& shader_cache_path, u32 shader_cache_version, 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(); void Destroy();
virtual bool HasSurface() const = 0; virtual bool HasSurface() const = 0;
@ -636,7 +644,7 @@ public:
virtual float GetAndResetAccumulatedGPUTime(); virtual float GetAndResetAccumulatedGPUTime();
protected: 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; virtual void DestroyDevice() = 0;
std::string GetShaderCacheBaseName(const std::string_view& type) const; std::string GetShaderCacheBaseName(const std::string_view& type) const;

View File

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

View File

@ -123,7 +123,7 @@ void MetalDevice::SetVSync(bool enabled)
[m_layer setDisplaySyncEnabled: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 @autoreleasepool
{ {
@ -166,7 +166,7 @@ bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_pr
m_queue = [queue retain]; m_queue = [queue retain];
Log_InfoPrintf("Metal Device: %s", [[m_device name] UTF8String]); Log_InfoPrintf("Metal Device: %s", [[m_device name] UTF8String]);
SetFeatures(); SetFeatures(disabled_features);
if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateLayer()) if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateLayer())
return false; 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 // https://gist.github.com/kylehowells/63d0723abc9588eb734cade4b7df660d
if ([m_device supportsFamily:MTLGPUFamilyMacCatalyst1] || [m_device supportsFamily:MTLGPUFamilyMac1] || if ([m_device supportsFamily:MTLGPUFamilyMacCatalyst1] || [m_device supportsFamily:MTLGPUFamilyMac1] ||
@ -211,11 +211,11 @@ void MetalDevice::SetFeatures()
m_max_multisamples = multisamples; m_max_multisamples = multisamples;
} }
m_features.dual_source_blend = true; m_features.dual_source_blend = !(disabled_features & FEATURE_MASK_DUAL_SOURCE_BLEND);
m_features.framebuffer_fetch = false; // TODO m_features.framebuffer_fetch = !(disabled_features & FEATURE_MASK_FRAMEBUFFER_FETCH) && false; // TODO
m_features.per_sample_shading = true; m_features.per_sample_shading = true;
m_features.noperspective_interpolation = 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.texture_buffers_emulated_with_ssbo = true;
m_features.geometry_shaders = false; m_features.geometry_shaders = false;
m_features.partial_msaa_resolve = 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; 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); m_gl_context = GL::Context::Create(m_window_info);
if (!m_gl_context) if (!m_gl_context)
@ -348,7 +349,7 @@ bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
} }
bool buggy_pbo; bool buggy_pbo;
if (!CheckFeatures(&buggy_pbo)) if (!CheckFeatures(&buggy_pbo, disabled_features))
return false; return false;
if (!CreateBuffers(buggy_pbo)) if (!CreateBuffers(buggy_pbo))
@ -360,7 +361,7 @@ bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
return true; 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(); 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; GLint max_dual_source_draw_buffers = 0;
glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max_dual_source_draw_buffers); glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max_dual_source_draw_buffers);
m_features.dual_source_blend = 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); (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__ #ifdef __APPLE__
// Partial texture buffer uploads appear to be broken in macOS's OpenGL driver. // Partial texture buffer uploads appear to be broken in macOS's OpenGL driver.
m_features.supports_texture_buffers = false; m_features.supports_texture_buffers = false;
#else #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? // And Samsung's ANGLE/GLES driver?
if (std::strstr(reinterpret_cast<const char*>(glGetString(GL_RENDERER)), "ANGLE")) 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. // noperspective is not supported in GLSL ES.
m_features.noperspective_interpolation = !is_gles; 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() && m_features.gpu_timing = !(m_gl_context->IsGLES() &&
(!GLAD_GL_EXT_disjoint_timer_query || !glGetQueryObjectivEXT || !glGetQueryObjectui64vEXT)); (!GLAD_GL_EXT_disjoint_timer_query || !glGetQueryObjectivEXT || !glGetQueryObjectui64vEXT));

View File

@ -122,7 +122,7 @@ public:
void UnbindPipeline(const OpenGLPipeline* pl); void UnbindPipeline(const OpenGLPipeline* pl);
protected: 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; void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) 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 UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024;
static constexpr u32 TEXTURE_STREAM_BUFFER_SIZE = 16 * 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); bool CreateBuffers(bool buggy_pbo);
void DestroyBuffers(); void DestroyBuffers();

View File

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

View File

@ -220,7 +220,8 @@ public:
void UnbindTextureBuffer(VulkanTextureBuffer* buf); void UnbindTextureBuffer(VulkanTextureBuffer* buf);
protected: 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; void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override; bool ReadPipelineCache(const std::string& filename) override;
@ -305,7 +306,7 @@ private:
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer); bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer);
void ProcessDeviceExtensions(); void ProcessDeviceExtensions();
bool CheckFeatures(); bool CheckFeatures(FeatureMask disabled_features);
bool CreateAllocator(); bool CreateAllocator();
void DestroyAllocator(); 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_ONE_MINUS_SRC1_ALPHA, // InvSrcAlpha1
VK_BLEND_FACTOR_DST_ALPHA, // DstAlpha VK_BLEND_FACTOR_DST_ALPHA, // DstAlpha
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, // InvDstAlpha VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, // InvDstAlpha
VK_BLEND_FACTOR_CONSTANT_ALPHA, // ConstantAlpha VK_BLEND_FACTOR_CONSTANT_COLOR, // ConstantAlpha
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA, // InvConstantAlpha VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, // InvConstantAlpha
}}; }};
static constexpr std::array<VkBlendOp, static_cast<u32>(GPUPipeline::BlendOp::MaxCount)> op_mapping = {{ static constexpr std::array<VkBlendOp, static_cast<u32>(GPUPipeline::BlendOp::MaxCount)> op_mapping = {{