Skip to content

Commit

Permalink
Fix the issue that the builtin display remains garbled after the syst…
Browse files Browse the repository at this point in the history
…em boots on ICL platforms (#92)
  • Loading branch information
0xFireWolf committed Oct 2, 2021
1 parent 7d632c5 commit 3c9a77e
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 4 deletions.
3 changes: 3 additions & 0 deletions 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)
Expand Down
15 changes: 15 additions & 0 deletions Manual/FAQ.IntelHD.cn.md
Expand Up @@ -2021,6 +2021,21 @@ igfx: @ (DBG) BLS: [COMM] Processing the request: Current = 0x00014ead; Target =

</details>

## 修复 Ice Lake 平台上笔记本开机持续花屏7到15秒的问题

为核显添加 `enable-dbuf-early-optimizer` 属性或者直接使用 `-igfxdbeo` 启动参数以修复 Ice Lake 笔记本开机后内屏短暂花屏的问题。
若发现内核日志记录了如下 DBUF 以及 Pipe Underrun 相关的错误信息,请启用此补丁来修复这些错误。

<details>
<summary>包含 DBUF 以及 Pipe Underrun 错误信息的内核日志</summary>

```
[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
```

</details>

## 已知问题
*兼容性*
- 受限制的显卡:HD2000 和 HD2500,它们只能用于 IQSV (因为在白苹果中它们只用来干这个),无解。
Expand Down
16 changes: 16 additions & 0 deletions Manual/FAQ.IntelHD.en.md
Expand Up @@ -2660,6 +2660,22 @@ igfx: @ (DBG) BLS: [COMM] Processing the request: Current = 0x00014ead; Target =

</details>

## 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.

<details>
<summary>Sample kernel log that contains DBUF-related errors</summary>

```
[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
```

</details>

## Known Issues

**Compatibility**
Expand Down
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -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

Expand Down Expand Up @@ -94,14 +95,15 @@ 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

- [Apple](https://www.apple.com) for macOS
- [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
Expand Down
45 changes: 42 additions & 3 deletions WhateverGreen/kern_igfx.hpp
Expand Up @@ -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
*/
Expand All @@ -1771,7 +1809,7 @@ class IGFX {
/**
* A collection of submodules
*/
PatchSubmodule *submodules[19] = {
PatchSubmodule *submodules[20] = {
&modDVMTCalcFix,
&modDPCDMaxLinkRateFix,
&modCoreDisplayClockFix,
Expand All @@ -1790,7 +1828,8 @@ class IGFX {
&modBacklightRegistersFix,
&modBacklightSmoother,
&modFramebufferDebugSupport,
&modMaxPixelClockOverride
&modMaxPixelClockOverride,
&modDisplayDataBufferEarlyOptimizer,
};

/**
Expand Down
104 changes: 104 additions & 0 deletions WhateverGreen/kern_igfx_memory.cpp
Expand Up @@ -10,6 +10,15 @@
#include <Headers/kern_util.hpp>
#include <Headers/kern_disasm.hpp>

///
/// 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;
Expand Down Expand Up @@ -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 <start, end> 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.");
}

0 comments on commit 3c9a77e

Please sign in to comment.