Skip to content

Commit 92cdd07

Browse files
committed
Enhancements to enable High Dynamic Range (HDR) processing
Introducing support for SDR-to-HDR switching in the hardware composer (HWC) of the display system. Enhancements include pipeline updates, the addition of degamma/gamma Look-Up Table (LUT) handling, and support for building HDR metadata, gamma transformations, and color space conversions. Additionally, the patch refactors code to adjust HDR property management and integrates new classes and utility methods for HDR processing. Key aspects of the patch include: Added HdrPipeline module to handle HDR-specific degamma, gamma, and color matrix operations. Updated DrmAtomicStateManager to support HDR properties, degamma/gamma LUT blobs, and relevant atomic properties during frame commits. Enhanced the HwcDisplay class to manage HDR metadata, degamma/gamma LUTs, HDR activation states, and to support the configuration of HDR output metadata. Fixed the issue where HDR settings weren't being properly cleared during SDR mode, resolving transition errors. Tracked-On: OAM-134123 Change-Id: Iad06253762c0f6245cfe425e799ae9758d162782 Signed-off-by: Kanli Hu <kanli.hu@intel.com>
1 parent ee308c2 commit 92cdd07

File tree

11 files changed

+301
-41
lines changed

11 files changed

+301
-41
lines changed

Android.bp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ filegroup {
8686
"drm/DrmMode.cpp",
8787
"drm/DrmPlane.cpp",
8888
"drm/DrmProperty.cpp",
89+
"drm/HdrPipeline.cpp",
8990
"drm/ResourceManager.cpp",
9091
"drm/UEventListener.cpp",
9192
"drm/VSyncWorker.cpp",

drm/DrmAtomicStateManager.cpp

Lines changed: 103 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@
1818

1919
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
2020
#define LOG_TAG "drmhwc"
21+
#include "DrmAtomicStateManager.h"
2122
#include <drm/drm_fourcc.h>
2223
#include <cmath>
23-
#include "DrmAtomicStateManager.h"
2424

2525
#include <drm/drm_mode.h>
2626
#include <sync/sync.h>
2727
#include <utils/Trace.h>
28-
#include "utils/intel_blit.h"
2928
#include <cassert>
29+
#include "utils/intel_blit.h"
3030

3131
#include "drm/DrmCrtc.h"
3232
#include "drm/DrmDevice.h"
@@ -132,20 +132,6 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
132132
}
133133
}
134134

