Merge "hwc2: Fix NULL pointer dereference and out of bound access"
diff --git a/libgralloc1/gr_buf_mgr.cpp b/libgralloc1/gr_buf_mgr.cpp
index d78cc94..35c4b02 100644
--- a/libgralloc1/gr_buf_mgr.cpp
+++ b/libgralloc1/gr_buf_mgr.cpp
@@ -540,6 +540,10 @@
int format = va_arg(args, int);
native_handle_t **handle = va_arg(args, native_handle_t **);
+ if (!handle) {
+ return GRALLOC1_ERROR_BAD_HANDLE;
+ }
+
private_handle_t *hnd = reinterpret_cast<private_handle_t *>(
native_handle_create(private_handle_t::kNumFds, private_handle_t::NumInts()));
if (hnd) {
@@ -549,7 +553,7 @@
hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION;
hnd->size = size;
hnd->offset = offset;
- hnd->base = uint64_t(base) + offset;
+ hnd->base = uint64_t(base);
hnd->gpuaddr = 0;
BufferInfo info(width, height, format);
GetAlignedWidthAndHeight(info, &alignedw, &alignedh);
@@ -567,6 +571,11 @@
int format = va_arg(args, int);
int *stride = va_arg(args, int *);
unsigned int alignedw = 0, alignedh = 0;
+
+ if (!stride) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
BufferInfo info(width, width, format);
GetAlignedWidthAndHeight(info, &alignedw, &alignedh);
*stride = INT(alignedw);
@@ -579,6 +588,10 @@
return GRALLOC1_ERROR_BAD_HANDLE;
}
+ if (!stride) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
BufferDim_t buffer_dim;
if (getMetaData(hnd, GET_BUFFER_GEOMETRY, &buffer_dim) == 0) {
*stride = buffer_dim.sliceWidth;
@@ -596,6 +609,10 @@
return GRALLOC1_ERROR_BAD_HANDLE;
}
+ if (!stride || !height) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
BufferDim_t buffer_dim;
int interlaced = 0;
@@ -631,6 +648,10 @@
int *aligned_width = va_arg(args, int *);
int *aligned_height = va_arg(args, int *);
int *tile_enabled = va_arg(args, int *);
+ if (!aligned_width || !aligned_height || !tile_enabled) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
unsigned int alignedw, alignedh;
BufferInfo info(width, height, format, prod_usage, cons_usage);
*tile_enabled = IsUBwcEnabled(format, prod_usage, cons_usage);
@@ -642,9 +663,15 @@
case GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE: {
private_handle_t *hnd = va_arg(args, private_handle_t *);
int *color_space = va_arg(args, int *);
+
if (private_handle_t::validate(hnd) != 0) {
return GRALLOC1_ERROR_BAD_HANDLE;
}
+
+ if (!color_space) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
*color_space = 0;
#ifdef USE_COLOR_METADATA
ColorMetaData color_metadata;
@@ -676,6 +703,11 @@
if (private_handle_t::validate(hnd) != 0) {
return GRALLOC1_ERROR_BAD_HANDLE;
}
+
+ if (!ycbcr) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
if (GetYUVPlaneInfo(hnd, ycbcr)) {
return GRALLOC1_ERROR_UNDEFINED;
}
@@ -684,10 +716,15 @@
case GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO: {
private_handle_t *hnd = va_arg(args, private_handle_t *);
int *map_secure_buffer = va_arg(args, int *);
+
if (private_handle_t::validate(hnd) != 0) {
return GRALLOC1_ERROR_BAD_HANDLE;
}
+ if (!map_secure_buffer) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
if (getMetaData(hnd, GET_MAP_SECURE_BUFFER, map_secure_buffer) == 0) {
*map_secure_buffer = 0;
}
@@ -696,9 +733,15 @@
case GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG: {
private_handle_t *hnd = va_arg(args, private_handle_t *);
int *flag = va_arg(args, int *);
+
if (private_handle_t::validate(hnd) != 0) {
return GRALLOC1_ERROR_BAD_HANDLE;
}
+
+ if (!flag) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
*flag = hnd->flags &private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
int linear_format = 0;
if (getMetaData(hnd, GET_LINEAR_FORMAT, &linear_format) == 0) {
@@ -711,9 +754,15 @@
case GRALLOC_MODULE_PERFORM_GET_RGB_DATA_ADDRESS: {
private_handle_t *hnd = va_arg(args, private_handle_t *);
void **rgb_data = va_arg(args, void **);
+
if (private_handle_t::validate(hnd) != 0) {
return GRALLOC1_ERROR_BAD_HANDLE;
}
+
+ if (!rgb_data) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
if (GetRgbDataAddress(hnd, rgb_data)) {
return GRALLOC1_ERROR_UNDEFINED;
}
@@ -730,6 +779,11 @@
uint32_t *aligned_width = va_arg(args, uint32_t *);
uint32_t *aligned_height = va_arg(args, uint32_t *);
uint32_t *size = va_arg(args, uint32_t *);
+
+ if (!aligned_width || !aligned_height || !size) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
auto info = BufferInfo(width, height, format, producer_usage, consumer_usage);
GetBufferSizeAndDimensions(info, size, aligned_width, aligned_height);
// Align size
@@ -737,14 +791,18 @@
*size = ALIGN(*size, align);
} break;
- // TODO(user): Break out similar functionality, preferably moving to a common lib.
-
case GRALLOC1_MODULE_PERFORM_GET_INTERLACE_FLAG: {
private_handle_t *hnd = va_arg(args, private_handle_t *);
int *flag = va_arg(args, int *);
+
if (private_handle_t::validate(hnd) != 0) {
return GRALLOC1_ERROR_BAD_HANDLE;
}
+
+ if (!flag) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
if (getMetaData(hnd, GET_PP_PARAM_INTERLACED, flag) != 0) {
*flag = 0;
}
diff --git a/libgralloc1/gr_device_impl.cpp b/libgralloc1/gr_device_impl.cpp
index 03e42ab..d421ff1 100644
--- a/libgralloc1/gr_device_impl.cpp
+++ b/libgralloc1/gr_device_impl.cpp
@@ -347,6 +347,10 @@
gralloc1_error_t GrallocImpl::GetProducerUsage(gralloc1_device_t *device, buffer_handle_t buffer,
gralloc1_producer_usage_t *outUsage) {
+ if (!outUsage) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
if (status == GRALLOC1_ERROR_NONE) {
const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer);
@@ -358,6 +362,10 @@
gralloc1_error_t GrallocImpl::GetBufferStride(gralloc1_device_t *device, buffer_handle_t buffer,
uint32_t *outStride) {
+ if (!outStride) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
if (status == GRALLOC1_ERROR_NONE) {
*outStride = UINT(PRIV_HANDLE_CONST(buffer)->GetStride());
@@ -373,6 +381,10 @@
return GRALLOC1_ERROR_BAD_DESCRIPTOR;
}
+ if (!device) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
GrallocImpl const *dev = GRALLOC_IMPL(device);
gralloc1_error_t status = dev->buf_mgr_->AllocateBuffers(num_descriptors, descriptors,
out_buffers);
@@ -403,6 +415,10 @@
gralloc1_error_t GrallocImpl::GetNumFlexPlanes(gralloc1_device_t *device, buffer_handle_t buffer,
uint32_t *out_num_planes) {
+ if (!out_num_planes) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
if (status == GRALLOC1_ERROR_NONE) {
GrallocImpl const *dev = GRALLOC_IMPL(device);
@@ -425,7 +441,8 @@
int32_t acquire_fence) {
ATRACE_CALL();
gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
- if (status != GRALLOC1_ERROR_NONE) {
+ if (status != GRALLOC1_ERROR_NONE || !out_data ||
+ !region) { // currently we ignore the region/rect client wants to lock
CloseFdIfValid(acquire_fence);
return status;
}
@@ -452,13 +469,8 @@
// return GRALLOC1_ERROR_BAD_VALUE;
}
- // currently we ignore the region/rect client wants to lock
- if (region == NULL) {
- return GRALLOC1_ERROR_BAD_VALUE;
- }
// TODO(user): Need to check if buffer was allocated with the same flags
status = dev->buf_mgr_->LockBuffer(hnd, prod_usage, cons_usage);
-
*out_data = reinterpret_cast<void *>(hnd->base);
return status;
@@ -470,7 +482,12 @@
const gralloc1_rect_t *region,
struct android_flex_layout *out_flex_layout,
int32_t acquire_fence) {
- void *out_data;
+ if (!out_flex_layout) {
+ CloseFdIfValid(acquire_fence);
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
+ void *out_data {};
gralloc1_error_t status = GrallocImpl::LockBuffer(device, buffer, prod_usage, cons_usage, region,
&out_data, acquire_fence);
if (status != GRALLOC1_ERROR_NONE) {
@@ -486,11 +503,14 @@
gralloc1_error_t GrallocImpl::UnlockBuffer(gralloc1_device_t *device, buffer_handle_t buffer,
int32_t *release_fence) {
gralloc1_error_t status = CheckDeviceAndHandle(device, buffer);
-
if (status != GRALLOC1_ERROR_NONE) {
return status;
}
+ if (!release_fence) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
const private_handle_t *hnd = PRIV_HANDLE_CONST(buffer);
GrallocImpl const *dev = GRALLOC_IMPL(device);
@@ -500,6 +520,10 @@
}
gralloc1_error_t GrallocImpl::Gralloc1Perform(gralloc1_device_t *device, int operation, ...) {
+ if (!device) {
+ return GRALLOC1_ERROR_BAD_VALUE;
+ }
+
va_list args;
va_start(args, operation);
GrallocImpl const *dev = GRALLOC_IMPL(device);
diff --git a/libqdutils/qd_utils.cpp b/libqdutils/qd_utils.cpp
index 10ac90b..2cce39c 100644
--- a/libqdutils/qd_utils.cpp
+++ b/libqdutils/qd_utils.cpp
@@ -31,6 +31,7 @@
#include <gralloc_priv.h>
#include "qd_utils.h"
+static const int kFBNodeMax = 4;
namespace qdutils {
static int parseLine(char *input, char *tokens[], const uint32_t maxToken, uint32_t *count) {
@@ -57,9 +58,9 @@
char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
int j = 0;
- for(j = 0; j < HWC_NUM_DISPLAY_TYPES; j++) {
+ for(j = 0; j < kFBNodeMax; j++) {
snprintf (msmFbTypePath, sizeof(msmFbTypePath),
- "/sys/class/graphics/fb%d/msm_fb_type", j);
+ "/sys/devices/virtual/graphics/fb%d/msm_fb_type", j);
displayDeviceFP = fopen(msmFbTypePath, "r");
if(displayDeviceFP) {
fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
@@ -71,11 +72,11 @@
}
fclose(displayDeviceFP);
} else {
- ALOGE("%s: Failed to open fb node %d", __func__, j);
+ ALOGE("%s: Failed to open fb node %s", __func__, msmFbTypePath);
}
}
- if (j < HWC_NUM_DISPLAY_TYPES)
+ if (j < kFBNodeMax)
return j;
else
ALOGE("%s: Failed to find %s node", __func__, type);
@@ -186,12 +187,12 @@
}
snprintf(msmFbTypePath, sizeof(msmFbTypePath),
- "/sys/class/graphics/fb%d/edid_raw_data", node_id);
+ "/sys/devices/virtual/graphics/fb%d/edid_raw_data", node_id);
edidFile = open(msmFbTypePath, O_RDONLY, 0);
if (edidFile < 0) {
- ALOGE("%s no edid raw data found", __func__);
+ ALOGE("%s no edid raw data found %s", __func__,msmFbTypePath);
return 0;
}
@@ -214,11 +215,11 @@
}
snprintf(connectPath, sizeof(connectPath),
- "/sys/class/graphics/fb%d/connected", nodeId);
+ "/sys/devices/virtual/graphics/fb%d/connected", nodeId);
connectFile = fopen(connectPath, "rb");
if (!connectFile) {
- ALOGW("Failed to open connect node for device node %d", nodeId);
+ ALOGW("Failed to open connect node for device node %s", connectPath);
return false;
}
@@ -253,11 +254,11 @@
}
snprintf(configPath, sizeof(configPath),
- "/sys/class/graphics/fb%d/config", nodeId);
+ "/sys/devices/virtual/graphics/fb%d/config", nodeId);
configFile = fopen(configPath, "rb");
if (!configFile) {
- ALOGW("Failed to open config node for device node %d", nodeId);
+ ALOGW("Failed to open config node for device node %s", configPath);
return -EINVAL;
}
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 345aeb2..961a745 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -391,8 +391,15 @@
}
void HWDeviceDRM::InitializeConfigs() {
- // TODO(user): Choose Best Mode
current_mode_index_ = 0;
+ // Update current mode with preferred mode
+ for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+ if (connector_info_.modes[mode_index].type & DRM_MODE_TYPE_PREFERRED) {
+ current_mode_index_ = mode_index;
+ break;
+ }
+ }
+
display_attributes_.resize(connector_info_.modes.size());
uint32_t width = connector_info_.modes[current_mode_index_].hdisplay;
@@ -499,8 +506,28 @@
hw_panel_info_.min_roi_height = connector_info_.hmin;
hw_panel_info_.needs_roi_merge = connector_info_.roi_merge;
hw_panel_info_.dynamic_fps = connector_info_.dynamic_fps;
- hw_panel_info_.min_fps = 60;
- hw_panel_info_.max_fps = 60;
+ drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_];
+ if (hw_panel_info_.dynamic_fps) {
+ uint32_t min_fps = current_mode.vrefresh;
+ uint32_t max_fps = current_mode.vrefresh;
+ for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+ if ((current_mode.vdisplay == connector_info_.modes[mode_index].vdisplay) &&
+ (current_mode.hdisplay == connector_info_.modes[mode_index].hdisplay)) {
+ if (min_fps > connector_info_.modes[mode_index].vrefresh) {
+ min_fps = connector_info_.modes[mode_index].vrefresh;
+ }
+ if (max_fps < connector_info_.modes[mode_index].vrefresh) {
+ max_fps = connector_info_.modes[mode_index].vrefresh;
+ }
+ }
+ }
+ hw_panel_info_.min_fps = min_fps;
+ hw_panel_info_.max_fps = max_fps;
+ } else {
+ hw_panel_info_.min_fps = current_mode.vrefresh;
+ hw_panel_info_.max_fps = current_mode.vrefresh;
+ }
+
hw_panel_info_.is_primary_panel = connector_info_.is_primary;
hw_panel_info_.is_pluggable = 0;
hw_panel_info_.hdr_enabled = connector_info_.panel_hdr_prop.hdr_enabled;
@@ -537,7 +564,7 @@
hw_panel_info_.width_align, hw_panel_info_.top_align, hw_panel_info_.height_align);
DLOGI("ROI: min_width = %d, min_height = %d, need_merge = %d", hw_panel_info_.min_roi_width,
hw_panel_info_.min_roi_height, hw_panel_info_.needs_roi_merge);
- DLOGI("FPS: min = %d, max =%d", hw_panel_info_.min_fps, hw_panel_info_.max_fps);
+ DLOGI("FPS: min = %d, max = %d", hw_panel_info_.min_fps, hw_panel_info_.max_fps);
DLOGI("Left Split = %d, Right Split = %d", hw_panel_info_.split_info.left_split,
hw_panel_info_.split_info.right_split);
DLOGI("Panel Transfer time = %d us", hw_panel_info_.transfer_time_us);
@@ -865,6 +892,21 @@
qos_data.clock_hz, qos_data.core_ab_bps, qos_data.core_ib_bps, qos_data.llcc_ab_bps,
qos_data.llcc_ib_bps, qos_data.dram_ab_bps, qos_data.dram_ib_bps,
qos_data.rot_clock_hz);
+
+ // Set refresh rate
+ if (vrefresh_) {
+ drmModeModeInfo mode = {};
+ drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_];
+ for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+ if ((current_mode.vdisplay == connector_info_.modes[mode_index].vdisplay) &&
+ (current_mode.hdisplay == connector_info_.modes[mode_index].hdisplay) &&
+ (vrefresh_ == connector_info_.modes[mode_index].vrefresh)) {
+ mode = connector_info_.modes[mode_index];
+ break;
+ }
+ }
+ drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &mode);
+ }
}
void HWDeviceDRM::AddSolidfillStage(const HWSolidfillStage &sf, uint32_t plane_alpha) {
@@ -910,6 +952,7 @@
int ret = drm_atomic_intf_->Validate();
if (ret) {
DLOGE("%s failed with error %d", __FUNCTION__, ret);
+ vrefresh_ = 0;
return kErrorHardware;
}
@@ -989,6 +1032,7 @@
int ret = drm_atomic_intf_->Commit(false /* synchronous */, false /* retain_planes*/);
if (ret) {
DLOGE("%s failed with error %d crtc %d", __FUNCTION__, ret, token_.crtc_id);
+ vrefresh_ = 0;
return kErrorHardware;
}
@@ -1014,6 +1058,20 @@
hw_layer_info.sync_handle = release_fence;
+ if (vrefresh_) {
+ // Update current mode index if refresh rate is changed
+ drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_];
+ for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+ if ((current_mode.vdisplay == connector_info_.modes[mode_index].vdisplay) &&
+ (current_mode.hdisplay == connector_info_.modes[mode_index].hdisplay) &&
+ (vrefresh_ == connector_info_.modes[mode_index].vrefresh)) {
+ current_mode_index_ = mode_index;
+ break;
+ }
+ }
+ vrefresh_ = 0;
+ }
+
return kErrorNone;
}
@@ -1181,6 +1239,17 @@
}
DisplayError HWDeviceDRM::SetRefreshRate(uint32_t refresh_rate) {
+ // Check if requested refresh rate is valid
+ drmModeModeInfo current_mode = connector_info_.modes[current_mode_index_];
+ for (uint32_t mode_index = 0; mode_index < connector_info_.modes.size(); mode_index++) {
+ if ((current_mode.vdisplay == connector_info_.modes[mode_index].vdisplay) &&
+ (current_mode.hdisplay == connector_info_.modes[mode_index].hdisplay) &&
+ (refresh_rate == connector_info_.modes[mode_index].vrefresh)) {
+ vrefresh_ = refresh_rate;
+ DLOGV_IF(kTagDriverConfig, "Set refresh rate to %d", refresh_rate);
+ return kErrorNone;
+ }
+ }
return kErrorNotSupported;
}
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index cc17668..5130fc5 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -184,6 +184,7 @@
std::string interface_str_ = "DSI";
std::vector<sde_drm::DRMSolidfillStage> solid_fills_ {};
bool resolution_switch_enabled_ = false;
+ uint32_t vrefresh_ = 0;
};
} // namespace sdm
diff --git a/sdm/libs/hwc2/Android.mk b/sdm/libs/hwc2/Android.mk
index b451d2c..9db57ab 100644
--- a/sdm/libs/hwc2/Android.mk
+++ b/sdm/libs/hwc2/Android.mk
@@ -36,7 +36,8 @@
hwc_tonemapper.cpp \
display_null.cpp \
hwc_socket_handler.cpp \
- hwc_buffer_allocator.cpp
+ hwc_buffer_allocator.cpp \
+ hwc_display_external_test.cpp
ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY), true)
LOCAL_CFLAGS += -DFEATURE_WIDE_COLOR
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.cpp b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
index 62b64be..1c264aa 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.cpp
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
@@ -165,6 +165,8 @@
hnd = (private_handle_t *)buf; // NOLINT
alloc_buffer_info->fd = hnd->fd;
alloc_buffer_info->stride = UINT32(hnd->width);
+ alloc_buffer_info->aligned_width = UINT32(hnd->width);
+ alloc_buffer_info->aligned_height = UINT32(hnd->height);
alloc_buffer_info->size = hnd->size;
buffer_info->private_data = reinterpret_cast<void *>(hnd);
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index f58fe8b..af02c56 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -54,8 +54,6 @@
namespace sdm {
-std::bitset<kDisplayMax> HWCDisplay::validated_ = 0;
-
// This weight function is needed because the color primaries are not sorted by gamut size
static ColorPrimaries WidestPrimaries(ColorPrimaries p1, ColorPrimaries p2) {
int weight = 10;
@@ -357,7 +355,7 @@
return -EINVAL;
}
- validated_.reset();
+ validated_ = false;
HWCDebugHandler::Get()->GetProperty("sys.hwc_disable_hdr", &disable_hdr_handling_);
if (disable_hdr_handling_) {
DLOGI("HDR Handling disabled");
@@ -420,7 +418,7 @@
layer_map_.emplace(std::make_pair(layer->GetId(), layer));
*out_layer_id = layer->GetId();
geometry_changes_ |= GeometryChanges::kAdded;
- validated_.reset();
+ validated_ = false;
return HWC2::Error::None;
}
@@ -452,7 +450,7 @@
}
geometry_changes_ |= GeometryChanges::kRemoved;
- validated_.reset();
+ validated_ = false;
return HWC2::Error::None;
}
@@ -718,7 +716,7 @@
ATRACE_INT("SetPowerMode ", state);
DisplayError error = display_intf_->SetDisplayState(state);
- validated_.reset();
+ validated_ = false;
if (error == kErrorNone) {
flush_on_error_ = flush_on_error;
@@ -902,7 +900,7 @@
return HWC2::Error::BadConfig;
}
- validated_.reset();
+ validated_ = false;
return HWC2::Error::None;
}
@@ -920,7 +918,7 @@
}
DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
- validated_.reset();
+ validated_ = false;
}
HWC2::PowerMode HWCDisplay::GetLastPowerMode() {
@@ -950,10 +948,10 @@
switch (event) {
case kIdleTimeout:
case kThermalEvent:
- case kIdlePowerCollapse:
- HWCSession::WaitForSequence(id_);
- validated_.reset();
- break;
+ case kIdlePowerCollapse: {
+ SEQUENCE_WAIT_SCOPE_LOCK(HWCSession::locker_[type_]);
+ validated_ = false;
+ } break;
default:
DLOGW("Unknown event: %d", event);
break;
@@ -982,7 +980,7 @@
}
return HWC2::Error::BadDisplay;
} else {
- validated_.set(type_);
+ validated_ = true;
}
} else {
// Skip is not set
@@ -1029,7 +1027,7 @@
return HWC2::Error::None;
}
- if (!validated_.test(type_)) {
+ if (!validated_) {
return HWC2::Error::NotValidated;
}
@@ -1051,7 +1049,7 @@
return HWC2::Error::None;
}
- if (!validated_.test(type_)) {
+ if (!validated_) {
DLOGW("Display is not validated");
return HWC2::Error::NotValidated;
}
@@ -1093,7 +1091,7 @@
// Use for sharing blit buffers and
// writing wfd buffer directly to output if there is full GPU composition
// and no color conversion needed
- if (!validated_.test(type_)) {
+ if (!validated_) {
DLOGW("Display is not validated");
return HWC2::Error::NotValidated;
}
@@ -1153,10 +1151,10 @@
}
if (skip_validate_ && !CanSkipValidate()) {
- validated_.reset(type_);
+ validated_ = false;
}
- if (!validated_.test(type_)) {
+ if (!validated_) {
DLOGV_IF(kTagCompManager, "Display %d is not validated", id_);
return HWC2::Error::NotValidated;
}
@@ -1186,7 +1184,7 @@
shutdown_pending_ = true;
return HWC2::Error::Unsupported;
} else if (error == kErrorNotValidated) {
- validated_.reset(type_);
+ validated_ = false;
return HWC2::Error::NotValidated;
} else if (error != kErrorPermission) {
DLOGE("Commit failed. Error = %d", error);
@@ -1207,7 +1205,7 @@
// Do no call flush on errors, if a successful buffer is never submitted.
if (flush_ && flush_on_error_) {
display_intf_->Flush();
- validated_.reset();
+ validated_ = false;
}
if (tone_mapper_ && tone_mapper_->IsActive()) {
@@ -1285,7 +1283,7 @@
if (display_intf_) {
error = display_intf_->SetMaxMixerStages(max_mixer_stages);
- validated_.reset();
+ validated_ = false;
}
return error;
@@ -1648,7 +1646,7 @@
if (display_status == kDisplayStatusResume || display_status == kDisplayStatusPause) {
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
- validated_.reset();
+ validated_ = false;
}
return status;
@@ -1666,7 +1664,7 @@
if (hwc_layer->GetDeviceSelectedCompositionType() != HWC2::Composition::Cursor) {
return HWC2::Error::None;
}
- if (!skip_validate_ && validated_.test(type_)) {
+ if (!skip_validate_ && validated_) {
// the device is currently in the middle of the validate/present sequence,
// cannot set the Position(as per HWC2 spec)
return HWC2::Error::NotValidated;
@@ -1704,7 +1702,7 @@
return -1;
}
- validated_.reset();
+ validated_ = false;
return 0;
}
@@ -1713,7 +1711,7 @@
auto layer = hwc_layer->GetSDMLayer();
layer->composition = kCompositionSDE;
}
- validated_.set(type_);
+ validated_ = true;
}
void HWCDisplay::MarkLayersForClientComposition() {
@@ -1733,7 +1731,7 @@
int ret = 0;
if (display_intf_) {
ret = display_intf_->SetPanelBrightness(level);
- validated_.reset();
+ validated_ = false;
} else {
ret = -EINVAL;
}
@@ -1748,7 +1746,7 @@
int HWCDisplay::ToggleScreenUpdates(bool enable) {
display_paused_ = enable ? false : true;
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
- validated_.reset();
+ validated_ = false;
return 0;
}
@@ -1852,7 +1850,7 @@
int HWCDisplay::SetActiveDisplayConfig(uint32_t config) {
int status = (display_intf_->SetActiveConfig(config) == kErrorNone) ? 0 : -1;
- validated_.reset();
+ validated_ = false;
return status;
}
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 7eefcd1..e90dbdd 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -161,7 +161,7 @@
void BuildLayerStack(void);
void BuildSolidFillStack(void);
HWCLayer *GetHWCLayer(hwc2_layer_t layer);
- void ResetValidation() { validated_.reset(); }
+ void ResetValidation() { validated_ = false; }
uint32_t GetGeometryChanges() { return geometry_changes_; }
// HWC2 APIs
@@ -249,7 +249,7 @@
OUTPUT_LAYER_DUMP,
};
- static std::bitset<kDisplayMax> validated_;
+ bool validated_ = false;
CoreInterface *core_intf_ = nullptr;
HWCCallbacks *callbacks_ = nullptr;
HWCBufferAllocator *buffer_allocator_ = NULL;
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index 97507ee..cfeb8a4 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -180,7 +180,7 @@
if (secure_display_active_) {
DisplayError error = display_intf_->Flush();
- validated_.reset();
+ validated_ = false;
if (error != kErrorNone) {
DLOGE("Flush failed. Error = %d", error);
}
@@ -234,7 +234,7 @@
display_null_.GetDisplayState(&state);
display_intf_->SetDisplayState(state);
- validated_.reset();
+ validated_ = false;
SetVsyncEnabled(HWC2::Vsync::Enable);
diff --git a/sdm/libs/hwc2/hwc_display_external_test.cpp b/sdm/libs/hwc2/hwc_display_external_test.cpp
new file mode 100644
index 0000000..8551854
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_display_external_test.cpp
@@ -0,0 +1,751 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <cutils/properties.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <utils/formats.h>
+#include <algorithm>
+#include <array>
+#include <sstream>
+#include <string>
+#include <fstream>
+
+#include "hwc_display_external_test.h"
+#include "hwc_debugger.h"
+
+#define __CLASS__ "HWCDisplayExternalTest"
+
+namespace sdm {
+
+using std::array;
+
+int HWCDisplayExternalTest::Create(CoreInterface *core_intf,
+ HWCBufferAllocator *buffer_allocator,
+ HWCCallbacks *callbacks,
+ qService::QService *qservice, uint32_t panel_bpp,
+ uint32_t pattern_type, HWCDisplay **hwc_display) {
+ HWCDisplay *hwc_external_test = new HWCDisplayExternalTest(core_intf, buffer_allocator,
+ callbacks, qservice,
+ panel_bpp, pattern_type);
+
+ int status = static_cast<HWCDisplayExternalTest *>(hwc_external_test)->Init();
+ if (status) {
+ delete hwc_external_test;
+ return status;
+ }
+
+ *hwc_display = hwc_external_test;
+
+ DLOGE("EXTERNAL panel_bpp %d, pattern_type %d", panel_bpp, pattern_type);
+
+ return status;
+}
+
+void HWCDisplayExternalTest::Destroy(HWCDisplay *hwc_display) {
+ static_cast<HWCDisplayExternalTest *>(hwc_display)->Deinit();
+
+ delete hwc_display;
+}
+
+HWCDisplayExternalTest::HWCDisplayExternalTest(CoreInterface *core_intf,
+ HWCBufferAllocator *buffer_allocator,
+ HWCCallbacks *callbacks,
+ qService::QService *qservice, uint32_t panel_bpp,
+ uint32_t pattern_type)
+ : HWCDisplay(core_intf, callbacks, kHDMI, HWC_DISPLAY_EXTERNAL, false, qservice,
+ DISPLAY_CLASS_EXTERNAL, buffer_allocator), panel_bpp_(panel_bpp),
+ pattern_type_(pattern_type) {
+}
+
+int HWCDisplayExternalTest::Init() {
+ uint32_t external_width = 0;
+ uint32_t external_height = 0;
+
+ int status = HWCDisplay::Init();
+ if (status) {
+ DLOGE("HWCDisplayExternalTest::Init status = %d ", status);
+ return status;
+ }
+
+ status = CreateLayerStack();
+ if (status) {
+ Deinit();
+ return status;
+ }
+
+ DisplayError error = HWCDisplay::GetMixerResolution(&external_width, &external_height);
+ if (error != kErrorNone) {
+ Deinit();
+ return -EINVAL;
+ }
+
+ status = HWCDisplay::SetFrameBufferResolution(external_width, external_height);
+ if (status) {
+ Deinit();
+ DLOGE("HWCDisplayExternalTest:: set fb resolution status = %d ", status);
+ return status;
+ }
+
+ return status;
+}
+
+int HWCDisplayExternalTest::Deinit() {
+ DestroyLayerStack();
+ return HWCDisplay::Deinit();
+}
+
+
+HWC2::Error HWCDisplayExternalTest::Validate(uint32_t *out_num_types, uint32_t *out_num_requests) {
+ auto status = HWC2::Error::None;
+ if (secure_display_active_) {
+ MarkLayersForGPUBypass();
+ return status;
+ }
+
+ if (layer_set_.empty()) {
+ flush_ = true;
+ return status;
+ }
+
+ if (shutdown_pending_) {
+ return status;
+ }
+ DisplayError error = display_intf_->Prepare(&layer_stack_);
+ if (error != kErrorNone) {
+ if (error == kErrorShutDown) {
+ shutdown_pending_ = true;
+ } else if (error != kErrorPermission) {
+ DLOGE("Prepare failed. Error = %d", error);
+ // To prevent surfaceflinger infinite wait, flush the previous frame during Commit()
+ // so that previous buffer and fences are released, and override the error.
+ flush_ = true;
+ }
+ }
+
+ MarkLayersForGPUBypass();
+
+ return status;
+}
+
+HWC2::Error HWCDisplayExternalTest::Present(int32_t *out_retire_fence) {
+ auto status = HWC2::Error::None;
+
+ if (secure_display_active_) {
+ return status;
+ }
+
+ if (shutdown_pending_) {
+ return status;
+ }
+
+ DumpInputBuffer();
+
+ if (!flush_) {
+ DisplayError error = kErrorUndefined;
+ error = display_intf_->Commit(&layer_stack_);
+ if (error == kErrorNone) {
+ // A commit is successfully submitted, start flushing on failure now onwards.
+ flush_on_error_ = true;
+ } else if (error == kErrorShutDown) {
+ shutdown_pending_ = true;
+ status = HWC2::Error::Unsupported;
+ } else if (error == kErrorNotValidated) {
+ status = HWC2::Error::NotValidated;
+ } else if (error != kErrorPermission) {
+ DLOGE("Commit failed. Error = %d", error);
+ // To prevent surfaceflinger infinite wait, flush the previous frame during Commit()
+ // so that previous buffer and fences are released, and override the error.
+ flush_ = true;
+ }
+ }
+ PostCommit(out_retire_fence);
+ return status;
+}
+
+void HWCDisplayExternalTest::SetSecureDisplay(bool secure_display_active) {
+ if (secure_display_active_ != secure_display_active) {
+ secure_display_active_ = secure_display_active;
+
+ if (secure_display_active_) {
+ DisplayError error = display_intf_->Flush();
+ if (error != kErrorNone) {
+ DLOGE("Flush failed. Error = %d", error);
+ }
+ }
+ }
+ return;
+}
+
+int HWCDisplayExternalTest::Perform(uint32_t operation, ...) {
+ return 0;
+}
+
+void HWCDisplayExternalTest::DumpInputBuffer() {
+ if (!dump_frame_count_ || flush_ || !dump_input_layers_) {
+ return;
+ }
+
+ const char *dir_path = "/data/vendor/display/frame_dump_external";
+ uint32_t width = buffer_info_.alloc_buffer_info.aligned_width;
+ uint32_t height = buffer_info_.alloc_buffer_info.aligned_height;
+ string format_str = GetFormatString(buffer_info_.buffer_config.format);
+
+ char *buffer = reinterpret_cast<char *>(mmap(NULL, buffer_info_.alloc_buffer_info.size,
+ PROT_READ|PROT_WRITE, MAP_SHARED,
+ buffer_info_.alloc_buffer_info.fd, 0));
+ if (buffer == MAP_FAILED) {
+ DLOGW("mmap failed. err = %d", errno);
+ return;
+ }
+
+ if (mkdir(dir_path, 0777) != 0 && errno != EEXIST) {
+ DLOGW("Failed to create %s directory errno = %d, desc = %s", dir_path, errno, strerror(errno));
+ return;
+ }
+
+ // if directory exists already, need to explicitly change the permission.
+ if (errno == EEXIST && chmod(dir_path, 0777) != 0) {
+ DLOGW("Failed to change permissions on %s directory", dir_path);
+ return;
+ }
+
+ if (buffer) {
+ std::stringstream dump_file_name;
+ dump_file_name << dir_path;
+ dump_file_name << "/input_layer_" << width << "x" << height << "_" << format_str << ".raw";
+
+ std::fstream fs;
+ fs.open(dump_file_name.str().c_str(), std::fstream::in | std::fstream::out | std::fstream::app);
+ if (!fs.is_open()) {
+ DLOGI("File open failed %s", dump_file_name.str().c_str());
+ return;
+ }
+
+ fs.write(buffer, (std::streamsize)buffer_info_.alloc_buffer_info.size);
+ fs.close();
+
+ DLOGI("Frame Dump %s: is successful", dump_file_name.str().c_str());
+ }
+
+ // Dump only once as the content is going to be same for all draw cycles
+ if (dump_frame_count_) {
+ dump_frame_count_ = 0;
+ }
+
+ if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) {
+ DLOGW("munmap failed. err = %d", errno);
+ return;
+ }
+}
+
+void HWCDisplayExternalTest::CalcCRC(uint32_t color_val, std::bitset<16> *crc_data) {
+ std::bitset<16> color = {};
+ std::bitset<16> temp_crc = {};
+
+ switch (panel_bpp_) {
+ case kDisplayBpp18:
+ color = (color_val & 0xFC) << 8;
+ break;
+ case kDisplayBpp24:
+ color = color_val << 8;
+ break;
+ case kDisplayBpp30:
+ color = color_val << 6;
+ break;
+ default:
+ return;
+ }
+
+ temp_crc[15] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^
+ (*crc_data)[4] ^ (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^
+ (*crc_data)[8] ^ (*crc_data)[9] ^ (*crc_data)[10] ^ (*crc_data)[11] ^
+ (*crc_data)[12] ^ (*crc_data)[14] ^ (*crc_data)[15] ^ color[0] ^ color[1] ^
+ color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^ color[7] ^ color[8] ^
+ color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[14] ^ color[15];
+
+ temp_crc[14] = (*crc_data)[12] ^ (*crc_data)[13] ^ color[12] ^ color[13];
+ temp_crc[13] = (*crc_data)[11] ^ (*crc_data)[12] ^ color[11] ^ color[12];
+ temp_crc[12] = (*crc_data)[10] ^ (*crc_data)[11] ^ color[10] ^ color[11];
+ temp_crc[11] = (*crc_data)[9] ^ (*crc_data)[10] ^ color[9] ^ color[10];
+ temp_crc[10] = (*crc_data)[8] ^ (*crc_data)[9] ^ color[8] ^ color[9];
+ temp_crc[9] = (*crc_data)[7] ^ (*crc_data)[8] ^ color[7] ^ color[8];
+ temp_crc[8] = (*crc_data)[6] ^ (*crc_data)[7] ^ color[6] ^ color[7];
+ temp_crc[7] = (*crc_data)[5] ^ (*crc_data)[6] ^ color[5] ^ color[6];
+ temp_crc[6] = (*crc_data)[4] ^ (*crc_data)[5] ^ color[4] ^ color[5];
+ temp_crc[5] = (*crc_data)[3] ^ (*crc_data)[4] ^ color[3] ^ color[4];
+ temp_crc[4] = (*crc_data)[2] ^ (*crc_data)[3] ^ color[2] ^ color[3];
+ temp_crc[3] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[15] ^ color[1] ^ color[2] ^ color[15];
+ temp_crc[2] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[14] ^ color[0] ^ color[1] ^ color[14];
+
+ temp_crc[1] = (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^ (*crc_data)[5] ^
+ (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^
+ (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^
+ (*crc_data)[14] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^ color[6] ^
+ color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^ color[13] ^
+ color[14];
+
+ temp_crc[0] = (*crc_data)[0] ^ (*crc_data)[1] ^ (*crc_data)[2] ^ (*crc_data)[3] ^ (*crc_data)[4] ^
+ (*crc_data)[5] ^ (*crc_data)[6] ^ (*crc_data)[7] ^ (*crc_data)[8] ^ (*crc_data)[9] ^
+ (*crc_data)[10] ^ (*crc_data)[11] ^ (*crc_data)[12] ^ (*crc_data)[13] ^
+ (*crc_data)[15] ^ color[0] ^ color[1] ^ color[2] ^ color[3] ^ color[4] ^ color[5] ^
+ color[6] ^ color[7] ^ color[8] ^ color[9] ^ color[10] ^ color[11] ^ color[12] ^
+ color[13] ^ color[15];
+
+ (*crc_data) = temp_crc;
+}
+
+int HWCDisplayExternalTest::FillBuffer() {
+ uint8_t *buffer = reinterpret_cast<uint8_t *>(mmap(NULL, buffer_info_.alloc_buffer_info.size,
+ PROT_READ|PROT_WRITE, MAP_SHARED,
+ buffer_info_.alloc_buffer_info.fd, 0));
+ if (buffer == MAP_FAILED) {
+ DLOGE("mmap failed. err = %d", errno);
+ return -EFAULT;
+ }
+
+ switch (pattern_type_) {
+ case kPatternColorRamp:
+ GenerateColorRamp(buffer);
+ break;
+ case kPatternBWVertical:
+ GenerateBWVertical(buffer);
+ break;
+ case kPatternColorSquare:
+ GenerateColorSquare(buffer);
+ break;
+ default:
+ DLOGW("Invalid Pattern type %d", pattern_type_);
+ return -EINVAL;
+ }
+
+ if (munmap(buffer, buffer_info_.alloc_buffer_info.size) != 0) {
+ DLOGE("munmap failed. err = %d", errno);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int HWCDisplayExternalTest::GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride) {
+ switch (format) {
+ case kFormatRGBA8888:
+ case kFormatRGBA1010102:
+ *stride = width * 4;
+ break;
+ case kFormatRGB888:
+ *stride = width * 3;
+ break;
+ default:
+ DLOGE("Unsupported format type %d", format);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void HWCDisplayExternalTest::PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha,
+ uint8_t **buffer) {
+ LayerBufferFormat format = buffer_info_.buffer_config.format;
+
+ switch (format) {
+ case kFormatRGBA8888:
+ *(*buffer)++ = UINT8(red & 0xFF);
+ *(*buffer)++ = UINT8(green & 0xFF);
+ *(*buffer)++ = UINT8(blue & 0xFF);
+ *(*buffer)++ = UINT8(alpha & 0xFF);
+ break;
+ case kFormatRGB888:
+ *(*buffer)++ = UINT8(red & 0xFF);
+ *(*buffer)++ = UINT8(green & 0xFF);
+ *(*buffer)++ = UINT8(blue & 0xFF);
+ break;
+ case kFormatRGBA1010102:
+ // Lower 8 bits of red
+ *(*buffer)++ = UINT8(red & 0xFF);
+
+ // Upper 2 bits of Red + Lower 6 bits of green
+ *(*buffer)++ = UINT8(((green & 0x3F) << 2) | ((red >> 0x8) & 0x3));
+
+ // Upper 4 bits of green + Lower 4 bits of blue
+ *(*buffer)++ = UINT8(((blue & 0xF) << 4) | ((green >> 6) & 0xF));
+
+ // Upper 6 bits of blue + Lower 2 bits of alpha
+ *(*buffer)++ = UINT8(((alpha & 0x3) << 6) | ((blue >> 4) & 0x3F));
+ break;
+ default:
+ DLOGW("format not supported format = %d", format);
+ break;
+ }
+}
+
+void HWCDisplayExternalTest::GenerateColorRamp(uint8_t *buffer) {
+ uint32_t width = buffer_info_.buffer_config.width;
+ uint32_t height = buffer_info_.buffer_config.height;
+ LayerBufferFormat format = buffer_info_.buffer_config.format;
+ uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width;
+ uint32_t buffer_stride = 0;
+
+ uint32_t color_ramp = 0;
+ uint32_t start_color_val = 0;
+ uint32_t step_size = 1;
+ uint32_t ramp_width = 0;
+ uint32_t ramp_height = 0;
+ uint32_t shift_by = 0;
+
+ std::bitset<16> crc_red = {};
+ std::bitset<16> crc_green = {};
+ std::bitset<16> crc_blue = {};
+
+ switch (panel_bpp_) {
+ case kDisplayBpp18:
+ ramp_height = 64;
+ ramp_width = 64;
+ shift_by = 2;
+ break;
+ case kDisplayBpp24:
+ ramp_height = 64;
+ ramp_width = 256;
+ break;
+ case kDisplayBpp30:
+ ramp_height = 32;
+ ramp_width = 256;
+ start_color_val = 0x180;
+ break;
+ default:
+ return;
+ }
+
+ GetStride(format, aligned_width, &buffer_stride);
+
+ for (uint32_t loop_height = 0; loop_height < height; loop_height++) {
+ uint32_t color_value = start_color_val;
+ uint8_t *temp = buffer + (loop_height * buffer_stride);
+
+ for (uint32_t loop_width = 0; loop_width < width; loop_width++) {
+ if (color_ramp == kColorRedRamp) {
+ PixelCopy(color_value, 0, 0, 0, &temp);
+ CalcCRC(color_value, &crc_red);
+ CalcCRC(0, &crc_green);
+ CalcCRC(0, &crc_blue);
+ }
+ if (color_ramp == kColorGreenRamp) {
+ PixelCopy(0, color_value, 0, 0, &temp);
+ CalcCRC(0, &crc_red);
+ CalcCRC(color_value, &crc_green);
+ CalcCRC(0, &crc_blue);
+ }
+ if (color_ramp == kColorBlueRamp) {
+ PixelCopy(0, 0, color_value, 0, &temp);
+ CalcCRC(0, &crc_red);
+ CalcCRC(0, &crc_green);
+ CalcCRC(color_value, &crc_blue);
+ }
+ if (color_ramp == kColorWhiteRamp) {
+ PixelCopy(color_value, color_value, color_value, 0, &temp);
+ CalcCRC(color_value, &crc_red);
+ CalcCRC(color_value, &crc_green);
+ CalcCRC(color_value, &crc_blue);
+ }
+
+ color_value = (start_color_val + (((loop_width + 1) % ramp_width) * step_size)) << shift_by;
+ }
+
+ if (panel_bpp_ == kDisplayBpp30 && ((loop_height + 1) % ramp_height) == 0) {
+ if (start_color_val == 0x180) {
+ start_color_val = 0;
+ step_size = 4;
+ } else {
+ start_color_val = 0x180;
+ step_size = 1;
+ color_ramp = (color_ramp + 1) % 4;
+ }
+ continue;
+ }
+
+ if (((loop_height + 1) % ramp_height) == 0) {
+ color_ramp = (color_ramp + 1) % 4;
+ }
+ }
+
+ DLOGI("CRC red %x", crc_red.to_ulong());
+ DLOGI("CRC green %x", crc_green.to_ulong());
+ DLOGI("CRC blue %x", crc_blue.to_ulong());
+}
+
+void HWCDisplayExternalTest::GenerateBWVertical(uint8_t *buffer) {
+ uint32_t width = buffer_info_.buffer_config.width;
+ uint32_t height = buffer_info_.buffer_config.height;
+ LayerBufferFormat format = buffer_info_.buffer_config.format;
+ uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width;
+ uint32_t buffer_stride = 0;
+ uint32_t bits_per_component = panel_bpp_ / 3;
+ uint32_t max_color_val = (1 << bits_per_component) - 1;
+
+ std::bitset<16> crc_red = {};
+ std::bitset<16> crc_green = {};
+ std::bitset<16> crc_blue = {};
+
+ if (panel_bpp_ == kDisplayBpp18) {
+ max_color_val <<= 2;
+ }
+
+ GetStride(format, aligned_width, &buffer_stride);
+
+ for (uint32_t loop_height = 0; loop_height < height; loop_height++) {
+ uint32_t color = 0;
+ uint8_t *temp = buffer + (loop_height * buffer_stride);
+
+ for (uint32_t loop_width = 0; loop_width < width; loop_width++) {
+ if (color == kColorBlack) {
+ PixelCopy(0, 0, 0, 0, &temp);
+ CalcCRC(0, &crc_red);
+ CalcCRC(0, &crc_green);
+ CalcCRC(0, &crc_blue);
+ }
+ if (color == kColorWhite) {
+ PixelCopy(max_color_val, max_color_val, max_color_val, 0, &temp);
+ CalcCRC(max_color_val, &crc_red);
+ CalcCRC(max_color_val, &crc_green);
+ CalcCRC(max_color_val, &crc_blue);
+ }
+
+ color = (color + 1) % 2;
+ }
+ }
+
+ DLOGI("CRC red %x", crc_red.to_ulong());
+ DLOGI("CRC green %x", crc_green.to_ulong());
+ DLOGI("CRC blue %x", crc_blue.to_ulong());
+}
+
+void HWCDisplayExternalTest::GenerateColorSquare(uint8_t *buffer) {
+ uint32_t width = buffer_info_.buffer_config.width;
+ uint32_t height = buffer_info_.buffer_config.height;
+ LayerBufferFormat format = buffer_info_.buffer_config.format;
+ uint32_t aligned_width = buffer_info_.alloc_buffer_info.aligned_width;
+ uint32_t buffer_stride = 0;
+ uint32_t max_color_val = 0;
+ uint32_t min_color_val = 0;
+
+ std::bitset<16> crc_red = {};
+ std::bitset<16> crc_green = {};
+ std::bitset<16> crc_blue = {};
+
+ switch (panel_bpp_) {
+ case kDisplayBpp18:
+ max_color_val = 63 << 2; // CEA Dynamic range for 18bpp 0 - 63
+ min_color_val = 0;
+ break;
+ case kDisplayBpp24:
+ max_color_val = 235; // CEA Dynamic range for 24bpp 16 - 235
+ min_color_val = 16;
+ break;
+ case kDisplayBpp30:
+ max_color_val = 940; // CEA Dynamic range for 30bpp 64 - 940
+ min_color_val = 64;
+ break;
+ default:
+ return;
+ }
+
+ array<array<uint32_t, 3>, 8> colors = {{
+ {{max_color_val, max_color_val, max_color_val}}, // White Color
+ {{max_color_val, max_color_val, min_color_val}}, // Yellow Color
+ {{min_color_val, max_color_val, max_color_val}}, // Cyan Color
+ {{min_color_val, max_color_val, min_color_val}}, // Green Color
+ {{max_color_val, min_color_val, max_color_val}}, // Megenta Color
+ {{max_color_val, min_color_val, min_color_val}}, // Red Color
+ {{min_color_val, min_color_val, max_color_val}}, // Blue Color
+ {{min_color_val, min_color_val, min_color_val}}, // Black Color
+ }};
+
+ GetStride(format, aligned_width, &buffer_stride);
+
+ for (uint32_t loop_height = 0; loop_height < height; loop_height++) {
+ uint32_t color = 0;
+ uint8_t *temp = buffer + (loop_height * buffer_stride);
+
+ for (uint32_t loop_width = 0; loop_width < width; loop_width++) {
+ PixelCopy(colors[color][0], colors[color][1], colors[color][2], 0, &temp);
+ CalcCRC(colors[color][0], &crc_red);
+ CalcCRC(colors[color][1], &crc_green);
+ CalcCRC(colors[color][2], &crc_blue);
+
+ if (((loop_width + 1) % 64) == 0) {
+ color = (color + 1) % colors.size();
+ }
+ }
+
+ if (((loop_height + 1) % 64) == 0) {
+ std::reverse(colors.begin(), (colors.end() - 1));
+ }
+ }
+
+ DLOGI("CRC red %x", crc_red.to_ulong());
+ DLOGI("CRC green %x", crc_green.to_ulong());
+ DLOGI("CRC blue %x", crc_blue.to_ulong());
+}
+
+int HWCDisplayExternalTest::InitLayer(Layer *layer) {
+ uint32_t active_config = 0;
+ DisplayConfigVariableInfo var_info = {};
+
+ GetActiveDisplayConfig(&active_config);
+
+ GetDisplayAttributesForConfig(INT32(active_config), &var_info);
+
+ layer->flags.updating = 1;
+ layer->src_rect = LayerRect(0, 0, var_info.x_pixels, var_info.y_pixels);
+ layer->dst_rect = layer->src_rect;
+ layer->frame_rate = var_info.fps;
+ layer->blending = kBlendingPremultiplied;
+
+ layer->input_buffer.unaligned_width = var_info.x_pixels;
+ layer->input_buffer.unaligned_height = var_info.y_pixels;
+ buffer_info_.buffer_config.format = kFormatRGBA8888;
+
+ if (layer->composition != kCompositionGPUTarget) {
+ buffer_info_.buffer_config.width = var_info.x_pixels;
+ buffer_info_.buffer_config.height = var_info.y_pixels;
+ switch (panel_bpp_) {
+ case kDisplayBpp18:
+ case kDisplayBpp24:
+ buffer_info_.buffer_config.format = kFormatRGB888;
+ break;
+ case kDisplayBpp30:
+ buffer_info_.buffer_config.format = kFormatRGBA1010102;
+ break;
+ default:
+ DLOGW("panel bpp not supported %d", panel_bpp_);
+ return -EINVAL;
+ }
+ buffer_info_.buffer_config.buffer_count = 1;
+
+ int ret = buffer_allocator_->AllocateBuffer(&buffer_info_);
+ if (ret != 0) {
+ DLOGE("Buffer allocation failed. ret: %d", ret);
+ return -ENOMEM;
+ }
+
+ ret = FillBuffer();
+ if (ret != 0) {
+ buffer_allocator_->FreeBuffer(&buffer_info_);
+ return ret;
+ }
+
+ layer->input_buffer.width = buffer_info_.alloc_buffer_info.aligned_width;
+ layer->input_buffer.height = buffer_info_.alloc_buffer_info.aligned_height;
+ layer->input_buffer.size = buffer_info_.alloc_buffer_info.size;
+ layer->input_buffer.planes[0].fd = buffer_info_.alloc_buffer_info.fd;
+ layer->input_buffer.planes[0].stride = buffer_info_.alloc_buffer_info.stride;
+ layer->input_buffer.format = buffer_info_.buffer_config.format;
+
+ DLOGI("Input buffer WxH %dx%d format %s size %d fd %d stride %d", layer->input_buffer.width,
+ layer->input_buffer.height, GetFormatString(layer->input_buffer.format),
+ layer->input_buffer.size, layer->input_buffer.planes[0].fd,
+ layer->input_buffer.planes[0].stride);
+ }
+
+ return 0;
+}
+
+int HWCDisplayExternalTest::DeinitLayer(Layer *layer) {
+ if (layer->composition != kCompositionGPUTarget) {
+ int ret = buffer_allocator_->FreeBuffer(&buffer_info_);
+ if (ret != 0) {
+ DLOGE("Buffer deallocation failed. ret: %d", ret);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+int HWCDisplayExternalTest::CreateLayerStack() {
+ for (uint32_t i = 0; i < (kTestLayerCnt + 1 /* one dummy gpu_target layer */); i++) {
+ Layer *layer = new Layer();
+
+ if (i == kTestLayerCnt) {
+ layer->composition = kCompositionGPUTarget;
+ }
+ DLOGE("External :: CreateLayerStack %d", i);
+ int ret = InitLayer(layer);
+ if (ret != 0) {
+ delete layer;
+ return ret;
+ }
+ layer_stack_.layers.push_back(layer);
+ }
+
+ return 0;
+}
+
+int HWCDisplayExternalTest::DestroyLayerStack() {
+ for (uint32_t i = 0; i < UINT32(layer_stack_.layers.size()); i++) {
+ Layer *layer = layer_stack_.layers.at(i);
+ int ret = DeinitLayer(layer);
+ if (ret != 0) {
+ return ret;
+ }
+ delete layer;
+ }
+ layer_stack_.layers = {};
+
+ return 0;
+}
+
+HWC2::Error HWCDisplayExternalTest::PostCommit(int32_t *out_retire_fence) {
+ auto status = HWC2::Error::None;
+ // Do no call flush on errors, if a successful buffer is never submitted.
+ if (flush_ && flush_on_error_) {
+ display_intf_->Flush();
+ }
+ if (!flush_) {
+ for (size_t i = 0; i < layer_stack_.layers.size(); i++) {
+ Layer *layer = layer_stack_.layers.at(i);
+ LayerBuffer &layer_buffer = layer->input_buffer;
+
+ close(layer_buffer.release_fence_fd);
+ layer_buffer.release_fence_fd = -1;
+ }
+ close(layer_stack_.retire_fence_fd);
+ layer_stack_.retire_fence_fd = -1;
+ *out_retire_fence = -1;
+ }
+ flush_ = false;
+
+ return status;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc2/hwc_display_external_test.h b/sdm/libs/hwc2/hwc_display_external_test.h
new file mode 100644
index 0000000..ef8027b
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_display_external_test.h
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HWC_DISPLAY_EXTERNAL_TEST_H__
+#define __HWC_DISPLAY_EXTERNAL_TEST_H__
+
+#include <bitset>
+
+#include "hwc_display.h"
+#include "hwc_buffer_allocator.h"
+
+namespace sdm {
+
+class HWCDisplayExternalTest : public HWCDisplay {
+ public:
+ static int Create(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+ HWCCallbacks *callbacks, qService::QService *qservice,
+ uint32_t panel_bpp, uint32_t pattern_type, HWCDisplay **hwc_display);
+ static void Destroy(HWCDisplay *hwc_display);
+ virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
+ virtual HWC2::Error Present(int32_t *out_retire_fence);
+ virtual void SetSecureDisplay(bool secure_display_active);
+ virtual int Perform(uint32_t operation, ...);
+
+ protected:
+ BufferInfo buffer_info_ = {};
+ uint32_t panel_bpp_ = 0;
+ uint32_t pattern_type_ = 0;
+
+ enum ColorPatternType {
+ kPatternNone = 0,
+ kPatternColorRamp,
+ kPatternBWVertical,
+ kPatternColorSquare,
+ };
+
+ enum DisplayBpp {
+ kDisplayBpp18 = 18,
+ kDisplayBpp24 = 24,
+ kDisplayBpp30 = 30,
+ };
+
+ enum ColorRamp {
+ kColorRedRamp = 0,
+ kColorGreenRamp = 1,
+ kColorBlueRamp = 2,
+ kColorWhiteRamp = 3,
+ };
+
+ enum Colors {
+ kColorBlack = 0,
+ kColorWhite = 1,
+ };
+
+ private:
+ HWCDisplayExternalTest(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
+ HWCCallbacks *callbacks, qService::QService *qservice,
+ uint32_t panel_bpp, uint32_t pattern_type);
+ int Init();
+ int Deinit();
+ void DumpInputBuffer();
+ void CalcCRC(uint32_t color_value, std::bitset<16> *crc_data);
+ int FillBuffer();
+ int GetStride(LayerBufferFormat format, uint32_t width, uint32_t *stride);
+ void PixelCopy(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha, uint8_t **buffer);
+ void GenerateColorRamp(uint8_t *buffer);
+ void GenerateBWVertical(uint8_t *buffer);
+ void GenerateColorSquare(uint8_t *buffer);
+ int InitLayer(Layer *layer);
+ int DeinitLayer(Layer *layer);
+ int CreateLayerStack();
+ int DestroyLayerStack();
+ HWC2::Error PostCommit(int32_t *out_retire_fence);
+
+ static const uint32_t kTestLayerCnt = 1;
+};
+
+} // namespace sdm
+
+#endif // __HWC_DISPLAY_EXTERNAL_TEST_H__
+
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index d4917f6..71f6b4e 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -220,7 +220,7 @@
// If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd
// Revisit this when validating display_paused
DisplayError error = display_intf_->Flush();
- validated_.reset();
+ validated_ = false;
if (error != kErrorNone) {
DLOGE("Flush failed. Error = %d", error);
}
@@ -256,7 +256,7 @@
}
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
- validated_.reset();
+ validated_ = false;
return status;
}
@@ -269,7 +269,7 @@
}
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
- validated_.reset();
+ validated_ = false;
return status;
}
@@ -289,7 +289,7 @@
callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
color_tranform_failed_ = false;
- validated_.reset();
+ validated_ = false;
return status;
}
@@ -332,7 +332,7 @@
return -EINVAL;
}
va_end(args);
- validated_.reset();
+ validated_ = false;
return 0;
}
@@ -419,7 +419,7 @@
void HWCDisplayPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
display_intf_->SetIdleTimeoutMs(timeout_ms);
- validated_.reset();
+ validated_ = false;
}
static void SetLayerBuffer(const BufferInfo &output_buffer_info, LayerBuffer *output_buffer) {
@@ -519,7 +519,7 @@
output_buffer_base_ = buffer;
post_processed_output_ = true;
DisablePartialUpdateOneFrame();
- validated_.reset();
+ validated_ = false;
}
int HWCDisplayPrimary::FrameCaptureAsync(const BufferInfo &output_buffer_info,
@@ -564,7 +564,7 @@
if (display_intf_) {
error = display_intf_->SetDetailEnhancerData(de_data);
- validated_.reset();
+ validated_ = false;
}
return error;
}
@@ -574,7 +574,7 @@
if (display_intf_) {
error = display_intf_->ControlPartialUpdate(enable, pending);
- validated_.reset();
+ validated_ = false;
}
return error;
@@ -585,7 +585,7 @@
if (display_intf_) {
error = display_intf_->DisablePartialUpdateOneFrame();
- validated_.reset();
+ validated_ = false;
}
return error;
@@ -594,7 +594,7 @@
DisplayError HWCDisplayPrimary::SetMixerResolution(uint32_t width, uint32_t height) {
DisplayError error = display_intf_->SetMixerResolution(width, height);
- validated_.reset();
+ validated_ = false;
return error;
}
diff --git a/sdm/libs/hwc2/hwc_display_virtual.cpp b/sdm/libs/hwc2/hwc_display_virtual.cpp
index 8837ad0..c523e31 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -131,7 +131,7 @@
auto status = HWC2::Error::None;
if (display_paused_) {
DisplayError error = display_intf_->Flush();
- validated_.reset();
+ validated_ = false;
if (error != kErrorNone) {
DLOGE("Flush failed. Error = %d", error);
}
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index a114af9..390f39e 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -32,6 +32,8 @@
#include <utils/debug.h>
#include <sync/sync.h>
#include <profiler.h>
+#include <qd_utils.h>
+#include <utils/utils.h>
#include <algorithm>
#include <string>
#include <bitset>
@@ -44,6 +46,7 @@
#include "hwc_debugger.h"
#include "hwc_display_primary.h"
#include "hwc_display_virtual.h"
+#include "hwc_display_external_test.h"
#define __CLASS__ "HWCSession"
@@ -192,8 +195,7 @@
hdmi_is_primary_ = true;
// Create display if it is connected, else wait for hotplug connect event.
if (hw_disp_info.is_connected) {
- status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, qservice_,
- &hwc_display_[HWC_DISPLAY_PRIMARY]);
+ status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, 0, 0, false);
}
} else {
// Create and power on primary display
@@ -346,7 +348,6 @@
int32_t HWCSession::CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height,
int32_t *format, hwc2_display_t *out_display_id) {
// TODO(user): Handle concurrency with HDMI
- SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
if (!device) {
return HWC2_ERROR_BAD_DISPLAY;
}
@@ -357,6 +358,7 @@
HWCSession *hwc_session = static_cast<HWCSession *>(device);
auto status = hwc_session->CreateVirtualDisplayObject(width, height, format);
+
if (status == HWC2::Error::None) {
*out_display_id = HWC_DISPLAY_VIRTUAL;
DLOGI("Created virtual display id:% " PRIu64 " with res: %dx%d",
@@ -839,18 +841,24 @@
return nullptr;
}
-// TODO(user): handle locking
-
HWC2::Error HWCSession::CreateVirtualDisplayObject(uint32_t width, uint32_t height,
int32_t *format) {
- if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
- return HWC2::Error::NoResources;
+ {
+ SCOPE_LOCK(locker_[HWC_DISPLAY_VIRTUAL]);
+ if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+ return HWC2::Error::NoResources;
+ }
+
+ auto status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, width,
+ height, format, &hwc_display_[HWC_DISPLAY_VIRTUAL]);
+ // TODO(user): validate width and height support
+ if (status) {
+ return HWC2::Error::Unsupported;
+ }
}
- auto status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, width,
- height, format, &hwc_display_[HWC_DISPLAY_VIRTUAL]);
- // TODO(user): validate width and height support
- if (status)
- return HWC2::Error::Unsupported;
+
+ SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
+ hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
return HWC2::Error::None;
}
@@ -865,8 +873,7 @@
hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
if (disp == HWC_DISPLAY_EXTERNAL) {
- status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_, primary_width,
- primary_height, qservice_, false, &hwc_display_[disp]);
+ status = CreateExternalDisplay(disp, primary_width, primary_height, false);
} else {
DLOGE("Invalid display type");
return -1;
@@ -1415,18 +1422,27 @@
void HWCSession::HandleExtHPD(const char *uevent_data, int length) {
const char *pstr = GetTokenValue(uevent_data, length, "name=");
- if (!pstr || (strcmp(pstr, "DP-1") != 0)) {
+ if (!pstr || (strncmp(pstr, "DP-1", strlen("DP-1")) != 0)) {
return;
}
pstr = GetTokenValue(uevent_data, length, "status=");
if (pstr) {
bool connected = false;
- if (strcmp(pstr, "connected") == 0) {
+ hpd_bpp_ = 0;
+ hpd_pattern_ = 0;
+ if (strncmp(pstr, "connected", strlen("connected")) == 0) {
connected = true;
}
+ int bpp = GetEventValue(uevent_data, length, "bpp=");
+ int pattern = GetEventValue(uevent_data, length, "pattern=");
+ if (bpp >=0 && pattern >= 0) {
+ hpd_bpp_ = bpp;
+ hpd_pattern_ = pattern;
+ }
- DLOGI("Recived Ext HPD, connected:%d status=%s", connected, pstr);
+ DLOGI("Recived Ext HPD, connected:%d status=%s bpp = %d pattern =%d ",
+ connected, pstr, hpd_bpp_, hpd_pattern_);
HotPlugHandler(connected);
}
}
@@ -1484,8 +1500,7 @@
if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetState(connected);
} else {
- status = HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_,
- qservice_, &hwc_display_[HWC_DISPLAY_PRIMARY]);
+ status = CreateExternalDisplay(HWC_DISPLAY_PRIMARY, 0, 0, false);
notify_hotplug = true;
}
@@ -1499,6 +1514,8 @@
DLOGE("Primary display is not connected.");
return -1;
}
+
+ hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
}
if (connected) {
@@ -1609,4 +1626,27 @@
}
}
+int HWCSession::CreateExternalDisplay(int disp_id, uint32_t primary_width,
+ uint32_t primary_height, bool use_primary_res) {
+ uint32_t panel_bpp = 0;
+ uint32_t pattern_type = 0;
+
+ if (GetDriverType() == DriverType::FB) {
+ qdutils::getDPTestConfig(&panel_bpp, &pattern_type);
+ } else {
+ panel_bpp = static_cast<uint32_t>(hpd_bpp_);
+ pattern_type = static_cast<uint32_t>(hpd_pattern_);
+ }
+
+ if (panel_bpp && pattern_type) {
+ return HWCDisplayExternalTest::Create(core_intf_, &buffer_allocator_, &callbacks_,
+ qservice_, panel_bpp, pattern_type,
+ &hwc_display_[disp_id]);
+ }
+
+ return HWCDisplayExternal::Create(core_intf_, &buffer_allocator_, &callbacks_,
+ primary_width, primary_height, qservice_,
+ use_primary_res, &hwc_display_[disp_id]);
+}
+
} // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index b9032a4..3659370 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -144,11 +144,7 @@
static int32_t SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
const float *matrix, int32_t /*android_color_transform_t*/ hint);
- // Meant to be called by HWCDisplay to preserve sequence of validate/present during events from
- // polling thread
- static void WaitForSequence(hwc2_display_t display) {
- SEQUENCE_WAIT_SCOPE_LOCK(locker_[display]);
- }
+ static Locker locker_[HWC_NUM_DISPLAY_TYPES];
private:
static const int kExternalConnectionTimeoutMs = 500;
@@ -178,6 +174,8 @@
int32_t SetSecondaryDisplayStatus(int disp_id, HWCDisplay::DisplayStatus status);
int32_t GetPanelBrightness(int *level);
int32_t MinHdcpEncryptionLevelChanged(int disp_id, uint32_t min_enc_level);
+ int32_t CreateExternalDisplay(int disp_id, uint32_t primary_width, uint32_t primary_height,
+ bool use_primary_res);
// service methods
void StartServices();
@@ -232,7 +230,6 @@
void Refresh(hwc2_display_t display);
void HotPlug(hwc2_display_t display, HWC2::Connection state);
- static Locker locker_[HWC_NUM_DISPLAY_TYPES];
CoreInterface *core_intf_ = nullptr;
HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr};
HWCCallbacks callbacks_;
@@ -250,6 +247,8 @@
bool hdmi_is_primary_ = false;
bool is_composer_up_ = false;
Locker callbacks_lock_;
+ int hpd_bpp_ = 0;
+ int hpd_pattern_ = 0;
};
} // namespace sdm