From 3c9a77ee1cb91acdc7d9ff9d6f8670f657039167 Mon Sep 17 00:00:00 2001
From: FireWolf <10460478+0xFireWolf@users.noreply.github.com>
Date: Sat, 2 Oct 2021 00:14:42 -0700
Subject: [PATCH] Fix the issue that the builtin display remains garbled after
the system boots on ICL platforms (#92)
---
Changelog.md | 3 +
Manual/FAQ.IntelHD.cn.md | 15 +++++
Manual/FAQ.IntelHD.en.md | 16 +++++
README.md | 4 +-
WhateverGreen/kern_igfx.hpp | 45 ++++++++++++-
WhateverGreen/kern_igfx_memory.cpp | 104 +++++++++++++++++++++++++++++
6 files changed, 183 insertions(+), 4 deletions(-)
diff --git a/Changelog.md b/Changelog.md
index fff61894..e3b73ab3 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,8 @@
WhateverGreen Changelog
=======================
+#### v1.5.4
+- Added the fix for the short period garbled screen after the system boots on Ice Lake platforms. (by @0xFireWolf, also thanks @m0d16l14n1 and @kingo132)
+
#### v1.5.3
- Added `no-gfx-spoof` to avoid forcing `device-id` values from PCI I/O.
- Added the backlight smoother submodule that makes brightness transitions smoother on Intel IVB+ platforms. (by @0xFireWolf)
diff --git a/Manual/FAQ.IntelHD.cn.md b/Manual/FAQ.IntelHD.cn.md
index 19215acf..70a72500 100644
--- a/Manual/FAQ.IntelHD.cn.md
+++ b/Manual/FAQ.IntelHD.cn.md
@@ -2021,6 +2021,21 @@ igfx: @ (DBG) BLS: [COMM] Processing the request: Current = 0x00014ead; Target =
+## 修复 Ice Lake 平台上笔记本开机持续花屏7到15秒的问题
+
+为核显添加 `enable-dbuf-early-optimizer` 属性或者直接使用 `-igfxdbeo` 启动参数以修复 Ice Lake 笔记本开机后内屏短暂花屏的问题。
+若发现内核日志记录了如下 DBUF 以及 Pipe Underrun 相关的错误信息,请启用此补丁来修复这些错误。
+
+
+包含 DBUF 以及 Pipe Underrun 错误信息的内核日志
+
+```
+[IGFB][ERROR][DISPLAY ] Display Pipe Underrun occurred on pipe(s) A
+[IGFB][ERROR][DISPLAY ] Internal cached DBuf values are not set. Failed to distribute DBufs
+```
+
+
+
## 已知问题
*兼容性*:
- 受限制的显卡:HD2000 和 HD2500,它们只能用于 IQSV (因为在白苹果中它们只用来干这个),无解。
diff --git a/Manual/FAQ.IntelHD.en.md b/Manual/FAQ.IntelHD.en.md
index 3ebb49f9..d65cc126 100644
--- a/Manual/FAQ.IntelHD.en.md
+++ b/Manual/FAQ.IntelHD.en.md
@@ -2660,6 +2660,22 @@ igfx: @ (DBG) BLS: [COMM] Processing the request: Current = 0x00014ead; Target =
+## Fix the issue that the builtin display remains garbled after the system boots on ICL platforms
+
+Add the `enable-dbuf-early-optimizer` property to `IGPU` or use the `-igfxdbeo` boot argument instead to fix the Display Data Buffer (DBUF) allocation issue on ICL platforms,
+otherwise your builtin display remains garbled for 7 to 15 seconds after the system boots.
+You need this fix if you observe a bunch of errors mentioning "DBUF" and "pipe underrun" in the kernel log.
+
+
+Sample kernel log that contains DBUF-related errors
+
+```
+[IGFB][ERROR][DISPLAY ] Display Pipe Underrun occurred on pipe(s) A
+[IGFB][ERROR][DISPLAY ] Internal cached DBuf values are not set. Failed to distribute DBufs
+```
+
+
+
## Known Issues
**Compatibility**
diff --git a/README.md b/README.md
index e85e47cd..fd7ecf5e 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,7 @@ WhateverGreen
- Supports all valid Core Display Clock (CDCLK) freqencies on Intel ICL platforms.
- Fixes the kernel panic caused by an incorrectly calculated amount of DVMT pre-allocated memory on Intel ICL platforms.
- Makes brightness transitions smoother on Intel IVB+ platforms.
+- Fixes the short period garbled screen issue after the system boots on Intel ICL platforms.
#### Documentation
@@ -94,6 +95,7 @@ indices of connectors for which online status is enforced. Format is similar to
- `-igfxblr` boot argument (and `enable-backlight-registers-fix` property) to fix backlight registers on KBL, CFL and ICL platforms.
- `-igfxmpc` boot argument (`enable-max-pixel-clock-override` and `max-pixel-clock-frequency` properties) to increase max pixel clock (as an alternative to patching CoreDisplay.framework).
- `-igfxbls` boot argument (and `enable-backlight-smoother` property) to make brightness transitions smoother on IVB+ platforms. [Read the manual](https://github.com/acidanthera/WhateverGreen/blob/master/Manual/FAQ.IntelHD.en.md#customize-the-behavior-of-the-backlight-smoother-to-improve-your-experience)
+- `-igfxdbeo` boot argument (and `enable-dbuf-early-optimizer` property) to fix the Display Data Buffer (DBUF) issues on ICL+ platforms.
#### Credits
@@ -101,7 +103,7 @@ indices of connectors for which online status is enforced. Format is similar to
- [AMD](https://www.amd.com) for ATOM VBIOS parsing code
- [The PCI ID Repository](http://pci-ids.ucw.cz) for multiple GPU model names
- [Andrey1970AppleLife](https://github.com/Andrey1970AppleLife) for [FAQs](https://github.com/acidanthera/WhateverGreen/blob/master/Manual/)
-- [FireWolf](https://github.com/0xFireWolf/) for the DPCD maximum link rate fix, infinite loop fix for Intel HDMI connections, LSPCON driver support, Core Display Clock frequency fix for ICL platforms, DVMT pre-allocated memory calculation fix for ICL platforms, and Backlight Smoother for IVB+ platforms.
+- [FireWolf](https://github.com/0xFireWolf/) for the DPCD maximum link rate fix, infinite loop fix for Intel HDMI connections, LSPCON driver support, Core Display Clock frequency fix for ICL platforms, DVMT pre-allocated memory calculation fix for ICL platforms, Backlight Smoother for IVB+ platforms, and Display Data Buffer fix for ICL platforms.
- [Floris497](https://github.com/Floris497) for the CoreDisplay [patches](https://github.com/Floris497/mac-pixel-clock-patch-v2)
- [Fraxul](https://github.com/Fraxul) for original CFL backlight patch
- [headkaze](https://github.com/headkaze) for Intel framebuffer patching code and CFL backlight patch improvements
diff --git a/WhateverGreen/kern_igfx.hpp b/WhateverGreen/kern_igfx.hpp
index b6050bb8..9075f5cd 100644
--- a/WhateverGreen/kern_igfx.hpp
+++ b/WhateverGreen/kern_igfx.hpp
@@ -1758,7 +1758,45 @@ class IGFX {
void processKernel(KernelPatcher &patcher, DeviceInfo *info) override;
void processFramebufferKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) override;
} modMaxPixelClockOverride;
-
+
+ /**
+ * A submodule to optimize the display data buffer position earlier to solve the 10-second flicker issue on ICL+
+ */
+ class DisplayDataBufferEarlyOptimizer: public PatchSubmodule {
+ /**
+ * The feature control key
+ */
+ static constexpr const char* kFeatureControl = "FeatureControl";
+
+ /**
+ * The display data buffer optimizer delay key
+ */
+ static constexpr const char* kOptimizerTime = "DBUFOptimizeTime";
+
+ /**
+ * Specify the amount of time in seconds to delay the execution of optimizing the display data buffer allocation
+ */
+ uint32_t optimizerTime {0};
+
+ /**
+ * Original AppleIntelFramebufferController::getFeatureControl function
+ */
+ void (*orgGetFeatureControl)(IOService *controller) {nullptr};
+
+ /**
+ * Fetch and load the featuer control information
+ *
+ * @param controller The hidden implicit `this` pointer
+ */
+ static void wrapGetFeatureControl(IOService *controller);
+
+ public:
+ // MARK: Patch Submodule IMP
+ void init() override;
+ void processKernel(KernelPatcher &patcher, DeviceInfo *info) override;
+ void processFramebufferKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) override;
+ } modDisplayDataBufferEarlyOptimizer;
+
/**
* A collection of shared submodules
*/
@@ -1771,7 +1809,7 @@ class IGFX {
/**
* A collection of submodules
*/
- PatchSubmodule *submodules[19] = {
+ PatchSubmodule *submodules[20] = {
&modDVMTCalcFix,
&modDPCDMaxLinkRateFix,
&modCoreDisplayClockFix,
@@ -1790,7 +1828,8 @@ class IGFX {
&modBacklightRegistersFix,
&modBacklightSmoother,
&modFramebufferDebugSupport,
- &modMaxPixelClockOverride
+ &modMaxPixelClockOverride,
+ &modDisplayDataBufferEarlyOptimizer,
};
/**
diff --git a/WhateverGreen/kern_igfx_memory.cpp b/WhateverGreen/kern_igfx_memory.cpp
index 4af9e8d3..a4b0facd 100644
--- a/WhateverGreen/kern_igfx_memory.cpp
+++ b/WhateverGreen/kern_igfx_memory.cpp
@@ -10,6 +10,15 @@
#include
#include
+///
+/// This file contains the following memory-related fixes
+///
+/// 1. DVMT calculation fix on ICL+.
+/// 2. Display data buffer early optimizer on ICL+.
+///
+
+// MARK: - DVMT Pre-allocated Memory Calculation Fix
+
void IGFX::DVMTCalcFix::init() {
// We only need to patch the framebuffer driver
requiresPatchingGraphics = false;
@@ -206,3 +215,98 @@ void IGFX::DVMTCalcFix::processFramebufferKext(KernelPatcher &patcher, size_t in
SYSLOG("igfx", "DVMT: Failed to find instructions of interest. Aborted patching.");
}
+// MARK: - Display Data Buffer Early Optimizer
+
+void IGFX::DisplayDataBufferEarlyOptimizer::wrapGetFeatureControl(IOService *controller) {
+ //
+ // Abstract
+ //
+ // Display Data Buffer (DBUF) is critical for display pipes and planes to function properly.
+ // The graphics driver allocates the buffer by writing a pair to the plane buffer configuration register.
+ // Apple expects that the firmware has allocated an adequate amount of buffer for the Pipe A that drives the builtin display,
+ // so the driver can optimize the allocation later to provide better display residency in memory low power modes.
+ // However, the buffer allocated by the BIOS on Ice Lake-based laptops seems to be not enough for the plane running in the mode configured by the driver,
+ // resulting in a garbled display that lasts for about 7 to 15 seconds when the system finishes booting and presents the login window.
+ // This issue will disappear when the function that optimizes the buffer allocation is fired by a timer enabled at the end of mode setting.
+ // The default delay of executing the optimizer function is 15 seconds which is hard-coded in the framebuffer controller's startup routine.
+ // Fortunately, we can change the delay by injecting the property "DBUFOptimizeTime" to the feature control dictionary.
+ // By specifying a delay of 0 second, we can invoke the optimizer function as soon as the graphics driver completes the modeset for the builtin display,
+ // thus fixing the garbled builtin screen issue on Ice Lake platforms without having any negative impacts on external monitors.
+ //
+ // Future Work
+ //
+ // Ideally, we should be able to increase the buffer allocation at an early boot stage,
+ // just like how we fix the Core Display Clock issue on Ice Lake platforms.
+ // However, I am still trying to figure out where the best place is to inject the code properly.
+ //
+ // Acknowledgements
+ //
+ // I would like to acknowledge @m0d16l14n1's passion and insistence on this annoying issue since Sep, 2020,
+ // and @kingo123 for implementing the proof-of-concept code showing that @m0d16l14n1's direction is correct.
+ // Your findings motivate me to resume this research on the display data buffer issue and find the root cause.
+ //
+ // - FireWolf
+ // - 2021.10
+ //
+ auto module = &callbackIGFX->modDisplayDataBufferEarlyOptimizer;
+
+ do {
+ // Guard: Fetch the current feature control dictionary
+ auto features = OSDynamicCast(OSDictionary, controller->getProperty(kFeatureControl));
+ if (features == nullptr) {
+ SYSLOG("igfx", "DBEO: Failed to fetch the feature control dictionary.");
+ break;
+ }
+
+ auto clonedFeatures = features->copyCollection();
+ if (clonedFeatures == nullptr) {
+ SYSLOG("igfx", "DBEO: Failed to clone the feature control dictionary.");
+ break;
+ }
+
+ auto newFeatures = OSDynamicCast(OSDictionary, clonedFeatures);
+ PANIC_COND(newFeatures == nullptr, "igfx", "DBEO: The cloned collection is not a dictionary.");
+
+ // Allocate the new optimizer delay
+ auto delay = OSNumber::withNumber(module->optimizerTime, 32);
+ if (delay == nullptr) {
+ SYSLOG("igfx", "DBEO: Failed to allocate the new optimizer delay.");
+ newFeatures->release();
+ break;
+ }
+
+ // Set the new optimizer delay
+ newFeatures->setObject(kOptimizerTime, delay);
+ controller->setProperty(kFeatureControl, newFeatures);
+ delay->release();
+ newFeatures->release();
+ DBGLOG("igfx", "DBEO: The new optimizer value has been set to %u.", module->optimizerTime);
+ } while (false);
+
+ module->orgGetFeatureControl(controller);
+}
+
+void IGFX::DisplayDataBufferEarlyOptimizer::init() {
+ // We only need to patch the framebuffer driver
+ requiresPatchingGraphics = false;
+ requiresPatchingFramebuffer = true;
+}
+
+void IGFX::DisplayDataBufferEarlyOptimizer::processKernel(KernelPatcher &patcher, DeviceInfo *info) {
+ // Enable the fix if the corresponding boot argument is found
+ enabled = checkKernelArgument("-igfxdbeo");
+ // Of if "enable-dbuf-early-optimizer" is set in IGPU property
+ if (!enabled)
+ enabled = info->videoBuiltin->getProperty("enable-dbuf-early-optimizer") != nullptr;
+ if (!enabled)
+ return;
+
+ // Fetch the user configuration
+ if (WIOKit::getOSDataValue(info->videoBuiltin, "dbuf-optimizer-delay", optimizerTime))
+ DBGLOG("igfx", "DBEO: User requested optimizer delay = %u.", optimizerTime);
+}
+
+void IGFX::DisplayDataBufferEarlyOptimizer::processFramebufferKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) {
+ KernelPatcher::RouteRequest request("__ZN31AppleIntelFramebufferController17getFeatureControlEv", wrapGetFeatureControl, orgGetFeatureControl);
+ SYSLOG_COND(!patcher.routeMultiple(index, &request, 1, address, size), "igfx", "DBEO: Failed to route the function.");
+}