135-
if (args.color_matrix && crtc->GetCtmProperty()) {
136-
auto blob = drm->RegisterUserPropertyBlob(args.color_matrix.get(),
137-
sizeof(drm_color_ctm));
138-
new_frame_state.ctm_blob = std::move(blob);
139-
140-
if (!new_frame_state.ctm_blob) {
141-
ALOGE("Failed to create CTM blob");
142-
return -EINVAL;
143-
}
144-
145-
if (!crtc->GetCtmProperty().AtomicSet(*pset, *new_frame_state.ctm_blob))
146-
return -EINVAL;
147-
}
148-
149135
if (args.colorspace && connector->GetColorspaceProperty()) {
150136
if (!connector->GetColorspaceProperty()
151137
.AtomicSet(*pset, connector->GetColorspacePropertyValue(
@@ -159,21 +145,89 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
159145
return -EINVAL;
160146
}
161147

162-
if (args.hdr_metadata && connector->GetHdrOutputMetadataProperty()) {
163-
auto blob = drm->RegisterUserPropertyBlob(args.hdr_metadata.get(),
164-
sizeof(hdr_output_metadata));
165-
new_frame_state.hdr_metadata_blob = std::move(blob);
166-
if (!new_frame_state.hdr_metadata_blob) {
167-
ALOGE("Failed to create %s blob",
168-
connector->GetHdrOutputMetadataProperty().GetName().c_str());
148+
if (connector->GetHdrOutputMetadataProperty()) {
149+
if (args.hdr_metadata) {
150+
auto blob = drm->RegisterUserPropertyBlob(args.hdr_metadata.get(),
151+
sizeof(hdr_output_metadata));
152+
new_frame_state.hdr_metadata_blob = std::move(blob);
153+
if (!new_frame_state.hdr_metadata_blob) {
154+
ALOGE("Failed to create %s blob",
155+
connector->GetHdrOutputMetadataProperty().GetName().c_str());
156+
return -EINVAL;
157+
}
158+
159+
if (!connector->GetHdrOutputMetadataProperty()
160+
.AtomicSet(*pset, *new_frame_state.hdr_metadata_blob))
161+
return -EINVAL;
162+
} else {
163+
if (!connector->GetHdrOutputMetadataProperty().AtomicSet(*pset, 0))
164+
return -EINVAL;
165+
}
166+
}
167+
168+
if (args.color_matrix && crtc->GetCtmProperty()) {
169+
auto blob = drm->RegisterUserPropertyBlob(args.color_matrix.get(),
170+
sizeof(drm_color_ctm));
171+
new_frame_state.ctm_blob = std::move(blob);
172+
173+
if (!new_frame_state.ctm_blob) {
174+
ALOGE("Failed to create CTM blob");
169175
return -EINVAL;
170176
}
171177

172-
if (!connector->GetHdrOutputMetadataProperty()
173-
.AtomicSet(*pset, *new_frame_state.hdr_metadata_blob))
178+
if (!crtc->GetCtmProperty().AtomicSet(*pset, *new_frame_state.ctm_blob))
174179
return -EINVAL;
175180
}
176181

182+
// HDR pipeline handling (degamma -> CTM -> gamma)
183+
// CTM matrix is set above
184+
{
185+
// Build blobs for degamma
186+
if (crtc->GetDeGammaLutProperty()) {
187+
if (args.degamma_lut) {
188+
auto blob = drm->RegisterUserPropertyBlob(args.degamma_lut->data(),
189+
args.degamma_lut->size() *
190+
sizeof(drm_color_lut));
191+
new_frame_state.degamma_blob = std::move(blob);
192+
if (!new_frame_state.degamma_blob) {
193+
ALOGE("Failed to create %s blob",
194+
crtc->GetDeGammaLutProperty().GetName().c_str());
195+
return -EINVAL;
196+
}
197+
198+
if (!crtc->GetDeGammaLutProperty()
199+
.AtomicSet(*pset, *new_frame_state.degamma_blob))
200+
return -EINVAL;
201+
} else {
202+
if (crtc->GetDeGammaLutProperty() &&
203+
!crtc->GetDeGammaLutProperty().AtomicSet(*pset, 0))
204+
return -EINVAL;
205+
}
206+
}
207+
// Output gamma PQ
208+
if (crtc->GetGammaLutProperty()) {
209+
if (args.gamma_lut) {
210+
auto blob = drm->RegisterUserPropertyBlob(args.gamma_lut->data(),
211+
args.gamma_lut->size() *
212+
sizeof(drm_color_lut));
213+
new_frame_state.gamma_blob = std::move(blob);
214+
if (!new_frame_state.gamma_blob) {
215+
ALOGE("Failed to create %s blob",
216+
crtc->GetGammaLutProperty().GetName().c_str());
217+
return -EINVAL;
218+
}
219+
220+
if (!crtc->GetGammaLutProperty().AtomicSet(*pset,
221+
*new_frame_state.gamma_blob))
222+
return -EINVAL;
223+
} else {
224+
if (crtc->GetGammaLutProperty() &&
225+
!crtc->GetGammaLutProperty().AtomicSet(*pset, 0))
226+
return -EINVAL;
227+
}
228+
}
229+
}
230+
177231
auto unused_planes = new_frame_state.used_planes;
178232

179233
if (args.composition) {
@@ -244,6 +298,10 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
244298
flags |= DRM_MODE_ATOMIC_NONBLOCK;
245299
}
246300

301+
if (args.hdr_enabled) {
302+
args.color_adjustment = false;
303+
}
304+
247305
if (args.color_adjustment == true) {
248306
SetColorSaturationHue();
249307
SetColorBrightnessContrast();
@@ -709,6 +767,26 @@ auto DrmAtomicStateManager::ApplyPendingLUT(struct drm_color_lut *lut, uint64_t
709767
return 0;
710768
}
711769

770+
auto DrmAtomicStateManager::ApplyPendingDeLUT(struct drm_color_lut *lut, uint64_t lut_size) -> int {
771+
uint32_t lut_blob_id = 0;
772+
if (pipe_->crtc->Get()->GetDeGammaLutProperty().id() == 0) {
773+
ALOGE("GetDeGammaLutProperty().id() == 0");
774+
return -EINVAL;
775+
}
776+
777+
drmModeCreatePropertyBlob(
778+
*(pipe_->device->GetFd()), lut, sizeof(struct drm_color_lut) * lut_size, &lut_blob_id);
779+
if (lut_blob_id == 0) {
780+
ALOGE("COLOR_ lut_blob_id == 0");
781+
return -EINVAL;
782+
}
783+
784+
drmModeObjectSetProperty(*(pipe_->device->GetFd()), pipe_->crtc->Get()->GetId(), DRM_MODE_OBJECT_CRTC,
785+
pipe_->crtc->Get()->GetDeGammaLutProperty().id(), lut_blob_id);
786+
drmModeDestroyPropertyBlob(*(pipe_->device->GetFd()), lut_blob_id);
787+
return 0;
788+
}
789+
712790
auto DrmAtomicStateManager::SetColorSaturationHue(void) ->int{
713791
double color_transform_matrix[16] = {1.0, 0.0, 0.0, 0.0,
714792
0.0, 1.0, 0.0, 0.0,

drm/DrmAtomicStateManager.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,18 @@ struct AtomicCommitArgs {
3838
std::optional<DrmMode> display_mode;
3939
std::optional<bool> active;
4040
std::shared_ptr<DrmKmsPlan> composition;
41-
std::shared_ptr<drm_color_ctm> color_matrix;
4241
std::optional<Colorspace> colorspace;
4342
std::optional<int32_t> content_type;
4443
std::shared_ptr<hdr_output_metadata> hdr_metadata;
4544
bool color_adjustment = false;
4645
std::shared_ptr<DrmFbIdHandle> writeback_fb;
4746
SharedFd writeback_release_fence;
4847

48+
bool hdr_enabled = false;
49+
std::shared_ptr<std::vector<drm_color_lut>> degamma_lut;
50+
std::shared_ptr<std::vector<drm_color_lut>> gamma_lut;
51+
std::shared_ptr<drm_color_ctm> color_matrix;
52+
4953
/* out */
5054
SharedFd out_fence;
5155

@@ -81,6 +85,8 @@ class DrmAtomicStateManager {
8185
uint32_t contrast_c,
8286
uint32_t brightness_c) ->int;
8387
auto ApplyPendingLUT(struct drm_color_lut *lut, uint64_t lut_size) -> int;
88+
auto ApplyPendingDeLUT(struct drm_color_lut *lut, uint64_t lut_size) -> int;
89+
8490
void StopThread() {
8591
{
8692
const std::unique_lock lock(mutex_);
@@ -105,7 +111,8 @@ class DrmAtomicStateManager {
105111
DrmModeUserPropertyBlobUnique mode_blob;
106112
DrmModeUserPropertyBlobUnique ctm_blob;
107113
DrmModeUserPropertyBlobUnique hdr_metadata_blob;
108-
114+
DrmModeUserPropertyBlobUnique degamma_blob;
115+
DrmModeUserPropertyBlobUnique gamma_blob;
109116
int release_fence_pt_index{};
110117

111118
/* To avoid setting the inactive state twice, which will fail the commit */

drm/DrmCrtc.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include "DrmDevice.h"
2727
#include "DrmVirtgpu.h"
28+
#include "utils/properties.h"
2829
namespace android {
2930

3031
static int GetCrtcProperty(const DrmDevice &dev, const DrmCrtc &crtc,
@@ -61,7 +62,8 @@ auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
6162
return {};
6263
}
6364

64-
if (dev.GetColorAdjustmentEnabling()) {
65+
if (dev.GetColorAdjustmentEnabling() ||
66+
Properties::EnableHdrDisplay()) {
6567
ret = GetCrtcProperty(dev, *c, "CTM", &c->ctm_property_);
6668
if (ret != 0) {
6769
ALOGV("Missing optional CTM property");
@@ -78,6 +80,16 @@ auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
7880
ALOGE("Failed to get GAMMA_LUT_SIZE property");
7981
return {};
8082
}
83+
84+
ret = GetCrtcProperty(dev, *c, "DEGAMMA_LUT", &c->de_gamma_lut_property_);
85+
if (ret != 0) {
86+
ALOGE("Failed to get DEGAMMA_LUT property");
87+
}
88+
89+
ret = GetCrtcProperty(dev, *c, "DEGAMMA_LUT_SIZE", &c->de_gamma_lut_size_property_);
90+
if (ret != 0) {
91+
ALOGE("Failed to get DEGAMMA_LUT_SIZE property");
92+
}
8193
}
8294

8395
if (dev.GetName() == "virtio_gpu") {

drm/DrmCrtc.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,13 @@ class DrmCrtc : public PipelineBindable<DrmCrtc> {
7676
auto &GetGammaLutSizeProperty() const {
7777
return gamma_lut_size_property_;
7878
}
79+
auto &GetDeGammaLutProperty() const {
80+
return de_gamma_lut_property_;
81+
}
7982

83+
auto &GetDeGammaLutSizeProperty() const {
84+
return de_gamma_lut_size_property_;
85+
}
8086
bool GetAllowP2P() const {
8187
return allow_p2p_;
8288
}
@@ -91,6 +97,8 @@ class DrmCrtc : public PipelineBindable<DrmCrtc> {
9197
DrmProperty ctm_property_;
9298
DrmProperty gamma_lut_property_;
9399
DrmProperty gamma_lut_size_property_;
100+
DrmProperty de_gamma_lut_property_;
101+
DrmProperty de_gamma_lut_size_property_;
94102
DrmProperty active_property_;
95103
DrmProperty mode_property_;
96104
DrmProperty out_fence_ptr_property_;

drm/HdrPipeline.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#include "HdrPipeline.h"
2+
#include <xf86drmMode.h>
3+
#include <xf86drm.h>
4+
#include <math.h>
5+
6+
std::vector<drm_color_lut> HdrPipeline::BuildSrgbDegamma(uint64_t size) {
7+
std::vector<drm_color_lut> lut(size);
8+
if (size < 2) return lut;
9+
for (uint64_t i = 0; i < size; ++i) {
10+
double e = double(i) / double(size - 1);
11+
double l = (e <= 0.04045) ? (e / 12.92) : std::pow((e + 0.055) / 1.055, 2.4);
12+
uint16_t v = static_cast<uint16_t>(std::lround(std::clamp(l, 0.0, 1.0) * 65535.0));
13+
lut[i].red = lut[i].green = lut[i].blue = v;
14+
}
15+
return lut;
16+
}
17+
18+
std::vector<drm_color_lut> HdrPipeline::BuildPqGamma(uint64_t size,
19+
float max_luminance, float max_average_luminance,
20+
float min_luminance) {
21+
std::vector<drm_color_lut> lut(size);
22+
if (size < 2) return lut;
23+
24+
// Clamp inputs
25+
max_luminance = std::max(1.0f, max_luminance);
26+
max_average_luminance = std::max(1.0f, std::min(max_average_luminance, max_luminance));
27+
min_luminance = std::max(0.0f, std::min(min_luminance, max_average_luminance));
28+
29+
// ST2084 constants
30+
const double m1 = 2610.0 / 16384.0;
31+
const double m2 = 2523.0 / 32.0;
32+
const double c1 = 3424.0 / 4096.0;
33+
const double c2 = 2413.0 / 128.0;
34+
const double c3 = 2392.0 / 128.0;
35+
36+
// Peak mapping: LUT 1.0 corresponds to panel peak (max_luminance)
37+
// Tone map (knee) above max_average_luminance
38+
const double knee_start = max_average_luminance;
39+
const double knee_end = max_luminance;
40+
const double knee_range = std::max(1e-6, knee_end - knee_start);
41+
42+
for (uint64_t i = 0; i < size; ++i) {
43+
double r = double(i) / double(size - 1); // 0..1 scene relative
44+
// Map to physical luminance range
45+
double L_scene = min_luminance + r * (max_luminance - min_luminance);
46+
47+
// Knee compression (Reinhard-like)
48+
if (L_scene > knee_start) {
49+
double x = (L_scene - knee_start) / knee_range; // 0..1
50+
// Smooth compression: y = x / (1 + x) keeps derivatives finite
51+
double comp = x / (1.0 + x);
52+
L_scene = knee_start + comp * knee_range;
53+
}
54+
55+
// Normalize to PQ absolute range (0..10000 nits)
56+
double L_norm = std::clamp(L_scene / 10000.0, 0.0, 1.0);
57+
58+
// ST2084 OETF
59+
double num = c1 + c2 * std::pow(L_norm, m1);
60+
double den = 1.0 + c3 * std::pow(L_norm, m1);
61+
double pq = std::pow(num / den, m2);
62+
63+
uint16_t v = static_cast<uint16_t>(std::lround(std::clamp(pq, 0.0, 1.0) * 65535.0));
64+
lut[i].red = lut[i].green = lut[i].blue = v;
65+
}
66+
67+
// Ensure LUT[0] == 0
68+
lut[0].red = lut[0].green = lut[0].blue = 0;
69+
return lut;
70+
}
71+
72+
std::shared_ptr<drm_color_ctm> HdrPipeline::BuildCtm709To2020() {
73+
// Approximate Rec.709 -> Rec.2020 conversion matrix
74+
double m[3][3] = {
75+
{0.627404, 0.329282, 0.043313},
76+
{0.069097, 0.919540, 0.011360},
77+
{0.016391, 0.088013, 0.895595}
78+
};
79+
auto ctm = std::make_shared<drm_color_ctm>();
80+
for (int i = 0; i < 3; ++i) {
81+
for (int j = 0; j < 3; ++j) {
82+
double v = m[i][j];
83+
int64_t fp = (int64_t)llround(std::fabs(v) * (1LL << 32));
84+
if (v < 0) fp |= (1ULL << 63);
85+
ctm->matrix[i * 3 + j] = (uint64_t)fp;
86+
}
87+
}
88+
return ctm;
89+
}

drm/HdrPipeline.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
#include <vector>
3+
#include <stdint.h>
4+
#include <drm_mode.h>
5+
6+
class HdrPipeline {
7+
public:
8+
9+
static std::vector<drm_color_lut> BuildSrgbDegamma(uint64_t size);
10+
static std::vector<drm_color_lut> BuildPqGamma(uint64_t size,
11+
float max_luminance, float max_average_luminance,
12+
float min_luminance);
13+
static std::shared_ptr<drm_color_ctm> BuildCtm709To2020();
14+
};

0 commit comments

Comments
 (0)