summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Kumar K.R <akumarkr@codeaurora.org>2016-11-09 01:32:25 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-12-16 11:26:51 -0800
commitbf2b25c1064e856a69821d7e65148f3ed3544ee5 (patch)
tree45fcd24e98fdaaff324ffda235d29cf25df4c60d
parent2b75da399a3cf0c1299e62bf5a6738a052928529 (diff)
downloaddisplay-bf2b25c1064e856a69821d7e65148f3ed3544ee5.tar.gz
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
-rw-r--r--sdm/include/core/layer_buffer.h3
-rw-r--r--sdm/include/core/layer_stack.h37
-rw-r--r--sdm/include/private/strategy_interface.h1
-rw-r--r--sdm/include/utils/constants.h2
-rw-r--r--sdm/libs/core/comp_manager.cpp2
-rw-r--r--sdm/libs/core/display_base.cpp126
-rw-r--r--sdm/libs/core/display_base.h6
-rw-r--r--sdm/libs/core/strategy.cpp10
-rw-r--r--sdm/libs/core/strategy.h1
-rw-r--r--sdm/libs/hwc/Android.mk5
-rw-r--r--sdm/libs/hwc/hwc_display.cpp37
-rw-r--r--sdm/libs/hwc/hwc_display.h2
-rw-r--r--sdm/libs/hwc/hwc_tonemapper.cpp290
-rw-r--r--sdm/libs/hwc/hwc_tonemapper.h81
-rw-r--r--sdm/libs/hwc2/hwc_display.cpp7
15 files changed, 576 insertions, 34 deletions
diff --git a/sdm/include/core/layer_buffer.h b/sdm/include/core/layer_buffer.h
index 27a4f03a..4b42e7b0 100644
--- a/sdm/include/core/layer_buffer.h
+++ b/sdm/include/core/layer_buffer.h
@@ -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.
diff --git a/sdm/include/core/layer_stack.h b/sdm/include/core/layer_stack.h
index 096e88f5..701e3cab 100644
--- a/sdm/include/core/layer_stack.h
+++ b/sdm/include/core/layer_stack.h
@@ -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
diff --git a/sdm/include/private/strategy_interface.h b/sdm/include/private/strategy_interface.h
index 122a3c64..90e1064d 100644
--- a/sdm/include/private/strategy_interface.h
+++ b/sdm/include/private/strategy_interface.h
@@ -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() { }
diff --git a/sdm/include/utils/constants.h b/sdm/include/utils/constants.h
index 31129c1a..72b1bedb 100644
--- a/sdm/include/utils/constants.h
+++ b/sdm/include/utils/constants.h
@@ -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;
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 9fc44e08..199be867 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -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) {
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 98513c40..77b6edcf 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -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
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 4ea108e6..85a1bc2e 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -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
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index f4a5088c..c987fd0b 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -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
diff --git a/sdm/libs/core/strategy.h b/sdm/libs/core/strategy.h
index 3fadd0df..a84d1398 100644
--- a/sdm/libs/core/strategy.h
+++ b/sdm/libs/core/strategy.h
@@ -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();
diff --git a/sdm/libs/hwc/Android.mk b/sdm/libs/hwc/Android.mk
index 259a727c..d2828b46 100644
--- a/sdm/libs/hwc/Android.mk
+++ b/sdm/libs/hwc/Android.mk
@@ -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
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index 1108c393..305ed668 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -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;
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index bf51222f..dad78b66 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -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);
diff --git a/sdm/libs/hwc/hwc_tonemapper.cpp b/sdm/libs/hwc/hwc_tonemapper.cpp
new file mode 100644
index 00000000..694acc0d
--- /dev/null
+++ b/sdm/libs/hwc/hwc_tonemapper.cpp
@@ -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
diff --git a/sdm/libs/hwc/hwc_tonemapper.h b/sdm/libs/hwc/hwc_tonemapper.h
new file mode 100644
index 00000000..7ed53735
--- /dev/null
+++ b/sdm/libs/hwc/hwc_tonemapper.h
@@ -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__
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 14d70147..f603f183 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -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;
}