diff --git a/Source/Core/VideoBackends/D3D/D3DBase.cpp b/Source/Core/VideoBackends/D3D/D3DBase.cpp index a290292e8e..6c4478c492 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D/D3DBase.cpp @@ -414,7 +414,10 @@ HRESULT Create(HWND wnd) hr = device->QueryInterface(&device1); if (FAILED(hr)) + { WARN_LOG(VIDEO, "Missing Direct3D 11.1 support. Logical operations will not be supported."); + g_Config.backend_info.bSupportsLogicOp = false; + } // BGRA textures are easier to deal with in TextureCache, but might not be supported UINT format_support; diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index fb8c18ae5e..03d2929322 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -62,6 +62,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsClipControl = true; g_Config.backend_info.bSupportsDepthClamp = true; g_Config.backend_info.bSupportsReversedDepthRange = false; + g_Config.backend_info.bSupportsLogicOp = true; g_Config.backend_info.bSupportsMultithreading = false; g_Config.backend_info.bSupportsGPUTextureDecoding = false; g_Config.backend_info.bSupportsST3CTextures = false; diff --git a/Source/Core/VideoBackends/Null/NullBackend.cpp b/Source/Core/VideoBackends/Null/NullBackend.cpp index 430da35f84..fa32ce0cf5 100644 --- a/Source/Core/VideoBackends/Null/NullBackend.cpp +++ b/Source/Core/VideoBackends/Null/NullBackend.cpp @@ -47,6 +47,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsBPTCTextures = false; g_Config.backend_info.bSupportsFramebufferFetch = false; g_Config.backend_info.bSupportsBackgroundCompiling = false; + g_Config.backend_info.bSupportsLogicOp = false; // aamodes: We only support 1 sample, so no MSAA g_Config.backend_info.Adapters.clear(); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index ffd84a1623..27113a6b8b 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -521,6 +521,9 @@ Renderer::Renderer() // depth clamping. g_Config.backend_info.bSupportsDepthClamp = false; + // GLES does not support logic op. + g_Config.backend_info.bSupportsLogicOp = false; + if (GLExtensions::Supports("GL_EXT_shader_framebuffer_fetch")) { g_ogl_config.SupportedFramebufferFetch = EsFbFetchType::FbFetchExt; diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index 95dfeb23e7..1ac21b03b0 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -83,6 +83,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsPostProcessing = true; g_Config.backend_info.bSupportsSSAA = true; g_Config.backend_info.bSupportsReversedDepthRange = true; + g_Config.backend_info.bSupportsLogicOp = true; g_Config.backend_info.bSupportsMultithreading = false; g_Config.backend_info.bSupportsCopyToVram = true; diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp index 18a739726b..2acd694f76 100644 --- a/Source/Core/VideoBackends/Software/SWmain.cpp +++ b/Source/Core/VideoBackends/Software/SWmain.cpp @@ -71,6 +71,7 @@ void VideoSoftware::InitBackendInfo() g_Config.backend_info.bSupportsCopyToVram = false; g_Config.backend_info.bSupportsFramebufferFetch = false; g_Config.backend_info.bSupportsBackgroundCompiling = false; + g_Config.backend_info.bSupportsLogicOp = true; // aamodes g_Config.backend_info.AAModes = {1}; diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index 57bdcdfce9..32bd449003 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -246,6 +246,7 @@ void VulkanContext::PopulateBackendInfo(VideoConfig* config) config->backend_info.bSupportsST3CTextures = false; // Dependent on features. config->backend_info.bSupportsBPTCTextures = false; // Dependent on features. config->backend_info.bSupportsReversedDepthRange = false; // No support yet due to driver bugs. + config->backend_info.bSupportsLogicOp = false; // Dependent on features. config->backend_info.bSupportsCopyToVram = true; // Assumed support. config->backend_info.bSupportsFramebufferFetch = false; } @@ -272,6 +273,7 @@ void VulkanContext::PopulateBackendInfoFeatures(VideoConfig* config, VkPhysicalD config->backend_info.bSupportsBBox = config->backend_info.bSupportsFragmentStoresAndAtomics = (features.fragmentStoresAndAtomics == VK_TRUE); config->backend_info.bSupportsSSAA = (features.sampleRateShading == VK_TRUE); + config->backend_info.bSupportsLogicOp = (features.logicOp == VK_TRUE); // Disable geometry shader when shaderTessellationAndGeometryPointSize is not supported. // Seems this is needed for gl_Layer. diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index aae881a0f1..da648b3ba6 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -338,13 +338,15 @@ PixelShaderUid GetPixelShaderUid() return out; } -void ClearUnusedPixelShaderUidBits(APIType ApiType, PixelShaderUid* uid) +void ClearUnusedPixelShaderUidBits(APIType ApiType, const ShaderHostConfig& host_config, + PixelShaderUid* uid) { pixel_shader_uid_data* uid_data = uid->GetUidData(); // OpenGL and Vulkan convert implicitly normalized color outputs to their uint representation. - // Therefore, it is not necessary to use a uint output on these backends. - if (ApiType != APIType::D3D) + // Therefore, it is not necessary to use a uint output on these backends. We also disable the + // uint output when logic op is not supported (i.e. driver/device does not support D3D11.1). + if (ApiType != APIType::D3D || !host_config.backend_logic_op) uid_data->uint_output = 0; } diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h index 2e630e2e49..da5137b8cb 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.h +++ b/Source/Core/VideoCommon/PixelShaderGen.h @@ -168,5 +168,6 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host const pixel_shader_uid_data* uid_data); void WritePixelShaderCommonHeader(ShaderCode& out, APIType ApiType, u32 num_texgens, bool per_pixel_lighting, bool bounding_box); -void ClearUnusedPixelShaderUidBits(APIType ApiType, PixelShaderUid* uid); +void ClearUnusedPixelShaderUidBits(APIType ApiType, const ShaderHostConfig& host_config, + PixelShaderUid* uid); PixelShaderUid GetPixelShaderUid(); diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index 6ab6f17fa5..13b1bfc0fc 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -456,12 +456,15 @@ std::optional ShaderCache::GetGXPipelineConfig(const GXP else vs = InsertVertexShader(config.vs_uid, CompileVertexShader(config.vs_uid)); + PixelShaderUid ps_uid = config.ps_uid; + ClearUnusedPixelShaderUidBits(m_api_type, m_host_config, &ps_uid); + const AbstractShader* ps; - auto ps_iter = m_ps_cache.shader_map.find(config.ps_uid); + auto ps_iter = m_ps_cache.shader_map.find(ps_uid); if (ps_iter != m_ps_cache.shader_map.end() && !ps_iter->second.pending) ps = ps_iter->second.shader.get(); else - ps = InsertPixelShader(config.ps_uid, CompilePixelShader(config.ps_uid)); + ps = InsertPixelShader(ps_uid, CompilePixelShader(ps_uid)); if (!vs || !ps) return {}; @@ -492,12 +495,15 @@ ShaderCache::GetGXUberPipelineConfig(const GXUberPipelineUid& config) else vs = InsertVertexUberShader(config.vs_uid, CompileVertexUberShader(config.vs_uid)); + UberShader::PixelShaderUid ps_uid = config.ps_uid; + UberShader::ClearUnusedPixelShaderUidBits(m_api_type, m_host_config, &ps_uid); + const AbstractShader* ps; - auto ps_iter = m_uber_ps_cache.shader_map.find(config.ps_uid); + auto ps_iter = m_uber_ps_cache.shader_map.find(ps_uid); if (ps_iter != m_uber_ps_cache.shader_map.end() && !ps_iter->second.pending) ps = ps_iter->second.shader.get(); else - ps = InsertPixelUberShader(config.ps_uid, CompilePixelUberShader(config.ps_uid)); + ps = InsertPixelUberShader(ps_uid, CompilePixelUberShader(ps_uid)); if (!vs || !ps) return {}; @@ -802,10 +808,13 @@ void ShaderCache::QueuePipelineCompile(const GXPipelineUid& uid, u32 priority) if (vs_it == shader_cache->m_vs_cache.shader_map.end()) shader_cache->QueueVertexShaderCompile(uid.vs_uid, priority); - auto ps_it = shader_cache->m_ps_cache.shader_map.find(uid.ps_uid); + PixelShaderUid ps_uid = uid.ps_uid; + ClearUnusedPixelShaderUidBits(shader_cache->m_api_type, shader_cache->m_host_config, &ps_uid); + + auto ps_it = shader_cache->m_ps_cache.shader_map.find(ps_uid); stages_ready &= ps_it != shader_cache->m_ps_cache.shader_map.end() && !ps_it->second.pending; if (ps_it == shader_cache->m_ps_cache.shader_map.end()) - shader_cache->QueuePixelShaderCompile(uid.ps_uid, priority); + shader_cache->QueuePixelShaderCompile(ps_uid, priority); return stages_ready; } @@ -870,11 +879,15 @@ void ShaderCache::QueueUberPipelineCompile(const GXUberPipelineUid& uid, u32 pri if (vs_it == shader_cache->m_uber_vs_cache.shader_map.end()) shader_cache->QueueVertexUberShaderCompile(uid.vs_uid, priority); - auto ps_it = shader_cache->m_uber_ps_cache.shader_map.find(uid.ps_uid); + UberShader::PixelShaderUid ps_uid = uid.ps_uid; + UberShader::ClearUnusedPixelShaderUidBits(shader_cache->m_api_type, + shader_cache->m_host_config, &ps_uid); + + auto ps_it = shader_cache->m_uber_ps_cache.shader_map.find(ps_uid); stages_ready &= ps_it != shader_cache->m_uber_ps_cache.shader_map.end() && !ps_it->second.pending; if (ps_it == shader_cache->m_uber_ps_cache.shader_map.end()) - shader_cache->QueuePixelUberShaderCompile(uid.ps_uid, priority); + shader_cache->QueuePixelUberShaderCompile(ps_uid, priority); return stages_ready; } diff --git a/Source/Core/VideoCommon/ShaderGenCommon.cpp b/Source/Core/VideoCommon/ShaderGenCommon.cpp index b4cf9e9a48..54d87691de 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.cpp +++ b/Source/Core/VideoCommon/ShaderGenCommon.cpp @@ -33,6 +33,7 @@ ShaderHostConfig ShaderHostConfig::GetCurrent() bits.backend_dynamic_sampler_indexing = g_ActiveConfig.backend_info.bSupportsDynamicSamplerIndexing; bits.backend_shader_framebuffer_fetch = g_ActiveConfig.backend_info.bSupportsFramebufferFetch; + bits.backend_logic_op = g_ActiveConfig.backend_info.bSupportsLogicOp; return bits; } diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index ad5604127c..85534b164b 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -180,7 +180,8 @@ union ShaderHostConfig u32 backend_bitfield : 1; u32 backend_dynamic_sampler_indexing : 1; u32 backend_shader_framebuffer_fetch : 1; - u32 pad : 11; + u32 backend_logic_op : 1; + u32 pad : 10; }; static ShaderHostConfig GetCurrent(); diff --git a/Source/Core/VideoCommon/UberShaderPixel.cpp b/Source/Core/VideoCommon/UberShaderPixel.cpp index 4b680fee2e..9c9630886a 100644 --- a/Source/Core/VideoCommon/UberShaderPixel.cpp +++ b/Source/Core/VideoCommon/UberShaderPixel.cpp @@ -29,13 +29,15 @@ PixelShaderUid GetPixelShaderUid() return out; } -void ClearUnusedPixelShaderUidBits(APIType ApiType, PixelShaderUid* uid) +void ClearUnusedPixelShaderUidBits(APIType ApiType, const ShaderHostConfig& host_config, + PixelShaderUid* uid) { pixel_ubershader_uid_data* uid_data = uid->GetUidData(); // OpenGL and Vulkan convert implicitly normalized color outputs to their uint representation. - // Therefore, it is not necessary to use a uint output on these backends. - if (ApiType != APIType::D3D) + // Therefore, it is not necessary to use a uint output on these backends. We also disable the + // uint output when logic op is not supported (i.e. driver/device does not support D3D11.1). + if (ApiType != APIType::D3D || !host_config.backend_logic_op) uid_data->uint_output = 0; } diff --git a/Source/Core/VideoCommon/UberShaderPixel.h b/Source/Core/VideoCommon/UberShaderPixel.h index 5bacf68a43..344cc4e032 100644 --- a/Source/Core/VideoCommon/UberShaderPixel.h +++ b/Source/Core/VideoCommon/UberShaderPixel.h @@ -29,5 +29,6 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config, const pixel_ubershader_uid_data* uid_data); void EnumeratePixelShaderUids(const std::function& callback); -void ClearUnusedPixelShaderUidBits(APIType ApiType, PixelShaderUid* uid); +void ClearUnusedPixelShaderUidBits(APIType ApiType, const ShaderHostConfig& host_config, + PixelShaderUid* uid); } diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 03ccfca3ba..c8a9e90638 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -201,6 +201,7 @@ struct VideoConfig final bool bSupportsFragmentStoresAndAtomics; // a.k.a. OpenGL SSBOs a.k.a. Direct3D UAVs bool bSupportsDepthClamp; // Needed by VertexShaderGen, so must stay in VideoCommon bool bSupportsReversedDepthRange; + bool bSupportsLogicOp; bool bSupportsMultithreading; bool bSupportsGPUTextureDecoding; bool bSupportsST3CTextures;