sdm: Add support for HDR

- Add LayerRequests to SDM Layer Interface, which will
  be used in informing any requests from SDM to client.
- Check for color metadata from client and handle
  HDR content.
- Include GPU Tonemapper to tonemap any requests
  coming from SDM

Change-Id: Idd1882ffab77fc3bff296114f36fb30bff4a4530
Crs-fixed: 1092142
This commit is contained in:
Arun Kumar K.R
2016-11-09 01:32:25 -08:00
committed by Gerrit - the friendly Code Review server
parent 2b75da399a
commit bf2b25c106
15 changed files with 576 additions and 34 deletions

View File

@@ -203,6 +203,9 @@ struct LayerBufferFlags {
uint32_t secure_camera : 1; //!< This flag shall be set by the client to indicate that the
//!< buffer is associated with secure camera session. A secure
//!< camera layer can co-exist with non-secure layer(s).
uint32_t hdr : 1; //!< This flag shall be set by the client to indicate that the
//!< the content is HDR.
};
uint32_t flags = 0; //!< For initialization purpose only.

View File

@@ -179,6 +179,36 @@ struct LayerFlags {
};
};
/*! @brief This structure defines flags associated with the layer requests. The 1-bit flag can be
set to ON(1) or OFF(0).
@sa Layer
*/
struct LayerRequestFlags {
union {
struct {
uint32_t tone_map : 1; //!< This flag will be set by SDM when the layer needs tone map
uint32_t secure: 1; //!< This flag will be set by SDM when the layer must be secure
};
uint32_t request_flags = 0; //!< For initialization purpose only.
//!< Shall not be refered directly.
};
};
/*! @brief This structure defines LayerRequest.
Includes width/height/format of the LayerRequest.
SDM shall set the properties of LayerRequest to be used by the client
@sa LayerRequest
*/
struct LayerRequest {
LayerRequestFlags flags; // Flags associated with this request
LayerBufferFormat format = kFormatRGBA8888; // Requested format
uint32_t width = 0;
uint32_t height = 0;
};
/*! @brief This structure defines flags associated with a layer stack. The 1-bit flag can be set to
ON(1) or OFF(0).
@@ -219,6 +249,8 @@ struct LayerStackFlags {
uint32_t post_processed_output : 1; // If output_buffer should contain post processed output
// This applies only to primary displays currently
uint32_t hdr_present : 1; //!< Set if stack has HDR content
};
uint32_t flags = 0; //!< For initialization purpose only.
@@ -322,6 +354,11 @@ struct Layer {
//!< no content is associated with the layer.
LayerFlags flags; //!< Flags associated with this layer.
LayerRequest request = {}; //!< o/p - request on this Layer by SDM.
Lut3d lut_3d = {}; //!< o/p - Populated by SDM when tone mapping is
//!< needed on this layer.
};
/*! @brief This structure defines a layer stack that contains layers which need to be composed and

View File

@@ -53,6 +53,7 @@ class StrategyInterface {
const HWMixerAttributes &mixer_attributes,
const DisplayConfigVariableInfo &fb_config) = 0;
virtual DisplayError SetCompositionState(LayerComposition composition_type, bool enable) = 0;
virtual DisplayError Purge() = 0;
protected:
virtual ~StrategyInterface() { }

View File

@@ -71,6 +71,8 @@ namespace sdm {
const int kMaxRotatePerLayer = 2;
const uint32_t kMaxBlitTargetLayers = 2;
const int kPageSize = 4096;
const uint32_t kGridSize = 129; // size used for non-linear transformation before Tone-mapping
const uint32_t kLutDim = 17; // Dim of the 3d LUT for tone-mapping.
typedef void * Handle;

View File

@@ -382,6 +382,8 @@ void CompManager::Purge(Handle display_ctx) {
reinterpret_cast<DisplayCompositionContext *>(display_ctx);
resource_intf_->Purge(display_comp_ctx->display_resource_ctx);
display_comp_ctx->strategy->Purge();
}
void CompManager::ProcessIdleTimeout(Handle display_ctx) {

View File

@@ -104,6 +104,8 @@ DisplayError DisplayBase::Init() {
display_attributes_, hw_panel_info_);
if (!color_mgr_) {
DLOGW("Unable to create ColorManagerProxy for display = %d", display_type_);
} else if (InitializeColorModes() != kErrorNone) {
DLOGW("InitColorModes failed for display = %d", display_type_);
}
return kErrorNone;
@@ -119,6 +121,9 @@ CleanupOnError:
DisplayError DisplayBase::Deinit() {
lock_guard<recursive_mutex> obj(recursive_mutex_);
color_modes_.clear();
color_mode_map_.clear();
if (color_mgr_) {
delete color_mgr_;
color_mgr_ = NULL;
@@ -216,6 +221,12 @@ DisplayError DisplayBase::Prepare(LayerStack *layer_stack) {
return error;
}
error = HandleHDR(layer_stack);
if (error != kErrorNone) {
DLOGW("HandleHDR failed");
return error;
}
if (color_mgr_ && color_mgr_->NeedsPartialUpdateDisable()) {
DisablePartialUpdateOneFrame();
}
@@ -659,11 +670,6 @@ DisplayError DisplayBase::GetColorModeCount(uint32_t *mode_count) {
return kErrorNotSupported;
}
DisplayError error = color_mgr_->ColorMgrGetNumOfModes(&num_color_modes_);
if (error != kErrorNone || !num_color_modes_) {
return kErrorNotSupported;
}
DLOGV_IF(kTagQDCM, "Number of modes from color manager = %d", num_color_modes_);
*mode_count = num_color_modes_;
@@ -681,30 +687,6 @@ DisplayError DisplayBase::GetColorModes(uint32_t *mode_count,
return kErrorNotSupported;
}
if (!color_modes_.size()) {
color_modes_.resize(num_color_modes_);
DisplayError error = color_mgr_->ColorMgrGetModes(&num_color_modes_, color_modes_.data());
if (error != kErrorNone) {
DLOGE("Failed");
return error;
}
for (uint32_t i = 0; i < num_color_modes_; i++) {
DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
color_modes_[i].id);
auto it = color_mode_map_.find(color_modes_[i].name);
if (it != color_mode_map_.end()) {
if (it->second->id < color_modes_[i].id) {
color_mode_map_.erase(it);
color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
}
} else {
color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
}
}
}
for (uint32_t i = 0; i < num_color_modes_; i++) {
DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
color_modes_[i].id);
@@ -720,6 +702,21 @@ DisplayError DisplayBase::SetColorMode(const std::string &color_mode) {
return kErrorNotSupported;
}
DisplayError error = kErrorNone;
// Set client requests when not in HDR Mode.
if (!hdr_playback_mode_) {
error = SetColorModeInternal(color_mode);
if (error != kErrorNone) {
return error;
}
}
// Store the new color mode request by client
current_color_mode_ = color_mode;
return error;
}
DisplayError DisplayBase::SetColorModeInternal(const std::string &color_mode) {
DLOGV_IF(kTagQDCM, "Color Mode = %s", color_mode.c_str());
ColorModeMap::iterator it = color_mode_map_.find(color_mode);
@@ -730,7 +727,7 @@ DisplayError DisplayBase::SetColorMode(const std::string &color_mode) {
SDEDisplayMode *sde_display_mode = it->second;
DLOGD("Color Mode Name = %s corresponding mode_id = %d", sde_display_mode->name,
DLOGV_IF(kTagQDCM, "Color Mode Name = %s corresponding mode_id = %d", sde_display_mode->name,
sde_display_mode->id);
DisplayError error = kErrorNone;
error = color_mgr_->ColorMgrSetMode(sde_display_mode->id);
@@ -1145,5 +1142,74 @@ void DisplayBase::PostCommitLayerParams(LayerStack *layer_stack) {
return;
}
DisplayError DisplayBase::InitializeColorModes() {
if (!color_mgr_) {
return kErrorNotSupported;
}
DisplayError error = color_mgr_->ColorMgrGetNumOfModes(&num_color_modes_);
if (error != kErrorNone || !num_color_modes_) {
DLOGV_IF(kTagQDCM, "GetNumModes failed = %d count = %d", error, num_color_modes_);
return kErrorNotSupported;
}
DLOGI("Number of Color Modes = %d", num_color_modes_);
if (!color_modes_.size()) {
color_modes_.resize(num_color_modes_);
DisplayError error = color_mgr_->ColorMgrGetModes(&num_color_modes_, color_modes_.data());
if (error != kErrorNone) {
color_modes_.clear();
DLOGE("Failed");
return error;
}
for (uint32_t i = 0; i < num_color_modes_; i++) {
DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
color_modes_[i].id);
auto it = color_mode_map_.find(color_modes_[i].name);
if (it != color_mode_map_.end()) {
if (it->second->id < color_modes_[i].id) {
color_mode_map_.erase(it);
color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
}
} else {
color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
}
}
}
return kErrorNone;
}
DisplayError DisplayBase::HandleHDR(LayerStack *layer_stack) {
DisplayError error = kErrorNone;
if (!color_mgr_) {
// TODO(user): Handle the case where color_mgr is not present
return kErrorNone;
}
if (!layer_stack->flags.hdr_present) {
// HDR playback off - set prev mode
if (hdr_playback_mode_) {
hdr_playback_mode_ = false;
DLOGI("Setting color mode = %s", current_color_mode_.c_str());
error = SetColorModeInternal(current_color_mode_);
// TODO(user): Enable DPPS
}
} else {
// hdr is present
if (!hdr_playback_mode_ && !layer_stack->flags.animating) {
// hdr is starting
hdr_playback_mode_ = true;
DLOGI("Setting HDR color mode = %s", hdr_color_mode_.c_str());
error = SetColorModeInternal(hdr_color_mode_);
}
// TODO(user): Disable DPPS
}
return error;
}
} // namespace sdm

View File

@@ -114,6 +114,7 @@ class DisplayBase : public DisplayInterface, DumpImpl {
virtual DisplayError ValidateGPUTargetParams();
void CommitLayerParams(LayerStack *layer_stack);
void PostCommitLayerParams(LayerStack *layer_stack);
DisplayError HandleHDR(LayerStack *layer_stack);
// DumpImpl method
void AppendDump(char *buffer, uint32_t length);
@@ -124,6 +125,8 @@ class DisplayBase : public DisplayInterface, DumpImpl {
uint32_t *new_mixer_height);
DisplayError ReconfigureMixer(uint32_t width, uint32_t height);
bool NeedsDownScale(const LayerRect &src_rect, const LayerRect &dst_rect, bool needs_rotation);
DisplayError InitializeColorModes();
DisplayError SetColorModeInternal(const std::string &color_mode);
recursive_mutex recursive_mutex_;
DisplayType display_type_;
@@ -155,6 +158,9 @@ class DisplayBase : public DisplayInterface, DumpImpl {
DisplayConfigVariableInfo fb_config_ = {};
uint32_t req_mixer_width_ = 0;
uint32_t req_mixer_height_ = 0;
std::string current_color_mode_ = "hal_native";
std::string hdr_color_mode_ = "hal_hdr";
bool hdr_playback_mode_ = false;
};
} // namespace sdm

View File

@@ -137,6 +137,7 @@ DisplayError Strategy::GetNextStrategy(StrategyConstraints *constraints) {
LayerStack *layer_stack = hw_layers_info_->stack;
for (uint32_t i = 0; i < hw_layers_info_->app_layer_count; i++) {
layer_stack->layers.at(i)->composition = kCompositionGPU;
layer_stack->layers.at(i)->request.flags.request_flags = 0; // Reset layer request
}
if (!extn_start_success_) {
@@ -244,4 +245,13 @@ DisplayError Strategy::SetCompositionState(LayerComposition composition_type, bo
return kErrorNone;
}
DisplayError Strategy::Purge() {
if (strategy_intf_) {
return strategy_intf_->Purge();
}
return kErrorNone;
}
} // namespace sdm

View File

@@ -49,6 +49,7 @@ class Strategy {
const HWMixerAttributes &mixer_attributes,
const DisplayConfigVariableInfo &fb_config);
DisplayError SetCompositionState(LayerComposition composition_type, bool enable);
DisplayError Purge();
private:
void GenerateROI();

View File

@@ -15,7 +15,7 @@ LOCAL_CLANG := true
LOCAL_SHARED_LIBRARIES := libsdmcore libqservice libbinder libhardware libhardware_legacy \
libutils libcutils libsync libmemalloc libqdutils libdl \
libpowermanager libsdmutils libc++
libpowermanager libsdmutils libgpu_tonemapper libc++
LOCAL_SRC_FILES := hwc_session.cpp \
hwc_display.cpp \
@@ -28,7 +28,8 @@ LOCAL_SRC_FILES := hwc_session.cpp \
hwc_buffer_sync_handler.cpp \
hwc_color_manager.cpp \
blit_engine_c2d.cpp \
cpuhint.cpp
cpuhint.cpp \
hwc_tonemapper.cpp
include $(BUILD_SHARED_LIBRARY)
endif

View File

@@ -41,9 +41,10 @@
#include <utility>
#include <vector>
#include "hwc_display.h"
#include "hwc_debugger.h"
#include "blit_engine_c2d.h"
#include "hwc_debugger.h"
#include "hwc_display.h"
#include "hwc_tonemapper.h"
#ifdef QTI_BSP
#include <hardware/display_defs.h>
@@ -98,6 +99,9 @@ int HWCDisplay::Init() {
}
}
tone_mapper_ = new HWCToneMapper();
tone_mapper_->Init();
display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_);
current_refresh_rate_ = max_refresh_rate_;
@@ -127,6 +131,9 @@ int HWCDisplay::Deinit() {
blit_engine_ = NULL;
}
delete tone_mapper_;
tone_mapper_ = NULL;
return 0;
}
@@ -172,6 +179,7 @@ int HWCDisplay::SetPowerMode(int mode) {
// Do not flush until a buffer is successfully submitted again.
flush_on_error = false;
state = kStateOff;
tone_mapper_->Terminate();
break;
case HWC_POWER_MODE_NORMAL:
@@ -273,6 +281,10 @@ void HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type
blit_engine_->SetFrameDumpConfig(count);
}
if (tone_mapper_) {
tone_mapper_->SetFrameDumpConfig(count);
}
DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
}
@@ -702,6 +714,15 @@ int HWCDisplay::CommitLayerStack(hwc_display_contents_1_t *content_list) {
}
}
if (layer_stack_.flags.hdr_present) {
status = tone_mapper_->HandleToneMap(content_list, &layer_stack_);
if (status != 0) {
DLOGE("Error handling HDR in ToneMapper");
}
} else {
tone_mapper_->Terminate();
}
DisplayError error = kErrorUndefined;
if (status == 0) {
error = display_intf_->Commit(&layer_stack_);
@@ -738,6 +759,11 @@ int HWCDisplay::PostCommitLayerStack(hwc_display_contents_1_t *content_list) {
display_intf_->Flush();
}
if (tone_mapper_ && tone_mapper_->IsActive()) {
tone_mapper_->PostCommit(&layer_stack_);
}
// Set the release fence fd to the blit engine
if (use_blit_comp_ && blit_engine_->BlitActive()) {
blit_engine_->PostCommit(&layer_stack_);
@@ -1282,6 +1308,13 @@ DisplayError HWCDisplay::SetMetaData(const private_handle_t *pvt_handle, Layer *
return kErrorNotSupported;
}
if (layer_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
(layer_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 ||
layer_buffer.color_metadata.transfer == Transfer_HLG)) {
layer_buffer.flags.hdr = true;
layer_stack_.flags.hdr_present = true;
}
if (meta_data->operation & SET_IGC) {
if (SetIGC(meta_data->igc, &layer_buffer.igc) != kErrorNone) {
return kErrorNotSupported;

View File

@@ -36,6 +36,7 @@
namespace sdm {
class BlitEngine;
class HWCToneMapper;
// Subclasses set this to their type. This has to be different from DisplayType.
// This is to avoid RTTI and dynamic_cast
@@ -217,6 +218,7 @@ class HWCDisplay : public DisplayEventHandler {
LayerRect display_rect_;
std::map<int, LayerBufferS3DFormat> s3d_format_hwc_to_sdm_;
bool animating_ = false;
HWCToneMapper *tone_mapper_ = NULL;
private:
void DumpInputBuffers(hwc_display_contents_1_t *content_list);

View File

@@ -0,0 +1,290 @@
/*
* Copyright (c) 2016, 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 <alloc_controller.h>
#include <gr.h>
#include <gralloc_priv.h>
#include <memalloc.h>
#include <sync/sync.h>
#include <TonemapFactory.h>
#include <core/buffer_allocator.h>
#include <utils/constants.h>
#include <utils/debug.h>
#include <utils/formats.h>
#include <utils/rect.h>
#include <vector>
#include "hwc_debugger.h"
#include "hwc_tonemapper.h"
#define __CLASS__ "HWCToneMapper"
namespace sdm {
int HWCToneMapper::Init() {
for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
intermediate_buffer_[i] = NULL;
release_fence_fd_[i] = -1;
}
return 0;
}
void HWCToneMapper::DeInit() {
return;
}
int HWCToneMapper::HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
uint32_t layer_count = UINT32(layer_stack->layers.size());
std::vector<uint32_t> tonemap_layer_index = {};
Layer *layer = NULL;
uint32_t i = 0;
uint32_t gpu_count = 0;
int fence_fd = -1;
int acquire_fd = -1;
int merged_fd = -1;
hwc_layer_1_t *hwc_layer = NULL;
const private_handle_t *dst_hnd = NULL;
const private_handle_t *src_hnd = NULL;
for (; i < layer_count; i++) {
layer = layer_stack->layers.at(i);
if (layer->request.flags.tone_map) {
tonemap_layer_index.push_back(i);
break;
}
if (layer->composition == kCompositionGPU) {
gpu_count++;
}
}
if (tonemap_layer_index.empty()) {
return 0;
}
// gpu count can be 0 when a layer is on FB and in next cycle it doesn't update and SDM marks
// it as SDE comp
if (gpu_count == 0) {
// TODO(akumarkr): Remove goto when added multiple instance support
// intermediate buffer can be null
goto update_fd;
}
if (intermediate_buffer_[0] == NULL) {
DLOGI("format = %d width = %d height = %d", layer->request.format, layer->request.width,
layer->request.height);
// TODO(akumarkr): use flags from LayerRequestFlags for format change etc.,
uint32_t usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | GRALLOC_USAGE_HW_TEXTURE |
GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
AllocateIntermediateBuffers(layer->input_buffer.width, layer->input_buffer.height,
HAL_PIXEL_FORMAT_RGBA_8888, usage);
}
current_intermediate_buffer_index_ =
(current_intermediate_buffer_index_ + 1) % kNumIntermediateBuffers;
if (!gpu_tone_mapper_) {
Color10Bit *grid_entries = NULL;
int grid_size = 0;
if (layer->lut_3d.validGridEntries) {
grid_entries = layer->lut_3d.gridEntries;
grid_size = INT(layer->lut_3d.gridSize);
}
gpu_tone_mapper_ = TonemapperFactory_GetInstance(TONEMAP_INVERSE, layer->lut_3d.lutEntries,
layer->lut_3d.dim, grid_entries, grid_size);
if (gpu_tone_mapper_ == NULL) {
DLOGE("Get Tonemapper failed");
return -1;
}
}
hwc_layer = &content_list->hwLayers[i];
dst_hnd = intermediate_buffer_[current_intermediate_buffer_index_];
src_hnd = static_cast<const private_handle_t *>(hwc_layer->handle);
acquire_fd = dup(layer->input_buffer.acquire_fence_fd);
buffer_sync_handler_.SyncMerge(acquire_fd, release_fence_fd_[current_intermediate_buffer_index_],
&merged_fd);
if (acquire_fd >= 0) {
CloseFd(&acquire_fd);
}
if (release_fence_fd_[current_intermediate_buffer_index_] >= 0) {
CloseFd(&release_fence_fd_[current_intermediate_buffer_index_]);
}
DTRACE_BEGIN("GPU_TM_BLIT");
fence_fd = gpu_tone_mapper_->blit(reinterpret_cast<const void *>(dst_hnd),
reinterpret_cast<const void *>(src_hnd), merged_fd);
DTRACE_END();
DumpToneMapOutput(&fence_fd);
update_fd:
// Acquire fence will be closed by HWC Display
// Fence returned by GPU will be closed in PostCommit
layer->input_buffer.acquire_fence_fd = fence_fd;
layer->input_buffer.planes[0].fd = intermediate_buffer_[current_intermediate_buffer_index_]->fd;
active_ = true;
tonemap_layer_index.clear();
return 0;
}
int HWCToneMapper::AllocateIntermediateBuffers(uint32_t width, uint32_t height, uint32_t format,
uint32_t usage) {
int status = 0;
if (width <= 0 || height <= 0) {
return false;
}
for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
status = alloc_buffer(&intermediate_buffer_[i], INT(width), INT(height), INT(format),
INT(usage));
if (status < 0) {
DLOGE("Allocation of Intermediate Buffer failed");
FreeIntermediateBuffers();
break;
}
}
return status;
}
void HWCToneMapper::FreeIntermediateBuffers() {
if (!intermediate_buffer_[0]) {
return;
}
for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
private_handle_t *buffer = intermediate_buffer_[i];
if (buffer) {
// Free the valid fence
if (release_fence_fd_[i] >= 0) {
CloseFd(&release_fence_fd_[i]);
}
free_buffer(buffer);
intermediate_buffer_[i] = NULL;
}
}
}
void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
uint32_t layer_count = UINT32(layer_stack->layers.size());
std::vector<uint32_t> tonemap_layer_index = {};
Layer *layer = NULL;
int rel_fence_fd = -1;
bool has_tonemap = false;
uint32_t i;
for (i = 0; i < layer_count; i++) {
layer = layer_stack->layers.at(i);
if (layer->request.flags.tone_map) {
tonemap_layer_index.push_back(i);
has_tonemap = true;
break;
}
}
if (has_tonemap) {
LayerBuffer &layer_buffer = layer->input_buffer;
rel_fence_fd = layer_buffer.release_fence_fd;
// close the fd returned by GPU Tonemapper
CloseFd(&layer_buffer.acquire_fence_fd);
SetReleaseFence(rel_fence_fd);
}
active_ = false;
}
void HWCToneMapper::SetReleaseFence(int fd) {
CloseFd(&release_fence_fd_[current_intermediate_buffer_index_]);
// used to give to GPU tonemapper along with input layer fd
release_fence_fd_[current_intermediate_buffer_index_] = dup(fd);
}
void HWCToneMapper::CloseFd(int *fd) {
if (*fd >= 0) {
close(*fd);
*fd = -1;
}
}
void HWCToneMapper::Terminate() {
if (!gpu_tone_mapper_) {
return;
}
// fix this on multiple instance: only delete obj and call ToneMapperDestroy on deInit.
delete gpu_tone_mapper_;
gpu_tone_mapper_ = NULL;
TonemapperFactory_Destroy();
FreeIntermediateBuffers();
active_ = false;
}
void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
DLOGI("Dump FrameConfig count = %d", count);
dump_frame_count_ = count;
dump_frame_index_ = 0;
}
void HWCToneMapper::DumpToneMapOutput(int *acquire_fd) {
if (!dump_frame_count_) {
return;
}
private_handle_t *target_buffer = intermediate_buffer_[current_intermediate_buffer_index_];
if (*acquire_fd >= 0) {
int error = sync_wait(*acquire_fd, 1000);
if (error < 0) {
DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
return;
}
}
char dump_file_name[PATH_MAX];
size_t result = 0;
snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
"/tonemap_%d.raw", (dump_frame_index_));
FILE* fp = fopen(dump_file_name, "w+");
if (fp) {
DLOGI("base addr = %x", target_buffer->base);
result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
fclose(fp);
}
dump_frame_count_--;
dump_frame_index_++;
CloseFd(acquire_fd);
}
} // namespace sdm

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2016, 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_TONEMAPPER_H__
#define __HWC_TONEMAPPER_H__
#include <fcntl.h>
#include <sys/mman.h>
#include <hardware/hwcomposer.h>
#include <core/layer_stack.h>
#include <utils/sys.h>
#include "hwc_buffer_sync_handler.h"
class Tonemapper;
namespace sdm {
class HWCToneMapper {
public:
HWCToneMapper() {}
~HWCToneMapper() {}
int Init();
void DeInit();
int HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack);
void Terminate();
void PostCommit(LayerStack *layer_stack);
bool IsActive() { return active_; }
void SetFrameDumpConfig(uint32_t count);
private:
int AllocateIntermediateBuffers(uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
void FreeIntermediateBuffers();
void SetReleaseFence(int fence_fd);
void CloseFd(int *fd);
void DumpToneMapOutput(int *acquire_fence);
static const uint32_t kNumIntermediateBuffers = 2;
bool active_ = false;
private_handle_t *intermediate_buffer_[kNumIntermediateBuffers] = {NULL, NULL};
uint32_t current_intermediate_buffer_index_ = 0;
int release_fence_fd_[kNumIntermediateBuffers];
HWCBufferSyncHandler buffer_sync_handler_ = {};
Tonemapper *gpu_tone_mapper_ = NULL;
uint32_t dump_frame_count_ = 0;
uint32_t dump_frame_index_ = 0;
};
} // namespace sdm
#endif // __HWC_TONEMAPPER_H__

View File

@@ -363,6 +363,13 @@ void HWCDisplay::BuildLayerStack() {
}
}
if (layer->color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
(layer->color_metadata.transfer == Transfer_SMPTE_ST2084 ||
layer->color_metadata.transfer == Transfer_HLG)) {
layer->flags.hdr = true;
layer_stack_.flags.hdr_present = true;
}
if (layer->flags.skip) {
layer_stack_.flags.skip_present = true;
}