diff options
author | Arun Kumar K.R <akumarkr@codeaurora.org> | 2016-11-09 01:32:25 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-12-16 11:26:51 -0800 |
commit | bf2b25c1064e856a69821d7e65148f3ed3544ee5 (patch) | |
tree | 45fcd24e98fdaaff324ffda235d29cf25df4c60d | |
parent | 2b75da399a3cf0c1299e62bf5a6738a052928529 (diff) | |
download | display-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.h | 3 | ||||
-rw-r--r-- | sdm/include/core/layer_stack.h | 37 | ||||
-rw-r--r-- | sdm/include/private/strategy_interface.h | 1 | ||||
-rw-r--r-- | sdm/include/utils/constants.h | 2 | ||||
-rw-r--r-- | sdm/libs/core/comp_manager.cpp | 2 | ||||
-rw-r--r-- | sdm/libs/core/display_base.cpp | 126 | ||||
-rw-r--r-- | sdm/libs/core/display_base.h | 6 | ||||
-rw-r--r-- | sdm/libs/core/strategy.cpp | 10 | ||||
-rw-r--r-- | sdm/libs/core/strategy.h | 1 | ||||
-rw-r--r-- | sdm/libs/hwc/Android.mk | 5 | ||||
-rw-r--r-- | sdm/libs/hwc/hwc_display.cpp | 37 | ||||
-rw-r--r-- | sdm/libs/hwc/hwc_display.h | 2 | ||||
-rw-r--r-- | sdm/libs/hwc/hwc_tonemapper.cpp | 290 | ||||
-rw-r--r-- | sdm/libs/hwc/hwc_tonemapper.h | 81 | ||||
-rw-r--r-- | sdm/libs/hwc2/hwc_display.cpp | 7 |
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; } |