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:
committed by
Gerrit - the friendly Code Review server
parent
2b75da399a
commit
bf2b25c106
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() { }
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
290
sdm/libs/hwc/hwc_tonemapper.cpp
Normal file
290
sdm/libs/hwc/hwc_tonemapper.cpp
Normal 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
|
||||
81
sdm/libs/hwc/hwc_tonemapper.h
Normal file
81
sdm/libs/hwc/hwc_tonemapper.h
Normal 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__
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user