android13/hardware/rockchip/hwcomposer/drmhwc/hwcomposer.cpp

4505 lines
151 KiB
C++
Executable File

/*
* Copyright (C) 2018 Fuzhou Rockchip Electronics Co.Ltd.
*
* Modification based on code covered by the Apache License, Version 2.0 (the "License").
* You may not use this software except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS TO YOU ON AN "AS IS" BASIS
* AND ANY AND ALL WARRANTIES AND REPRESENTATIONS WITH RESPECT TO SUCH SOFTWARE, WHETHER EXPRESS,
* IMPLIED, STATUTORY OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF TITLE,
* NON-INFRINGEMENT, MERCHANTABILITY, SATISFACTROY QUALITY, ACCURACY OR FITNESS FOR A PARTICULAR
* PURPOSE 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.
*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#define LOG_TAG "hwcomposer-drm"
#include "drmhwcomposer.h"
#include "drmeventlistener.h"
#include "drmresources.h"
#include "platform.h"
#include "virtualcompositorworker.h"
#include "vsyncworker.h"
#include "autolock.h"
#include <stdlib.h>
#include <cinttypes>
#include <map>
#include <vector>
#include <sstream>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#ifdef ANDROID_P
#include <log/log.h>
#include <libsync/sw_sync.h>
#include <android/sync.h>
#else
#include <cutils/log.h>
#include <sw_sync.h>
#include <sync/sync.h>
#endif
#include <cutils/properties.h>
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
#include <utils/Trace.h>
#include <drm_fourcc.h>
#if RK_DRM_GRALLOC
#include "gralloc_drm_handle.h"
#endif
#include <linux/fb.h>
#include "hwc_util.h"
#include "hwc_rockchip.h"
#include <android/configuration.h>
#define UM_PER_INCH 25400
#if USE_GRALLOC_4
#include "drmgralloc4.h"
#endif
namespace android {
static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
int index);
static int update_display_bestmode(hwc_drm_display_t *hd, int display, DrmConnector *c);
#if SKIP_BOOT
static unsigned int g_boot_cnt = 0;
#endif
static unsigned int g_boot_gles_cnt = 0;
static unsigned int g_extern_gles_cnt = 0;
static bool g_bSkipExtern = false;
#ifdef USE_HWC2
static bool g_hasHotplug = false;
// Must to wait hwc-set to send Hotplug event
// If you don't do this, there will be problems with the hot-plugging device registration and destruction timing.
// In severe cases, the fence fd will leak or the system will not respond.
static bool g_waitHwcSetHotplug = false;
#endif
//#if RK_INVALID_REFRESH
hwc_context_t* g_ctx = NULL;
//#endif
class DummySwSyncTimeline {
public:
int Init() {
int ret = timeline_fd_.Set(sw_sync_timeline_create());
if (ret < 0)
return ret;
return 0;
}
UniqueFd CreateDummyFence() {
int ret = sw_sync_fence_create(timeline_fd_.get(), "dummy fence",
timeline_pt_ + 1);
if (ret < 0) {
ALOGE("Failed to create dummy fence %d", ret);
return ret;
}
UniqueFd ret_fd(ret);
ret = sw_sync_timeline_inc(timeline_fd_.get(), 1);
if (ret) {
ALOGE("Failed to increment dummy sync timeline %d", ret);
return ret;
}
++timeline_pt_;
return ret_fd;
}
private:
UniqueFd timeline_fd_;
int timeline_pt_ = 0;
};
struct CheckedOutputFd {
CheckedOutputFd(int *fd, const char *description,
DummySwSyncTimeline &timeline)
: fd_(fd), description_(description), timeline_(timeline) {
}
CheckedOutputFd(CheckedOutputFd &&rhs)
: description_(rhs.description_), timeline_(rhs.timeline_) {
std::swap(fd_, rhs.fd_);
}
CheckedOutputFd &operator=(const CheckedOutputFd &rhs) = delete;
~CheckedOutputFd() {
if (fd_ == NULL)
return;
if (*fd_ >= 0)
return;
*fd_ = timeline_.CreateDummyFence().Release();
if (*fd_ < 0)
ALOGE("Failed to fill %s (%p == %d) before destruction",
description_.c_str(), fd_, *fd_);
}
private:
int *fd_ = NULL;
std::string description_;
DummySwSyncTimeline &timeline_;
};
// map of display:hwc_drm_display_t
typedef std::map<int, hwc_drm_display_t> DisplayMap;
class DrmHotplugHandler : public DrmEventHandler {
public:
void Init(DisplayMap* displays, DrmResources *drm, const struct hwc_procs *procs) {
displays_ = displays;
drm_ = drm;
procs_ = procs;
int ret = pthread_mutex_init(&lock_, NULL);
if (ret) {
ALOGE("Failed to initialize drm compositor lock %d\n", ret);
return;
}
}
void HandleEvent(uint64_t timestamp_us) {
AutoLock lock(&lock_, __func__);
if (lock.Lock())
return;
DrmConnector *extend = NULL;
DrmConnector *primary = NULL;
for (auto &conn : drm_->connectors()) {
//In sleep mode,we need get raw connector state,otherwise,we will miss the chance
//to handle hotplug event.
//Pg: sleep (force_disconnect will be true)==> plug out HDMI ==> plug in HDMI ==> wake up (force_disconnect still be ture)
//Workround: use raw connector state.
drmModeConnection old_state = conn->raw_state();
conn->UpdateModes();
drmModeConnection cur_state = conn->raw_state();
if (cur_state == old_state)
continue;
ALOGI("hwc_hotplug: %s event @%" PRIu64 " for connector %u type=%s, type_id=%d\n",
cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us,
conn->id(),drm_->connector_type_str(conn->get_type()),conn->type_id());
if (cur_state == DRM_MODE_CONNECTED) {
/*
* if connector is only one , only to use primary. by libin
*/
if (drm_->connectors().size() == 1){
primary = conn.get();
ALOGI("connectors_.size()=%u only primary\n",(uint32_t)drm_->connectors().size());
}else{
if (conn->possible_displays() & HWC_DISPLAY_EXTERNAL_BIT){
ALOGD("hwc_hotplug: find the first connect external type=%s(%d)",
drm_->connector_type_str(conn->get_type()), conn->type_id());
extend = conn.get();
}
else if (conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT){
ALOGD("hwc_hotplug: find the first connect primary type=%s(%d)",
drm_->connector_type_str(conn->get_type()), conn->type_id());
primary = conn.get();
}
}
}
}
/*
* status changed?
*/
drm_->DisplayChanged();
DrmConnector *old_primary = drm_->GetConnectorFromType(HWC_DISPLAY_PRIMARY);
primary = primary ? primary : old_primary;
if (!primary || primary->raw_state() != DRM_MODE_CONNECTED) {
primary = NULL;
for (auto &conn : drm_->connectors()) {
if (!(conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT))
continue;
if (conn->raw_state() == DRM_MODE_CONNECTED) {
primary = conn.get();
ALOGD("hwc_hotplug: find the second connect primary type=%s(%d)",
drm_->connector_type_str(conn->get_type()), conn->type_id());
break;
}
}
}
if (!primary) {
for (auto &conn : drm_->connectors()) {
if (!(conn->possible_displays() & HWC_DISPLAY_PRIMARY_BIT))
continue;
ALOGD("hwc_hotplug: find the third primary type=%s(%d)",
drm_->connector_type_str(conn->get_type()), conn->type_id());
primary = conn.get();
}
}
if (!primary) {
ALOGE("hwc_hotplug: %s %d Failed to find primary display\n", __FUNCTION__, __LINE__);
return;
}
//ClearDisplay show be called before display update(SetPrimaryDisplay/SetExtendDisplay).
//It will singal the original disconnect display.
drm_->ClearDisplay();
if (primary != old_primary) {
hwc_drm_display_t *hd = &(*displays_)[primary->display()];
hwc_drm_display_t *old_hd = &(*displays_)[old_primary->display()];
update_display_bestmode(hd, HWC_DISPLAY_PRIMARY, primary);
DrmMode mode = primary->best_mode();
primary->set_current_mode(mode);
hd->framebuffer_width = old_hd->framebuffer_width;
hd->framebuffer_height = old_hd->framebuffer_height;
hd->rel_xres = mode.h_display();
hd->rel_yres = mode.v_display();
hd->v_total = mode.v_total();
//rk: Avoid fb handle is null which lead HDMI display nothing with GLES.
usleep(HOTPLUG_MSLEEP*1000);
procs_->invalidate(procs_);
drm_->SetPrimaryDisplay(primary);
}
DrmConnector *old_extend = drm_->GetConnectorFromType(HWC_DISPLAY_EXTERNAL);
extend = extend ? extend : old_extend;
if (!extend || extend->raw_state() != DRM_MODE_CONNECTED) {
extend = NULL;
for (auto &conn : drm_->connectors()) {
if (!(conn->possible_displays() & HWC_DISPLAY_EXTERNAL_BIT))
continue;
if (conn->id() == primary->id())
continue;
if (conn->raw_state() == DRM_MODE_CONNECTED) {
extend = conn.get();
ALOGD("hwc_hotplug: find the second connect external type=%s(%d)",
drm_->connector_type_str(conn->get_type()), conn->type_id());
break;
}
}
}
drm_->SetExtendDisplay(extend);
if (!extend) {
#ifdef USE_HWC2
g_waitHwcSetHotplug = false;
procs_->invalidate(procs_);
while(!g_waitHwcSetHotplug && g_hasHotplug){
usleep(2000);
}
#endif
procs_->hotplug(procs_, HWC_DISPLAY_EXTERNAL, 0);
/**********************long-running operations should move back of hotplug**************************/
/*
* If Connector changed ,update baseparameter , resolution , color.
*/
hwc_get_baseparameter_config(NULL,0,BP_UPDATE,0);
//When wake up from TV mode, it will bind crtc to TV connector.
//If we also plug in HDMI,and don't bind crtc to HDMI connector,
//the crtc of connected HDMI will be NULL. Which lead HDMI show nothing.
//Pg: Defect #149666
/**************************************************************************/
//2. We should get current mode before UpdateDisplayRoute.
//otherwise, it will lead crtc is disabled when current mode is 0
//when boot system sometimes.
drm_->UpdateDisplayRoute();
//Update LUT from baseparameter when Hot_plug devices conneted
hwc_SetGamma(drm_);
//rk: Avoid fb handle is null which lead HDMI display nothing with GLES.
usleep(HOTPLUG_MSLEEP*1000);
procs_->invalidate(procs_);
return;
}
//if extend is connected at boot time, to upload this hotplug event.
#ifdef USE_HWC2
if( extend != old_extend || (!g_hasHotplug && extend != NULL)){
#else
if( extend != old_extend){
#endif
hwc_drm_display_t *hd = &(*displays_)[extend->display()];
update_display_bestmode(hd, HWC_DISPLAY_EXTERNAL, extend);
DrmMode mode = extend->best_mode();
extend->set_current_mode(mode);
char framebuffer_size[PROPERTY_VALUE_MAX];
uint32_t width = 0, height = 0 , vrefresh = 0 ;
property_get("persist." PROPERTY_TYPE ".framebuffer.aux", framebuffer_size, "use_baseparameter");
/*
* if unset framebuffer_size, get it from baseparameter , by libin
*/
if(hwc_have_baseparameter() && !strcmp(framebuffer_size,"use_baseparameter")){
int res = 0;
res = hwc_get_baseparameter_config(framebuffer_size,HWC_DISPLAY_EXTERNAL,BP_FB_SIZE,0);
if(res)
ALOGW("BP: hwc get baseparameter config err ,res = %d",res);
}
sscanf(framebuffer_size, "%dx%d@%d", &width, &height, &vrefresh);
if (width && height) {
hd->framebuffer_width = width;
hd->framebuffer_height = height;
hd->vrefresh = vrefresh ? vrefresh : 60;
} else if (mode.h_display() && mode.v_display() && mode.v_refresh()) {
hd->framebuffer_width = mode.h_display();
hd->framebuffer_height = mode.v_display();
hd->vrefresh = mode.v_refresh();
/*
* Limit to 1080p if large than 2160p
*/
if (hd->framebuffer_height >= 2160 && hd->framebuffer_width >= hd->framebuffer_height) {
hd->framebuffer_width = hd->framebuffer_width * (1080.0 / hd->framebuffer_height);
hd->framebuffer_height = 1080;
}
} else {
hd->framebuffer_width = 1920;
hd->framebuffer_height = 1080;
hd->vrefresh = 60;
ALOGE("Failed to find available display mode for display %d\n", HWC_DISPLAY_EXTERNAL);
}
hd->rel_xres = mode.h_display();
hd->rel_yres = mode.v_display();
hd->v_total = mode.v_total();
hd->active = false;
g_bSkipExtern = true;
g_extern_gles_cnt = 0;
#ifdef USE_HWC2
g_waitHwcSetHotplug = false;
procs_->invalidate(procs_);
while(!g_waitHwcSetHotplug && g_hasHotplug){
usleep(2000);
}
#endif
procs_->hotplug(procs_, HWC_DISPLAY_EXTERNAL, 0);
usleep(64 * 1000);
hd->active = true;
procs_->hotplug(procs_, HWC_DISPLAY_EXTERNAL, 1);
}
/**********************long-running operations should move back of hotplug**************************/
/*
* If Connector changed ,update baseparameter , resolution , color.
*/
hwc_get_baseparameter_config(NULL,0,BP_UPDATE,0);
//1. When wake up from TV mode, it will bind crtc to TV connector.
//If we also plug in HDMI,and don't bind crtc to HDMI connector,
//the crtc of connected HDMI will be NULL. Which lead HDMI show nothing.
//Pg: Defect #149666
/**************************************************************************/
//2. We should get current mode before UpdateDisplayRoute.
//otherwise, it will lead crtc is disabled when current mode is 0
//when boot system sometimes.
drm_->UpdateDisplayRoute();
//Update LUT from baseparameter when Hot_plug devices conneted
hwc_SetGamma(drm_);
#ifdef USE_HWC2
if(!g_hasHotplug)
g_hasHotplug = true;
#endif
//rk: Avoid fb handle is null which lead HDMI display nothing with GLES.
usleep(HOTPLUG_MSLEEP*1000);
procs_->invalidate(procs_);
}
private:
DrmResources *drm_ = NULL;
const struct hwc_procs *procs_ = NULL;
DisplayMap* displays_ = NULL;
pthread_mutex_t lock_;
};
struct hwc_context_t {
// map of display:hwc_drm_display_t
typedef std::map<int, hwc_drm_display_t> DisplayMap;
~hwc_context_t() {
virtual_compositor_worker.Exit();
}
hwc_composer_device_1_t device;
hwc_procs_t const *procs = NULL;
DisplayMap displays;
DrmResources drm;
std::unique_ptr<Importer> importer;
const gralloc_module_t *gralloc;
DummySwSyncTimeline dummy_timeline;
VirtualCompositorWorker virtual_compositor_worker;
DrmHotplugHandler hotplug_handler;
VSyncWorker primary_vsync_worker;
VSyncWorker extend_vsync_worker;
int fb_fd;
int fb_blanked;
int hdmi_status_fd;
int dp_status_fd;
#if RK_CTS_WORKROUND
FILE* regFile;
#endif
bool isGLESComp;
#if RK_INVALID_REFRESH
bool mOneWinOpt;
threadPamaters mRefresh;
#endif
#if RK_STEREO
bool is_3d;
//int fd_3d;
//threadPamaters mControlStereo;
#endif
bool hdr_video_compose_by_gles = false;
std::vector<DrmCompositionDisplayPlane> comp_plane_group;
std::vector<DrmHwcDisplayContents> layer_contents;
};
static void *hotplug_event_thread(void *arg){
hwc_context_t* ctx = (hwc_context_t*)arg;
ctx->hotplug_handler.HandleEvent(0);
pthread_exit(NULL);
return NULL;
}
/**
* sys.3d_resolution.main 1920x1080p60-114693:148500
* width x height p|i refresh-flag:clock
*/
static int update_display_bestmode(hwc_drm_display_t *hd, int display, DrmConnector *c)
{
char resolution[PROPERTY_VALUE_MAX];
char resolution_3d[PROPERTY_VALUE_MAX];
uint32_t width, height, flags;
uint32_t hsync_start, hsync_end, htotal;
uint32_t vsync_start, vsync_end, vtotal;
uint32_t width_3d, height_3d, vrefresh_3d, flag_3d, clk_3d;
bool interlaced, interlaced_3d;
float vrefresh;
char val,val_3d;
int timeline;
static uint32_t last_mainType,last_auxType;
uint32_t MaxResolution = 0,temp;
timeline = property_get_int32( PROPERTY_TYPE ".display.timeline", -1);
/*
* force update propetry when timeline is zero or not exist.
*/
if (timeline && timeline == hd->display_timeline &&
hd->hotplug_timeline == hd->ctx->drm.timeline())
return 0;
hd->display_timeline = timeline;
hd->hotplug_timeline = hd->ctx->drm.timeline();
if (display == HWC_DISPLAY_PRIMARY)
{
if(hwc_have_baseparameter() && c->get_type() != last_mainType)
{
property_set("persist." PROPERTY_TYPE ".resolution.main","use_baseparameter");
ALOGD("BP:DisplayDevice change type[%d] => type[%d],to update main resolution",last_mainType,c->get_type());
last_mainType = c->get_type();
}
/* if baseparameter exist to use it, if none set to "Auto" */
if(hwc_have_baseparameter()){
property_get("persist." PROPERTY_TYPE ".resolution.main", resolution, "use_baseparameter");
property_get( PROPERTY_TYPE ".3d_resolution.main", resolution_3d, "0x0p0-0:0");
if(!(strcmp(resolution,"use_baseparameter"))){
int res = 0;
res = hwc_get_baseparameter_config(resolution,display,BP_RESOLUTION,c->get_type());
if(res){
ALOGE("BP:Get main BP_RESOLUTION fail, res = %d line =%d",res,__LINE__);
}
}
}else{
property_get("persist." PROPERTY_TYPE ".resolution.main", resolution, "Auto");
property_get( PROPERTY_TYPE ".3d_resolution.main", resolution_3d, "0x0p0-0:0");
}
}
else
{
if(hwc_have_baseparameter() && c->get_type() != last_auxType)
{
property_set("persist." PROPERTY_TYPE ".resolution.aux","use_baseparameter");
ALOGD("BP:DisplayDevice change type[%d] => type[%d],to update aux resolution",last_auxType,c->get_type());
last_auxType = c->get_type();
}
/* if baseparameter exist to use it, if none set to "Auto" */
if(hwc_have_baseparameter()){
property_get("persist." PROPERTY_TYPE ".resolution.aux", resolution, "use_baseparameter");
property_get( PROPERTY_TYPE ".3d_resolution.aux", resolution_3d, "0x0p0-0:0");
if(!(strcmp(resolution,"use_baseparameter"))){
int res = 0;
res = hwc_get_baseparameter_config(resolution,display,BP_RESOLUTION,c->get_type());
if(res){
ALOGE("BP:Get aux BP_RESOLUTION fail, res = %d line =%d",res,__LINE__);
}
}
}else{
property_get("persist." PROPERTY_TYPE ".resolution.aux", resolution, "Auto");
property_get( PROPERTY_TYPE ".3d_resolution.aux", resolution_3d, "0x0p0-0:0");
}
}
hwc_set_baseparameter_config(&hd->ctx->drm);
if(hd->is_3d && strcmp(resolution_3d,"0x0p0-0:0"))
{
ALOGD_IF(log_level(DBG_DEBUG), "Enter 3d resolution=%s",resolution_3d);
sscanf(resolution_3d, "%dx%d%c%d-%d:%d", &width_3d, &height_3d, &val_3d,
&vrefresh_3d, &flag_3d, &clk_3d);
if (val_3d == 'i')
interlaced_3d = true;
else
interlaced_3d = false;
if (width_3d != 0 && height_3d != 0) {
//use raw mode,otherwise it may filter by resolution_white.xml
for (const DrmMode &conn_mode : c->raw_modes()) {
if (conn_mode.equal(width_3d, height_3d, vrefresh_3d, flag_3d, clk_3d, interlaced_3d)) {
ALOGD_IF(log_level(DBG_DEBUG), "Match 3D parameters: w=%d,h=%d,val=%c,vrefresh_3d=%d,flag=%d,clk=%d",
width_3d,height_3d,val_3d,vrefresh_3d,flag_3d,clk_3d);
c->set_best_mode(conn_mode);
return 0;
}
}
}
}
else if (strcmp(resolution,"Auto") != 0)
{
int len = sscanf(resolution, "%dx%d@%f-%d-%d-%d-%d-%d-%d-%x",
&width, &height, &vrefresh, &hsync_start,
&hsync_end, &htotal, &vsync_start,&vsync_end,
&vtotal, &flags);
if (len == 10 && width != 0 && height != 0) {
for (const DrmMode &conn_mode : c->modes()) {
if (conn_mode.equal(width, height, vrefresh, hsync_start, hsync_end,
htotal, vsync_start, vsync_end, vtotal, flags)) {
c->set_best_mode(conn_mode);
return 0;
}
}
}
uint32_t ivrefresh;
len = sscanf(resolution, "%dx%d%c%d", &width, &height, &val, &ivrefresh);
if (val == 'i')
interlaced = true;
else
interlaced = false;
if (len == 4 && width != 0 && height != 0) {
for (const DrmMode &conn_mode : c->modes()) {
if (conn_mode.equal(width, height, ivrefresh, interlaced)) {
c->set_best_mode(conn_mode);
return 0;
}
}
}
}
for (const DrmMode &conn_mode : c->modes()) {
if (conn_mode.type() & DRM_MODE_TYPE_PREFERRED) {
c->set_best_mode(conn_mode);
return 0;
}
else {
temp = conn_mode.h_display()*conn_mode.v_display();
if(MaxResolution <= temp)
MaxResolution = temp;
}
}
for (const DrmMode &conn_mode : c->modes()) {
if(MaxResolution == conn_mode.h_display()*conn_mode.v_display()) {
c->set_best_mode(conn_mode);
return 0;
}
}
//use raw modes to get mode.
for (const DrmMode &conn_mode : c->raw_modes()) {
if (conn_mode.type() & DRM_MODE_TYPE_PREFERRED) {
c->set_best_mode(conn_mode);
return 0;
}
else {
temp = conn_mode.h_display()*conn_mode.v_display();
if(MaxResolution <= temp)
MaxResolution = temp;
}
}
for (const DrmMode &conn_mode : c->raw_modes()) {
if(MaxResolution == conn_mode.h_display()*conn_mode.v_display()) {
c->set_best_mode(conn_mode);
return 0;
}
}
ALOGE("Error: Should not get here display=%d %s %d\n", display, __FUNCTION__, __LINE__);
DrmMode mode;
c->set_best_mode(mode);
return -ENOENT;
}
static native_handle_t *dup_buffer_handle(buffer_handle_t handle) {
native_handle_t *new_handle =
native_handle_create(handle->numFds, handle->numInts);
if (new_handle == NULL)
return NULL;
const int *old_data = handle->data;
int *new_data = new_handle->data;
for (int i = 0; i < handle->numFds; i++) {
*new_data = dup(*old_data);
old_data++;
new_data++;
}
memcpy(new_data, old_data, sizeof(int) * handle->numInts);
return new_handle;
}
static void free_buffer_handle(native_handle_t *handle) {
int ret = native_handle_close(handle);
if (ret)
ALOGE("Failed to close native handle %d", ret);
ret = native_handle_delete(handle);
if (ret)
ALOGE("Failed to delete native handle %d", ret);
}
const hwc_drm_bo *DrmHwcBuffer::operator->() const {
if (importer_ == NULL) {
ALOGE("Access of non-existent BO");
exit(1);
return NULL;
}
return &bo_;
}
void DrmHwcBuffer::Clear() {
if (importer_ != NULL) {
importer_->ReleaseBuffer(&bo_);
importer_ = NULL;
}
}
int DrmHwcBuffer::ImportBuffer(buffer_handle_t handle, Importer *importer
#if RK_VIDEO_SKIP_LINE
, uint32_t SkipLine
#endif
) {
hwc_drm_bo tmp_bo;
int ret = importer->ImportBuffer(handle, &tmp_bo
#if RK_VIDEO_SKIP_LINE
, SkipLine
#endif
);
if (ret)
return ret;
if (importer_ != NULL) {
importer_->ReleaseBuffer(&bo_);
}
importer_ = importer;
bo_ = tmp_bo;
return 0;
}
int DrmHwcNativeHandle::CopyBufferHandle(buffer_handle_t handle,
const gralloc_module_t *gralloc) {
#if USE_GRALLOC_4
/* import 'handle' 得到对应的 新的 imported 的 buffer_handle_t 实例. */
buffer_handle_t handle_copy;
status_t ret = gralloc4::importBuffer(handle, &handle_copy);
if ( ret != NO_ERROR )
{
ALOGE("err. ret : %d", ret);
return ret;
}
#else // USE_GRALLOC_4
native_handle_t *handle_copy = dup_buffer_handle(handle);
if (handle_copy == NULL) {
ALOGE("Failed to duplicate handle");
return -ENOMEM;
}
int ret = gralloc->registerBuffer(gralloc, handle_copy);
if (ret) {
ALOGE("Failed to register buffer handle %d", ret);
free_buffer_handle(handle_copy);
return ret;
}
#endif // USE_GRALLOC_4
Clear();
gralloc_ = gralloc;
handle_ = const_cast<native_handle_t*>(handle_copy);
return 0;
}
DrmHwcNativeHandle::~DrmHwcNativeHandle() {
Clear();
pthread_mutex_destroy(&lock_);
}
void DrmHwcNativeHandle::Clear() {
AutoLock lock(&lock_, "DrmHwcNativeHandle::Clear");
int ret = lock.Lock();
if (ret)
return;
#if USE_GRALLOC_4
if ( handle_ != NULL )
{
gralloc4::freeBuffer(handle_);
gralloc_ = NULL;
handle_ = NULL;
}
#else // USE_GRALLOC_4
if (gralloc_ != NULL && handle_ != NULL) {
gralloc_->unregisterBuffer(gralloc_, handle_);
free_buffer_handle(handle_);
gralloc_ = NULL;
handle_ = NULL;
}
#endif // USE_GRALLOC_4
}
static const char *DrmFormatToString(uint32_t drm_format) {
switch (drm_format) {
case DRM_FORMAT_BGR888:
return "DRM_FORMAT_BGR888";
case DRM_FORMAT_ARGB8888:
return "DRM_FORMAT_ARGB8888";
case DRM_FORMAT_XBGR8888:
return "DRM_FORMAT_XBGR8888";
case DRM_FORMAT_ABGR8888:
return "DRM_FORMAT_ABGR8888";
case DRM_FORMAT_BGR565:
return "DRM_FORMAT_BGR565";
case DRM_FORMAT_YVU420:
return "DRM_FORMAT_YVU420";
case DRM_FORMAT_NV12:
return "DRM_FORMAT_NV12";
default:
return "<invalid>";
}
}
static void DumpBuffer(const DrmHwcBuffer &buffer, std::ostringstream *out) {
if (!buffer) {
*out << "buffer=<invalid>";
return;
}
*out << "buffer[w/h/format]=";
*out << buffer->width << "/" << buffer->height << "/" << DrmFormatToString(buffer->format);
}
static const char *TransformToString(uint32_t transform) {
switch (transform) {
case DrmHwcTransform::kIdentity:
return "IDENTITY";
case DrmHwcTransform::kFlipH:
return "FLIPH";
case DrmHwcTransform::kFlipV:
return "FLIPV";
case DrmHwcTransform::kRotate90:
return "ROTATE90";
case DrmHwcTransform::kRotate180:
return "ROTATE180";
case DrmHwcTransform::kRotate270:
return "ROTATE270";
default:
return "<invalid>";
}
}
const char *BlendingToString(DrmHwcBlending blending) {
switch (blending) {
case DrmHwcBlending::kNone:
return "NONE";
case DrmHwcBlending::kPreMult:
return "PREMULT";
case DrmHwcBlending::kCoverage:
return "COVERAGE";
default:
return "<invalid>";
}
}
void DrmHwcLayer::dump_drm_layer(int index, std::ostringstream *out) const {
*out << "DrmHwcLayer[" << index << "] ";
DumpBuffer(buffer,out);
*out << " transform=" << TransformToString(transform)
<< " blending[a=" << (int)alpha
<< "]=" << BlendingToString(blending) << " source_crop";
source_crop.Dump(out);
*out << " handle parameter";
*out << "[w/h/s]=" << width << "/" << height << "/" << stride;
*out << " display_frame";
display_frame.Dump(out);
*out << "\n";
}
int DrmHwcLayer::InitFromHwcLayer(struct hwc_context_t *ctx, int display, hwc_layer_1_t *sf_layer, Importer *importer,
const gralloc_module_t *gralloc, bool bClone) {
DrmConnector *c;
DrmMode mode;
unsigned int size;
int ret = 0;
int src_w, src_h, dst_w, dst_h;
hwc_region_t * visible_region = &sf_layer->visibleRegionScreen;
hwc_rect_t const * visible_rects = visible_region->rects;
int left_min = 0, top_min = 0, right_max = 0, bottom_max=0;
UN_USED(importer);
bClone_ = bClone;
#if RK_3D_VIDEO
int32_t alreadyStereo = 0;
#ifdef USE_HWC2
if(sf_layer->handle)
{
alreadyStereo = hwc_get_handle_alreadyStereo(ctx->gralloc, sf_layer->handle);
if(alreadyStereo < 0)
{
ALOGE("hwc_get_handle_alreadyStereo fail");
alreadyStereo = 0;
}
}
#else
alreadyStereo = sf_layer->alreadyStereo;
#endif
stereo = alreadyStereo;
#endif
if(sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
bFbTarget_ = true;
else
bFbTarget_ = false;
if(sf_layer->flags & HWC_SKIP_LAYER)
bSkipLayer = true;
else
bSkipLayer = false;
#if RK_VIDEO_SKIP_LINE
SkipLine = 0;
#endif
bUse = true;
sf_handle = sf_layer->handle;
raw_sf_layer = sf_layer;
mlayer = sf_layer;
alpha = sf_layer->planeAlpha;
frame_no = get_frame();
DrmConnector *conn = ctx->drm.GetConnectorFromType(display);
if (!conn) {
ALOGE("%s:Failed to get connector for display %d line=%d", __FUNCTION__,display,__LINE__);
return -ENODEV;
}
hwc_drm_display_t *hd = &ctx->displays[conn->display()];
#if DUAL_VIEW_MODE
int dualModeEnable = 0,dualModeTB = 0,dualModeRatioPri = 0,dualModeRatioAux = 0;
char value[PROPERTY_VALUE_MAX];
property_get("persist." PROPERTY_TYPE ".dualModeEnable", value, "0");
dualModeEnable = atoi(value);
property_get("persist." PROPERTY_TYPE ".dualModeTB", value, "0");
dualModeTB = atoi(value);
property_get("persist." PROPERTY_TYPE ".dualModeRatioPri", value, "0");
dualModeRatioPri = atoi(value);
property_get("persist." PROPERTY_TYPE ".dualModeRatioAux", value, "0");
dualModeRatioAux = atoi(value);
//DUAL_VIEW_MODE only support 2 or 3 Ratio
if(dualModeRatioPri == 0 || dualModeRatioAux == 0){
ALOGE_IF(log_level(DBG_ERROR),"DUAL:Not support 0 Ration (%d:%d) , disable DUAL_VIEW_MODE",dualModeRatioPri,dualModeRatioAux);
dualModeEnable = 0;
}
//DUAL_VIEW_MODE Primary framebuffer must equal to Extend
char framebuffer_size_pri[PROPERTY_VALUE_MAX] = {0};
char framebuffer_size_aux[PROPERTY_VALUE_MAX] = {0};
property_get("persist." PROPERTY_TYPE ".framebuffer.main", framebuffer_size_pri, "main");
property_get("persist." PROPERTY_TYPE ".framebuffer.aux", framebuffer_size_aux, "aux");
if(strcmp(framebuffer_size_pri,framebuffer_size_aux)){
ALOGE_IF(log_level(DBG_ERROR),"DUAL:Primary framebuffer is not equal to Extend, disable DUAL_VIEW_MODE");
dualModeEnable = 0;
}
if(dualModeEnable == 1){
hd->bDualViewMode = true;
property_set( PROPERTY_TYPE ".hwc.compose_policy","0");
if(display == 0){
if(dualModeTB == 1)
source_crop = DrmHwcRect<float>(
sf_layer->sourceCropf.left, sf_layer->sourceCropf.top,
sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom / (dualModeRatioPri + dualModeRatioAux) * dualModeRatioPri);
else
source_crop = DrmHwcRect<float>(
sf_layer->sourceCropf.left, sf_layer->sourceCropf.top,
sf_layer->sourceCropf.right / (dualModeRatioPri + dualModeRatioAux) * dualModeRatioPri , sf_layer->sourceCropf.bottom);
}else if(display == 1){
if(dualModeTB == 1)
source_crop = DrmHwcRect<float>(
sf_layer->sourceCropf.left, sf_layer->sourceCropf.top + sf_layer->sourceCropf.bottom / (dualModeRatioPri + dualModeRatioAux) * dualModeRatioPri,
sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom);
else
source_crop = DrmHwcRect<float>(
sf_layer->sourceCropf.left + sf_layer->sourceCropf.right / (dualModeRatioPri + dualModeRatioAux) * dualModeRatioPri , sf_layer->sourceCropf.top,
sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom);
}
}else
#endif
{
source_crop = DrmHwcRect<float>(
sf_layer->sourceCropf.left, sf_layer->sourceCropf.top,
sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom);
}
if(bClone)
{
//int panle_height = hd->rel_yres + hd->v_total;
//int y_offset = (panle_height - panle_height * 3 / 147) / 2 + panle_height * 3 / 147;
int y_offset = hd->v_total;
display_frame = DrmHwcRect<int>(
hd->w_scale * sf_layer->displayFrame.left, hd->h_scale * sf_layer->displayFrame.top + y_offset,
hd->w_scale * sf_layer->displayFrame.right, hd->h_scale * sf_layer->displayFrame.bottom + y_offset);
}
else
{
if(stereo == FPS_3D)
{
int y_offset = hd->v_total;
display_frame = DrmHwcRect<int>(
hd->w_scale * sf_layer->displayFrame.left, hd->h_scale * sf_layer->displayFrame.top,
hd->w_scale * sf_layer->displayFrame.right, hd->h_scale * sf_layer->displayFrame.bottom + y_offset);
}
else
{
display_frame = DrmHwcRect<int>(
hd->w_scale * sf_layer->displayFrame.left, hd->h_scale * sf_layer->displayFrame.top,
hd->w_scale * sf_layer->displayFrame.right, hd->h_scale * sf_layer->displayFrame.bottom);
}
}
src_w = (int)(source_crop.right - source_crop.left);
src_h = (int)(source_crop.bottom - source_crop.top);
dst_w = (int)(display_frame.right - display_frame.left);
dst_h = (int)(display_frame.bottom - display_frame.top);
if(hd->is_interlaced)
{
//use vop plane scale instead of vop post scale.
char overscan[PROPERTY_VALUE_MAX];
int left_margin, right_margin, top_margin, bottom_margin;
float left_margin_f, right_margin_f, top_margin_f, bottom_margin_f;
float lscale = 0, tscale = 0, rscale = 0, bscale = 0;
int disp_old_l,disp_old_t,disp_old_r,disp_old_b;
if(hd->stereo_mode != NON_3D)
{
left_margin = 100;
top_margin = 100;
right_margin = 100;
bottom_margin = 100;
}
else
{
if (display == HWC_DISPLAY_PRIMARY){
if(hwc_have_baseparameter()){
property_get("persist." PROPERTY_TYPE ".overscan.main", overscan, "use_baseparameter");
if(!strcmp(overscan,"use_baseparameter"))
hwc_get_baseparameter_config(overscan,display,BP_OVERSCAN,0);
}else{
property_get("persist." PROPERTY_TYPE ".overscan.main", overscan, "overscan 100,100,100,100");
}
sscanf(overscan, "overscan %d,%d,%d,%d", &left_margin, &top_margin,
&right_margin, &bottom_margin);
}else{
if(hwc_have_baseparameter()){
property_get("persist." PROPERTY_TYPE ".overscan.aux", overscan, "use_baseparameter");
if(!strcmp(overscan,"use_baseparameter"))
hwc_get_baseparameter_config(overscan,display,BP_OVERSCAN,0);
}else{
property_get("persist." PROPERTY_TYPE ".overscan.aux", overscan, "overscan 100,100,100,100");
}
sscanf(overscan, "overscan %d,%d,%d,%d", &left_margin, &top_margin,
&right_margin, &bottom_margin);
}
}
//limit overscan to (OVERSCAN_MIN_VALUE,OVERSCAN_MAX_VALUE)
if (left_margin < OVERSCAN_MIN_VALUE) left_margin = OVERSCAN_MIN_VALUE;
if (top_margin < OVERSCAN_MIN_VALUE) top_margin = OVERSCAN_MIN_VALUE;
if (right_margin < OVERSCAN_MIN_VALUE) right_margin = OVERSCAN_MIN_VALUE;
if (bottom_margin < OVERSCAN_MIN_VALUE) bottom_margin = OVERSCAN_MIN_VALUE;
if (left_margin > OVERSCAN_MAX_VALUE) left_margin = OVERSCAN_MAX_VALUE;
if (top_margin > OVERSCAN_MAX_VALUE) top_margin = OVERSCAN_MAX_VALUE;
if (right_margin > OVERSCAN_MAX_VALUE) right_margin = OVERSCAN_MAX_VALUE;
if (bottom_margin > OVERSCAN_MAX_VALUE) bottom_margin = OVERSCAN_MAX_VALUE;
left_margin_f = (float)(100 - left_margin ) / 2;
top_margin_f = (float)(100 - top_margin ) / 2;
right_margin_f = (float)(100 - right_margin ) / 2;
bottom_margin_f = (float)(100 - bottom_margin) / 2;
lscale = ((float)left_margin_f / 100);
tscale = ((float)top_margin_f / 100);
rscale = ((float)right_margin_f / 100);
bscale = ((float)bottom_margin_f / 100);
disp_old_l = display_frame.left;
disp_old_t = display_frame.top;
disp_old_r = display_frame.right;
disp_old_b = display_frame.bottom;
display_frame.left = ((int)(display_frame.left * (1.0 - lscale - rscale)) + (int)(hd->rel_xres * lscale));
display_frame.top = ((int)(display_frame.top * (1.0 - tscale - bscale)) + (int)(hd->rel_yres * tscale));
dst_w -= ((int)(dst_w * lscale) + (int)(dst_w * rscale));
dst_h -= ((int)(dst_h * tscale) + (int)(dst_h * bscale));
display_frame.right = display_frame.left + dst_w;
display_frame.bottom = display_frame.top + dst_h;
ALOGD_IF(log_level(DBG_VERBOSE),"vop plane scale overscan, display margin(%f,%f,%f,%f) scale_factor(%f,%f,%f,%f) disp_area(%d,%d,%d,%d) ==> (%d,%d,%d,%d)",
left_margin_f,top_margin_f,right_margin_f,bottom_margin_f,
lscale,tscale,rscale,bscale,
disp_old_l,disp_old_t,disp_old_r,disp_old_b,
display_frame.left,display_frame.top,display_frame.right,display_frame.bottom);
}
c = ctx->drm.GetConnectorFromType(HWC_DISPLAY_PRIMARY);
if (!c) {
ALOGE("Failed to get DrmConnector for display %d", 0);
return -ENODEV;
}
mode = c->active_mode();
if(sf_handle)
{
#if (!RK_PER_MODE && RK_DRM_GRALLOC)
width = hwc_get_handle_attibute(gralloc,sf_layer->handle,ATT_WIDTH);
height = hwc_get_handle_attibute(gralloc,sf_layer->handle,ATT_HEIGHT);
stride = hwc_get_handle_attibute(gralloc,sf_layer->handle,ATT_STRIDE);
format = hwc_get_handle_attibute(gralloc,sf_layer->handle,ATT_FORMAT);
#else
width = hwc_get_handle_width(gralloc,sf_layer->handle);
height = hwc_get_handle_height(gralloc,sf_layer->handle);
stride = hwc_get_handle_stride(gralloc,sf_layer->handle);
format = hwc_get_handle_format(gralloc,sf_layer->handle);
#endif
}
else
{
format = HAL_PIXEL_FORMAT_RGBA_8888;
}
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12 || format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
is_yuv = true;
else
is_yuv = false;
rect_merge.left = display_frame.left;
rect_merge.top = display_frame.top;
rect_merge.right = display_frame.right;
rect_merge.bottom = display_frame.bottom;
if(visible_rects && format != HAL_PIXEL_FORMAT_YCrCb_NV12_VIDEO
&& format != HAL_PIXEL_FORMAT_YCrCb_NV12){
left_min = visible_rects[0].left;
top_min = visible_rects[0].top;
right_max = visible_rects[0].right;
bottom_max = visible_rects[0].bottom;
for (int r = 0; r < (int) visible_region->numRects; r++) {
int r_left;
int r_top;
int r_right;
int r_bottom;
r_left = hwcMAX(display_frame.left, visible_rects[r].left);
left_min = hwcMIN(r_left, left_min);
r_top = hwcMAX(display_frame.top, visible_rects[r].top);
top_min = hwcMIN(r_top, top_min);
r_right = hwcMIN(display_frame.right, visible_rects[r].right);
right_max = hwcMAX(r_right, right_max);
r_bottom = hwcMIN(display_frame.bottom, visible_rects[r].bottom);
bottom_max = hwcMAX(r_bottom, bottom_max);
}
rect_merge.left = hwcMAX(display_frame.left, left_min);
rect_merge.top = hwcMAX(display_frame.top, top_min);
rect_merge.right = hwcMIN(display_frame.right, right_max);
rect_merge.bottom = hwcMIN(display_frame.bottom, bottom_max);
}
if(hd->hasEotfPlane)
{
if(is_yuv)
{
uint32_t android_colorspace = hwc_get_layer_colorspace(sf_layer);
colorspace = colorspace_convert_to_linux(android_colorspace);
if(colorspace == 0)
{
colorspace = V4L2_COLORSPACE_DEFAULT;
}
if((android_colorspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_ST2084)
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s:line=%d has st2084",__FUNCTION__,__LINE__);
eotf = SMPTE_ST2084;
}
else
{
//ALOGE("Unknow etof %d",eotf);
eotf = TRADITIONAL_GAMMA_SDR;
}
}
else
{
//If enter GLES in HDR video,fake the fb target layer to HDR.
if(hd->isHdr && bFbTarget_)
{
colorspace = V4L2_COLORSPACE_BT2020;
eotf = SMPTE_ST2084;
}
else
{
colorspace = V4L2_COLORSPACE_DEFAULT;
eotf = TRADITIONAL_GAMMA_SDR;
}
}
}
else
{
if(is_yuv)
{
uint32_t android_colorspace = hwc_get_layer_colorspace(sf_layer);
colorspace = colorspace_convert_to_linux(android_colorspace);
if(colorspace == 0)
{
colorspace = V4L2_COLORSPACE_DEFAULT;
}
eotf = TRADITIONAL_GAMMA_SDR;
}else{
colorspace = V4L2_COLORSPACE_DEFAULT;
eotf = TRADITIONAL_GAMMA_SDR;
}
}
#if RK_BOX
if(is_yuv){
char value_yuv[PROPERTY_VALUE_MAX];
int scaleMode = 0;
property_get("persist." PROPERTY_TYPE ".video.cvrs",value_yuv, "0");
scaleMode = atoi(value_yuv);
if(scaleMode > 0){
ret = hwc_video_to_area(source_crop,display_frame,scaleMode);
if(ret == false)
ALOGE("hwc video to area fail !! reset to full screen");
}
}
#endif
if((sf_layer->transform == HWC_TRANSFORM_ROT_90)
||(sf_layer->transform == HWC_TRANSFORM_ROT_270)){
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12 || format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
{
//rga need this alignment.
src_h = ALIGN_DOWN(src_h, 8);
src_w = ALIGN_DOWN(src_w, 2);
}
h_scale_mul = (float) (src_h)/(dst_w);
v_scale_mul = (float) (src_w)/(dst_h);
} else {
h_scale_mul = (float) (src_w)/(dst_w);
v_scale_mul = (float) (src_h)/(dst_h);
}
#if RK_VIDEO_SKIP_LINE
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12 || format == HAL_PIXEL_FORMAT_YCrCb_NV12_10){
if(width >= 3840){
if(h_scale_mul > 1.0 || v_scale_mul > 1.0){
SkipLine = 2;
}
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12_10 && h_scale_mul >= (3840 / 1600)){
SkipLine = 3;
}
}
int video_skipline = property_get_int32("vendor.video.skipline", 0);
if (video_skipline == 2){
SkipLine = 2;
}else if(video_skipline == 3){
SkipLine = 3;
}
}
#endif
is_scale = (h_scale_mul != 1.0) || (v_scale_mul != 1.0);
is_match = false;
is_take = false;
#if USE_AFBC_LAYER
is_afbc = false;
#endif
#if (RK_RGA_COMPSITE_SYNC | RK_RGA_PREPARE_ASYNC)
is_rotate_by_rga = false;
#endif
bMix = false;
bpp = android::bytesPerPixel(format);
size = (source_crop.right - source_crop.left) * (source_crop.bottom - source_crop.top) * bpp;
is_large = (mode.h_display()*mode.v_display()*4*3/4 > size)? true:false;
#if RK_PRINT_LAYER_NAME
char layername[100];
#ifdef USE_HWC2
if(sf_handle)
{
HWC_GET_HANDLE_LAYERNAME(gralloc,sf_layer,sf_handle, layername, 100);
}
#else
strcpy(layername, sf_layer->LayerName);
#endif
name = layername;
#endif
ALOGV("\t sourceCropf(%f,%f,%f,%f)",source_crop.left,source_crop.top,source_crop.right,source_crop.bottom);
ALOGV("h_scale_mul=%f,v_scale_mul=%f,is_scale=%d,is_large=%d",h_scale_mul,v_scale_mul,is_scale,is_large);
transform = 0;
// 270* and 180* cannot be combined with flips. More specifically, they
// already contain both horizontal and vertical flips, so those fields are
// redundant in this case. 90* rotation can be combined with either horizontal
// flip or vertical flip, so treat it differently
if (sf_layer->transform == HWC_TRANSFORM_ROT_270) {
transform = DrmHwcTransform::kRotate270;
} else if (sf_layer->transform == HWC_TRANSFORM_ROT_180) {
transform = DrmHwcTransform::kRotate180;
} else {
if (sf_layer->transform & HWC_TRANSFORM_FLIP_H)
transform |= DrmHwcTransform::kFlipH;
if (sf_layer->transform & HWC_TRANSFORM_FLIP_V)
transform |= DrmHwcTransform::kFlipV;
if (sf_layer->transform & HWC_TRANSFORM_ROT_90)
transform |= DrmHwcTransform::kRotate90;
if(!sf_layer->transform)
transform |= DrmHwcTransform::kRotate0;
}
#if RK_PRINT_LAYER_NAME
#if RK_RGA_TEST
if((format==HAL_PIXEL_FORMAT_RGB_565) && strstr(sf_layer->LayerName,"SurfaceView"))
transform |= DrmHwcTransform::kRotate90;
#endif
#endif
switch (sf_layer->blending) {
case HWC_BLENDING_NONE:
blending = DrmHwcBlending::kNone;
break;
case HWC_BLENDING_PREMULT:
blending = DrmHwcBlending::kPreMult;
break;
case HWC_BLENDING_COVERAGE:
blending = DrmHwcBlending::kCoverage;
break;
default:
ALOGE("Invalid blending in hwc_layer_1_t %d", sf_layer->blending);
return -EINVAL;
}
#if 0
ret = buffer.ImportBuffer(sf_layer->handle, importer
#if RK_VIDEO_SKIP_LINE
, SkipLine
#endif
);
if (ret)
return ret;
#endif
#if USE_AFBC_LAYER
// if(sf_handle)
if ( sf_handle && bFbTarget_ )
{
ALOGD_IF(log_level(DBG_VERBOSE),"we got buffer handle for fb_target_layer, to get internal_format.");
#if USE_GRALLOC_4
internal_format = gralloc4::get_internal_format(sf_handle);
#else // #if USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)sf_handle;
internal_format = drm_hnd->internal_format;
#else
ret = gralloc->perform(gralloc, GRALLOC_MODULE_PERFORM_GET_INTERNAL_FORMAT,
sf_handle, &internal_format);
if (ret) {
ALOGE("Failed to get internal_format for buffer %p (%d)", sf_handle, ret);
return ret;
}
#endif
#endif // #if USE_GRALLOC_4
#if USE_GRALLOC_4
if ( gralloc4::does_use_afbc_format(sf_handle) )
#else
if(isAfbcInternalFormat(internal_format))
#endif
{
ALOGD_IF(log_level(DBG_VERBOSE),"to set 'is_afbc'.");
is_afbc = true;
}
else
{
ALOGD_IF(log_level(DBG_VERBOSE),"not a afbc_buffer.");
}
}
if(bFbTarget_ && !sf_handle)
{
ALOGD_IF(log_level(DBG_VERBOSE),"we could not got buffer handle, and current buffer is for fb_target_layer, to check AFBC in a trick way.");
static int iFbdcSupport = -1;
ALOGD_IF(log_level(DBG_VERBOSE),"iFbdcSupport = %d",iFbdcSupport);
// if(iFbdcSupport == -1)
if(iFbdcSupport <= 0)
{
char fbdc_value[PROPERTY_VALUE_MAX];
int ret = property_get( PROPERTY_TYPE ".gmali.fbdc_target", fbdc_value, "0");
ALOGV("ret = %d",ret);
iFbdcSupport = atoi(fbdc_value);
if(iFbdcSupport > 0 && display == 0)
{
ALOGD_IF(log_level(DBG_VERBOSE),"to set 'is_afbc'.");
is_afbc = true;
}
}
else if(iFbdcSupport > 0 && display == 0)
{
ALOGD_IF(log_level(DBG_VERBOSE),"to set 'is_afbc'.");
is_afbc = true;
}
}
#endif
return 0;
}
int DrmHwcLayer::ImportBuffer(struct hwc_context_t *ctx, hwc_layer_1_t *sf_layer, Importer *importer)
{
#if TARGET_BOARD_PLATFORM_RK3326
/*
* RK3326 VOP not support alpha scale, need to convert layer format
* DRM_FORMAT_ARGB8888 -> DRM_FORMAT_XRGB8888
* DRM_FORMAT_ABGR8888 -> DRM_FORMAT_XBGR8888
*/
if(is_scale)
importer->SetFlag(DrmGenericImporterFlag::VOP_NOT_SUPPORT_ALPHA_SCALE);
else
importer->SetFlag(DrmGenericImporterFlag::NO_FLAG);
#endif
int ret = buffer.ImportBuffer(sf_layer->handle, importer
#if RK_VIDEO_SKIP_LINE
, SkipLine
#endif
);
ret = handle.CopyBufferHandle(sf_layer->handle, ctx->gralloc);
if (ret)
return ret;
gralloc_buffer_usage = hwc_get_handle_usage(ctx->gralloc,sf_layer->handle);
return ret;
}
static void hwc_dump(struct hwc_composer_device_1 *dev, char *buff,
int buff_len) {
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
std::ostringstream out;
ctx->drm.compositor()->Dump(&out);
std::string out_str = out.str();
strncpy(buff, out_str.c_str(),
std::min((size_t)buff_len, out_str.length() + 1));
buff[buff_len - 1] = '\0';
}
static bool hwc_skip_layer(const std::pair<int, int> &indices, int i) {
return indices.first >= 0 && i >= indices.first && i <= indices.second;
}
static bool is_use_gles_comp(struct hwc_context_t *ctx, DrmConnector *connector, hwc_display_contents_1_t *display_content, int display_id)
{
int num_layers = display_content->numHwLayers;
hwc_drm_display_t *hd = &ctx->displays[display_id];
DrmCrtc *crtc = NULL;
if (!connector) {
ALOGE("%s: Failed to get connector for display %d line=%d", __FUNCTION__,display_id, __LINE__);
}
else
{
crtc = ctx->drm.GetCrtcFromConnector(connector);
if (connector->state() != DRM_MODE_CONNECTED || !crtc) {
ALOGE("Failed to get crtc for display %d line=%d", display_id, __LINE__);
}
}
//force go into GPU
/*
<=0: DISPLAY_PRIMARY & DISPLAY_EXTERNAL both go into GPU.
=1: DISPLAY_PRIMARY go into overlay,DISPLAY_EXTERNAL go into GPU.
=2: DISPLAY_EXTERNAL go into overlay,DISPLAY_PRIMARY go into GPU.
others: DISPLAY_PRIMARY & DISPLAY_EXTERNAL both go into overlay.
*/
int iMode = hwc_get_int_property( PROPERTY_TYPE ".hwc.compose_policy","0");
if( iMode <= 0 || (iMode == 1 && display_id == 2) || (iMode == 2 && display_id == 1) )
{
ALOGD_IF(log_level(DBG_DEBUG), PROPERTY_TYPE ".hwc.compose_policy=%d,go to GPU GLES at line=%d", iMode, __LINE__);
return true;
}
iMode = hwc_get_int_property( PROPERTY_TYPE ".hwc","1");
if( iMode <= 0 )
{
ALOGD_IF(log_level(DBG_DEBUG), PROPERTY_TYPE ".hwc=%d,go to GPU GLES at line=%d", iMode, __LINE__);
return true;
}
#if RK_CTS_WORKROUND
int is_auto_fill = 0;
bool isFind = FindAppHintInFile(ctx->regFile, AUTO_FILL_PROG_NAME, IS_AUTO_FILL, &is_auto_fill, IMG_INT_TYPE);
if(is_auto_fill)
{
if(!hd->bPerfMode)
{
ALOGD_IF(log_level(DBG_DEBUG),"enter perf mode");
ctl_gpu_performance(1);
ctl_cpu_performance(1, 0);
hd->bPerfMode = true;
}
ALOGD_IF(log_level(DBG_DEBUG),"is auto fill program,go to GPU GLES at line=%d", __LINE__);
return true;
}
else
{
if(hd->bPerfMode)
{
ALOGD_IF(log_level(DBG_DEBUG),"exit perf mode");
ctl_gpu_performance(0);
ctl_cpu_performance(0, 0);
hd->bPerfMode = false;
}
}
#endif
if(num_layers == 1)
{
ALOGD_IF(log_level(DBG_DEBUG),"No layer,go to GPU GLES at line=%d", __LINE__);
return true;
}
if(g_boot_gles_cnt < BOOT_GLES_COUNT)
{
ALOGD_IF(log_level(DBG_DEBUG),"g_boot_gles_cnt=%d,go to GPU GLES at line=%d", g_boot_gles_cnt, __LINE__);
g_boot_gles_cnt++;
return true;
}
if(g_bSkipExtern && (g_extern_gles_cnt < BOOT_GLES_COUNT))
{
ALOGD_IF(log_level(DBG_DEBUG),"g_extern_gles_cnt=%d,go to GPU GLES at line=%d", g_extern_gles_cnt, __LINE__);
g_extern_gles_cnt++;
return true;
}
#if RK_INVALID_REFRESH
if(ctx->mOneWinOpt)
{
ALOGD_IF(log_level(DBG_DEBUG),"Enter static screen opt,go to GPU GLES at line=%d", __LINE__);
return true;
}
#endif
#if RK_STEREO
if(ctx->is_3d)
{
ALOGD_IF(log_level(DBG_DEBUG),"Is 3d mode,go to GPU GLES at line=%d", __LINE__);
return true;
}
#endif
//If the transform nv12 layers is bigger than one,then go into GPU GLES.
//If the transform normal layers is bigger than zero,then go into GPU GLES.
hd->transform_nv12 = 0;
hd->transform_normal = 0;
int ret = 0;
int format = 0;
#if USE_AFBC_LAYER
uint64_t internal_format = 0;
int iFbdcCnt = 0;
#endif
int video_4k_cnt = 0;
int large_UI_cnt = 0;
for (int j = 0; j < num_layers-1; j++) {
hwc_layer_1_t *layer = &display_content->hwLayers[j];
if(layer->handle)
{
#if (!RK_PER_MODE && RK_DRM_GRALLOC)
format = hwc_get_handle_attibute(ctx->gralloc,layer->handle,ATT_FORMAT);
#else
format = hwc_get_handle_format(ctx->gralloc,layer->handle);
#endif
}
int src_l=0,src_t=0,src_r=0,src_b=0,src_w=0,src_h=0;
int dst_l=0,dst_t=0,dst_r=0,dst_b=0,dst_w=0,dst_h=0;
hwc_rect_t rect_merge;
int left_min = 0, top_min = 0, right_max = 0, bottom_max=0;
float rga_h_scale=1.0, rga_v_scale=1.0;
src_l = (int)layer->sourceCropf.left;
src_t = (int)layer->sourceCropf.top;
src_r = (int)layer->sourceCropf.right;
src_b = (int)layer->sourceCropf.bottom;
src_w = (int)(layer->sourceCropf.right - layer->sourceCropf.left);
src_h = (int)(layer->sourceCropf.bottom - layer->sourceCropf.top);
dst_w = (int)(layer->displayFrame.right - layer->displayFrame.left);
dst_h = (int)(layer->displayFrame.bottom - layer->displayFrame.top);
src_l = ALIGN_DOWN(src_l, 2);
dst_l = 0;
dst_t = 0;
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12 || format == HAL_PIXEL_FORMAT_YCrCb_NV12_10){
if(src_w >= 3840 && src_h >= 2160 && (src_w != dst_w ||src_h != dst_h))
video_4k_cnt++;
}else if(src_w * src_h >= 1920 * 1080){
large_UI_cnt++;
}
if(hd->isVideo && (layer->transform != 0))
{
#if !RK_RGA_SCALE_AND_ROTATE
if((layer->transform == HWC_TRANSFORM_ROT_90) || (layer->transform == HWC_TRANSFORM_ROT_270))
{
dst_r = (int)(src_b - src_t);
dst_b = (int)(src_r - src_l);
src_h = ALIGN_DOWN(src_h, 8);
src_w = ALIGN_DOWN(src_w, 2);
}
else
{
dst_r = (int)(src_r - src_l);
dst_b = (int)(src_b - src_t);
src_w = ALIGN_DOWN(src_w, 8);
src_h = ALIGN_DOWN(src_h, 2);
}
dst_w = dst_r - dst_l;
dst_h = dst_b - dst_t;
int dst_raw_w = dst_w;
int dst_raw_h = dst_h;
dst_w = ALIGN_DOWN(dst_w, 8);
dst_h = ALIGN_DOWN(dst_h, 2);
#else
UN_USED(dst_r);
UN_USED(dst_b);
rect_merge.left = layer->displayFrame.left;
rect_merge.top = layer->displayFrame.top;
rect_merge.right = layer->displayFrame.right;
rect_merge.bottom = layer->displayFrame.bottom;
#if 0
int left_min = 0, top_min = 0, right_max = 0, bottom_max=0;
hwc_region_t * visible_region = &layer->visibleRegionScreen;
hwc_rect_t const * visible_rects = visible_region->rects;
if(visible_rects){
left_min = visible_rects[0].left;
top_min = visible_rects[0].top;
right_max = visible_rects[0].right;
bottom_max = visible_rects[0].bottom;
for (int r = 0; r < (int) visible_region->numRects; r++) {
int r_left;
int r_top;
int r_right;
int r_bottom;
r_left = hwcMAX(layer->displayFrame.left, visible_rects[r].left);
left_min = hwcMIN(r_left, left_min);
r_top = hwcMAX(layer->displayFrame.top, visible_rects[r].top);
top_min = hwcMIN(r_top, top_min);
r_right = hwcMIN(layer->displayFrame.right, visible_rects[r].right);
right_max = hwcMAX(r_right, right_max);
r_bottom = hwcMIN(layer->displayFrame.bottom, visible_rects[r].bottom);
bottom_max = hwcMAX(r_bottom, bottom_max);
}
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12_VIDEO
|| format == HAL_PIXEL_FORMAT_YCrCb_NV12){
rect_merge.left = layer->displayFrame.left;
rect_merge.top = layer->displayFrame.top;
rect_merge.right = layer->displayFrame.right;
rect_merge.bottom = layer->displayFrame.bottom;
}
else
{
rect_merge.left = hwcMAX(layer->displayFrame.left, left_min);
rect_merge.top = hwcMAX(layer->displayFrame.top, top_min);
rect_merge.right = hwcMIN(layer->displayFrame.right, right_max);
rect_merge.bottom = hwcMIN(layer->displayFrame.bottom, bottom_max);
}
}
#endif
src_w = ALIGN_DOWN(src_w, 2);
src_h = ALIGN_DOWN(src_h, 2);
dst_w = rect_merge.right - rect_merge.left;
dst_h = rect_merge.bottom - rect_merge.top;
dst_w = ALIGN(dst_w, 8);
dst_h = ALIGN(dst_h, 2);
#endif
if(src_w <= 0 || src_h <= 0)
{
ALOGD_IF(log_level(DBG_DEBUG),"layer src sourceCropf(%f,%f,%f,%f) is invalid,go to GPU GLES at line=%d",
layer->sourceCropf.left,layer->sourceCropf.top,layer->sourceCropf.right,layer->sourceCropf.bottom, __LINE__);
return true;
}
if((layer->transform == HWC_TRANSFORM_ROT_90) || (layer->transform == HWC_TRANSFORM_ROT_270))
{
rga_h_scale = (float)dst_h / src_w;
rga_v_scale = (float)dst_w / src_h;
}
else
{
rga_h_scale = (float)dst_w / src_w;
rga_v_scale = (float)dst_h / src_h;
}
#if (RGA_VER == 0 || RGA_VER == 1)
/* Arbitrary non-integer scaling ratio, from 1/2 to 8
RGA1:
RK3066
RK3188
Beetles
Beetlesplus
RGA1_plus:
Audi -> 3128
Granite -> soifa 3gr
*/
if(rga_h_scale < 0.5 || rga_v_scale < 0.5 ||
rga_h_scale > 8.0 || rga_v_scale > 8.0)
{
ALOGD_IF(log_level(DBG_DEBUG),"rga scale(%f,%f) out of range,go to GPU GLES at line=%d",
rga_h_scale,rga_v_scale,__LINE__);
return true;
}
if(src_w >= 1920 || src_h >= 1080)
{
ALOGD_IF(log_level(DBG_DEBUG),"rga1/rga1_plus take more than 20ms when roate 1080p or bigger video(%d,%d),go to GPU GLES at line=%d",
src_w,src_h,__LINE__);
return true;
}
#elif (RGA_VER == 2)
/* Arbitrary non-integer scaling ratio, from 1/8 to 8
RGA2-Lite:
Maybach -> 3368
BMW -> 3366
Benz -> 3228
infiniti ->3228H
rk3328
rk3326
*/
if(rga_h_scale < 0.125 || rga_v_scale < 0.125 ||
rga_h_scale > 8.0 || rga_v_scale > 8.0)
{
ALOGD_IF(log_level(DBG_DEBUG),"rga scale(%f,%f) out of range,go to GPU GLES at line=%d",
rga_h_scale,rga_v_scale,__LINE__);
return true;
}
#else
/* Arbitrary non-integer scaling ratio, from 1/16 to 16
RGA2:
Lincoln -> 3288/3288w
Capricorn -> 3190
RGA2-Enhance
mclaren -> 3399
mercury -> 1108
*/
if(rga_h_scale < 0.0625 || rga_v_scale < 0.0625 ||
rga_h_scale > 16.0 || rga_v_scale > 16.0)
{
ALOGD_IF(log_level(DBG_DEBUG),"rga scale(%f,%f) out of range,go to GPU GLES at line=%d",
rga_h_scale,rga_v_scale,__LINE__);
return true;
}
#endif
if(src_w > src_h && src_h >= 2160)
{
ALOGD_IF(log_level(DBG_DEBUG),"RGA take more than 30ms when roate 4K or bigger video(%d,%d),go to GPU GLES at line=%d",
src_w,src_h,__LINE__);
return true;
}
}
#if 0
if (layer->flags & HWC_SKIP_LAYER)
{
ALOGD_IF(log_level(DBG_DEBUG),"layer is skipped,go to GPU GLES at line=%d", __LINE__);
return true;
}
#endif
if(
#if (RK_RGA_COMPSITE_SYNC | RK_RGA_PREPARE_ASYNC)
!ctx->drm.isSupportRkRga() && layer->transform
#else
layer->transform
#endif
)
{
ALOGD_IF(log_level(DBG_DEBUG),"layer's transform=0x%x,go to GPU GLES at line=%d", layer->transform, __LINE__);
return true;
}
if(layer->transform != HWC_TRANSFORM_ROT_270 && layer->transform & HWC_TRANSFORM_ROT_90)
{
if((layer->transform & HWC_TRANSFORM_FLIP_H) || (layer->transform & HWC_TRANSFORM_FLIP_V) )
{
ALOGD_IF(log_level(DBG_DEBUG),"layer's transform=0x%x,go to GPU GLES at line=%d", layer->transform, __LINE__);
return true;
}
}
#if 0
if( (layer->blending == HWC_BLENDING_PREMULT)&& layer->planeAlpha!=0xFF )
{
ALOGD_IF(log_level(DBG_DEBUG),"layer's blending planeAlpha=0x%x,go to GPU GLES at line=%d", layer->planeAlpha, __LINE__);
return true;
}
#endif
if(layer->handle)
{
char layername[100];
#if RK_PRINT_LAYER_NAME
#ifdef USE_HWC2
HWC_GET_HANDLE_LAYERNAME(ctx->gralloc,layer,layer->handle, layername, 100);
#else
strcpy(layername, layer->LayerName);
#endif
#endif
//DumpLayer(layername,layer->handle);
if(!vop_support_format(format))
{
ALOGD_IF(log_level(DBG_DEBUG),"layer's format=0x%x is not support,go to GPU GLES at line=%d", format, __LINE__);
return true;
}
#if 1 // vendor.hwc.hdr_video_compose_by_gles property to enable/disable hdr_video_compose_by_gles
#if (defined TARGET_BOARD_PLATFORM_RK3399) || (defined TARGET_BOARD_PLATFORM_RK3288)
if(hd->isHdr && ctx->hdr_video_compose_by_gles)
{
if(connector && !connector->is_hdmi_support_hdr()
&& crtc && !ctx->drm.is_plane_support_hdr2sdr(crtc))
{
ALOGD_IF(log_level(DBG_DEBUG), "layer is hdr video,go to GPU GLES at line=%d", __LINE__);
return true;
}
}
#endif
#endif
#if 1
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12 || format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
{
int src_xoffset = layer->sourceCropf.left * getPixelWidthByAndroidFormat(format);
if(!IS_ALIGN(src_xoffset,16))
{
ALOGD_IF(log_level(DBG_DEBUG),"layer's x offset = %d,vop nedd address should 16 bytes alignment,go to GPU GLES at line=%d", src_xoffset,__LINE__);
return true;
}
}
#endif
#if 1
if(!vop_support_scale(layer,hd))
{
ALOGD_IF(log_level(DBG_DEBUG),"layer's scale is not support,go to GPU GLES at line=%d", __LINE__);
return true;
}
#endif
if(layer->transform)
{
#ifdef TARGET_BOARD_PLATFORM_RK3288
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
{
ALOGD_IF(log_level(DBG_DEBUG),"rk3288'rga cann't support nv12_10,go to GPU GLES at line=%d", __LINE__);
return true;
}
#endif
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12 || format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
hd->transform_nv12++;
else if(layer->compositionType != HWC_NODRAW)
hd->transform_normal++;
}
#if USE_AFBC_LAYER
#if USE_GRALLOC_4
internal_format = gralloc4::get_internal_format(layer->handle);
#else // #if USE_GRALLOC_4
#if RK_PER_MODE
struct gralloc_drm_handle_t* drm_hnd = (struct gralloc_drm_handle_t *)layer->handle;
internal_format = drm_hnd->internal_format;
UN_USED(ret);
#else
ret = ctx->gralloc->perform(ctx->gralloc, GRALLOC_MODULE_PERFORM_GET_INTERNAL_FORMAT,
layer->handle, &internal_format);
if (ret) {
ALOGE("Failed to get internal_format for buffer %p (%d)", layer->handle, ret);
return false;
}
#endif
#endif // #if USE_GRALLOC_4
#if USE_GRALLOC_4
if ( gralloc4::does_use_afbc_format(layer->handle) )
#else
if(isAfbcInternalFormat(internal_format))
#endif
iFbdcCnt++;
#else
UN_USED(ret);
#endif
}
}
if(hd->transform_nv12 > 1 || hd->transform_normal > 0)
{
ALOGD_IF(log_level(DBG_DEBUG), "too many rotate layers,go to GPU GLES at line=%d", __LINE__);
return true;
}
if(video_4k_cnt >= 1 && large_UI_cnt >= 2)
{
ALOGD_IF(log_level(DBG_DEBUG), "4k video(%d) and too much large UI(%d),go to GPU GLES at line=%d",video_4k_cnt,
large_UI_cnt, __LINE__);
return true;
}
#if USE_AFBC_LAYER
if(iFbdcCnt > 1)
{
ALOGD_IF(log_level(DBG_DEBUG),"iFbdcCnt=%d,go to GPU GLES line=%d",iFbdcCnt, __LINE__);
return true;
}
#endif
return false;
}
static HDMI_STAT DetectStatus(const char* property)
{
char status[PROPERTY_VALUE_MAX];
property_get(property, status, "on");
ALOGD_IF(log_level(DBG_VERBOSE),"get %s is %s", property, status);
if(!strcmp(status, "off"))
return HDMI_OFF;
else
return HDMI_ON;
}
/*
* Use property on/off to enable/disable display devices
* sys.hdmi_status.aux -> HDMI
* sys.dp_status.aux -> DP
*/
static void DetectAuxStatus(const hwc_context_t *ctx)
{
static HDMI_STAT last_hdmi_status = HDMI_ON;
static HDMI_STAT last_dp_status = HDMI_ON;
char acStatus[10];
int ret = 0;
HDMI_STAT hdmi_status = DetectStatus( PROPERTY_TYPE ".hdmi_status.aux");
if(ctx->hdmi_status_fd > 0 && hdmi_status != last_hdmi_status)
{
if(hdmi_status == HDMI_ON)
strcpy(acStatus,"detect");
else
strcpy(acStatus,"off");
ret = write(ctx->hdmi_status_fd,acStatus,strlen(acStatus)+1);
if(ret < 0)
{
ALOGE("set hdmi status to %s falied, ret = %d", acStatus, ret);
}
last_hdmi_status = hdmi_status;
ALOGD_IF(log_level(DBG_VERBOSE),"set hdmi status to %s",acStatus);
}
HDMI_STAT dp_status = DetectStatus( PROPERTY_TYPE ".dp_status.aux");
if(ctx->dp_status_fd > 0 && dp_status != last_dp_status)
{
if(dp_status == HDMI_ON)
strcpy(acStatus,"detect");
else
strcpy(acStatus,"off");
ret = write(ctx->dp_status_fd,acStatus,strlen(acStatus)+1);
if(ret < 0)
{
ALOGE("set dp status to %s falied, ret = %d", acStatus, ret);
}
ALOGD_IF(log_level(DBG_VERBOSE),"set dp status to %s",acStatus);
last_dp_status = dp_status;
}
return ;
}
static bool parse_hdmi_output_format_prop(char* strprop, drm_hdmi_output_type *format, dw_hdmi_rockchip_color_depth *depth) {
if (!strcmp(strprop, "Auto")) {
*format = DRM_HDMI_OUTPUT_YCBCR_HQ;
*depth = ROCKCHIP_DEPTH_DEFAULT;
return true;
}
if (!strcmp(strprop, "RGB-8bit")) {
*format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
*depth = ROCKCHIP_HDMI_DEPTH_8;
return true;
}
if (!strcmp(strprop, "RGB-10bit")) {
*format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
*depth = ROCKCHIP_HDMI_DEPTH_10;
return true;
}
if (!strcmp(strprop, "YCBCR444-8bit")) {
*format = DRM_HDMI_OUTPUT_YCBCR444;
*depth = ROCKCHIP_HDMI_DEPTH_8;
return true;
}
if (!strcmp(strprop, "YCBCR444-10bit")) {
*format = DRM_HDMI_OUTPUT_YCBCR444;
*depth = ROCKCHIP_HDMI_DEPTH_10;
return true;
}
if (!strcmp(strprop, "YCBCR422-8bit")) {
*format = DRM_HDMI_OUTPUT_YCBCR422;
*depth = ROCKCHIP_HDMI_DEPTH_8;
return true;
}
if (!strcmp(strprop, "YCBCR422-10bit")) {
*format = DRM_HDMI_OUTPUT_YCBCR422;
*depth = ROCKCHIP_HDMI_DEPTH_10;
return true;
}
if (!strcmp(strprop, "YCBCR420-8bit")) {
*format = DRM_HDMI_OUTPUT_YCBCR420;
*depth = ROCKCHIP_HDMI_DEPTH_8;
return true;
}
if (!strcmp(strprop, "YCBCR420-10bit")) {
*format = DRM_HDMI_OUTPUT_YCBCR420;
*depth = ROCKCHIP_HDMI_DEPTH_10;
return true;
}
ALOGE("hdmi output format is invalid. [%s]", strprop);
return false;
}
static bool update_hdmi_output_format(struct hwc_context_t *ctx, DrmConnector *connector, int display,
hwc_drm_display_t *hd) {
int timeline = 0;
drm_hdmi_output_type color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
dw_hdmi_rockchip_color_depth color_depth = ROCKCHIP_HDMI_DEPTH_8;
int ret = 0;
int need_change_format = 0;
int need_change_depth = 0;
char prop_format[PROPERTY_VALUE_MAX];
static uint32_t last_mainType,last_auxType;
timeline = property_get_int32( PROPERTY_TYPE ".display.timeline", -1);
drmModeAtomicReqPtr pset = NULL;
/*
* force update propetry when timeline is zero or not exist.
*/
if (timeline && timeline == hd->display_timeline &&
hd->hotplug_timeline == hd->ctx->drm.timeline())
return 0;
//hd->display_timeline = timeline;//let update_display_bestmode function update the value.
//hd->hotplug_timeline = hd->ctx->drm.timeline();//let update_display_bestmode function update the value.
memset(prop_format, 0, sizeof(prop_format));
if (display == HWC_DISPLAY_PRIMARY){
if(hwc_have_baseparameter()){
if(connector->get_type() != last_mainType){
property_set("persist." PROPERTY_TYPE ".color.main","use_baseparameter");
ALOGD("BP:DisplayDevice change type[%d] => type[%d],to update main color",last_mainType,connector->get_type());
last_mainType = connector->get_type();
}
property_get("persist." PROPERTY_TYPE ".color.main", prop_format, "use_baseparameter");
if(!strcmp(prop_format,"use_baseparameter")){
hwc_get_baseparameter_config(prop_format,display,BP_COLOR,connector->get_type());
ret = sscanf(prop_format,"%d-%d",&color_format,&color_depth);
if(ret != 2){
ALOGE("BP: get color fail! to use default ");
color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
color_depth = ROCKCHIP_DEPTH_DEFAULT;
}
}else{
/* Can get the persist." PROPERTY_TYPE ".color.main, to use it. */
ret = parse_hdmi_output_format_prop(prop_format, &color_format, &color_depth);
if (ret == false) {
ALOGE("Get color fail! to use default ");
color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
color_depth = ROCKCHIP_DEPTH_DEFAULT;
}
}
}else{
/* if resolution is null,set to "Auto" */
property_get("persist." PROPERTY_TYPE ".color.main", prop_format, "Auto");
ret = parse_hdmi_output_format_prop(prop_format, &color_format, &color_depth);
if (ret == false) {
ALOGE("Get color fail! to use default ");
color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
color_depth = ROCKCHIP_DEPTH_DEFAULT;
}
}
}else if(display == HWC_DISPLAY_EXTERNAL){
if(hwc_have_baseparameter()){
if(connector->get_type() != last_auxType){
property_set("persist." PROPERTY_TYPE ".color.aux","use_baseparameter");
ALOGD("BP:DisplayDevice change type[%d] => type[%d],to update aux color",last_auxType,connector->get_type());
last_auxType = connector->get_type();
}
property_get("persist." PROPERTY_TYPE ".color.aux", prop_format, "use_baseparameter");
if(!strcmp(prop_format,"use_baseparameter")){
hwc_get_baseparameter_config(prop_format,display,BP_COLOR,connector->get_type());
ret = sscanf(prop_format,"%d-%d",&color_format,&color_depth);
if(ret != 2){
ALOGE("BP: get color fail! to use default ");
color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
color_depth = ROCKCHIP_DEPTH_DEFAULT;
}
}else{
/* Can get the persist." PROPERTY_TYPE ".color.aux, to use it. */
ret = parse_hdmi_output_format_prop(prop_format, &color_format, &color_depth);
if (ret == false) {
ALOGE("Get color fail! to use default ");
color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
color_depth = ROCKCHIP_DEPTH_DEFAULT;
}
}
}else{
/* if resolution is null,set to "Auto" */
property_get("persist." PROPERTY_TYPE ".color.aux", prop_format, "Auto");
ret = parse_hdmi_output_format_prop(prop_format, &color_format, &color_depth);
if (ret == false) {
ALOGE("Get color fail! to use default ");
color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
color_depth = ROCKCHIP_DEPTH_DEFAULT;
}
}
}
if(hd->color_format != color_format) {
need_change_format = 1;
}
if(hd->color_depth != color_depth) {
need_change_depth = 1;
}
if(connector->hdmi_output_format_property().id() > 0 && need_change_format > 0) {
pset = drmModeAtomicAlloc();
if (!pset) {
ALOGE("%s:line=%d Failed to allocate property set", __FUNCTION__, __LINE__);
return false;
}
ALOGD_IF(log_level(DBG_VERBOSE),"%s: change hdmi output format: %d", __FUNCTION__, color_format);
ret = drmModeAtomicAddProperty(pset, connector->id(), connector->hdmi_output_format_property().id(), color_format);
if (ret < 0) {
ALOGE("%s:line=%d Failed to add prop[%d] to [%d]", __FUNCTION__, __LINE__, connector->hdmi_output_format_property().id(), connector->id());
}
if (ret < 0) {
ALOGE("%s:line=%d Failed to commit pset ret=%d\n", __FUNCTION__, __LINE__, ret);
drmModeAtomicFree(pset);
return false;
}
else
{
hd->color_format = color_format;
}
}
if(connector->hdmi_output_depth_property().id() > 0 && need_change_depth > 0) {
if (!pset) {
pset = drmModeAtomicAlloc();
}
if (!pset) {
ALOGE("%s:line=%d Failed to allocate property set", __FUNCTION__, __LINE__);
return false;
}
ALOGD_IF(log_level(DBG_VERBOSE),"%s: change hdmi output depth: %d", __FUNCTION__, color_depth);
ret = drmModeAtomicAddProperty(pset, connector->id(), connector->hdmi_output_depth_property().id(), color_depth);
if (ret < 0) {
ALOGE("%s:line=%d Failed to add prop[%d] to [%d]", __FUNCTION__, __LINE__, connector->hdmi_output_depth_property().id(), connector->id());
}
if (ret < 0) {
ALOGE("%s:line=%d Failed to commit pset ret=%d\n", __FUNCTION__, __LINE__, ret);
drmModeAtomicFree(pset);
return false;
}
else
{
hd->color_depth = color_depth;
}
}
if (pset != NULL) {
drmModeAtomicCommit(ctx->drm.fd(), pset, DRM_MODE_ATOMIC_ALLOW_MODESET, &ctx->drm);
drmModeAtomicFree(pset);
pset = NULL;
}
return true;
}
/**
* @brief set hdr_metadata and colorimetry.
*
* @param hdr_metadata [IN] hdr metadata
* @param android_colorspace [IN] colorspace
* @return
* true: set successfully.
* false: set fail.
*/
static bool set_hdmi_hdr_meta(struct hwc_context_t *ctx, DrmConnector *connector,
hdr_metadata_s* hdr_metadata, hwc_drm_display_t *hd,
uint32_t android_colorspace)
{
uint32_t blob_id = 0;
int ret = -1;
int colorimetry = 0;
if(!ctx || !connector || !hdr_metadata)
{
ALOGE("%s:line=%d parameter is null", __FUNCTION__, __LINE__);
return false;
}
if(connector->hdr_metadata_property().id())
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s: android_colorspace = 0x%x", __FUNCTION__, android_colorspace);
drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
if (!pset) {
ALOGE("%s:line=%d Failed to allocate property set", __FUNCTION__, __LINE__);
return false;
}
if(!memcmp(&hd->last_hdr_metadata, hdr_metadata, sizeof(hdr_metadata_s)))
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s: no need to update metadata", __FUNCTION__);
}
else
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s: hdr_metadata eotf=0x%x, hd->last_hdr_metadata=0x%x", __FUNCTION__,
HDR_METADATA_EOTF_P(hdr_metadata), HDR_METADATA_EOTF_T(hd->last_hdr_metadata));
ctx->drm.CreatePropertyBlob(hdr_metadata, sizeof(hdr_metadata_s), &blob_id);
ret = drmModeAtomicAddProperty(pset, connector->id(), connector->hdr_metadata_property().id(), blob_id);
if (ret < 0) {
ALOGE("%s:line=%d Failed to add prop[%d] to [%d]", __FUNCTION__, __LINE__, connector->hdr_metadata_property().id(), connector->id());
}
}
if(connector->hdmi_output_colorimetry_property().id())
{
if((android_colorspace & HAL_DATASPACE_STANDARD_BT2020) == HAL_DATASPACE_STANDARD_BT2020)
{
colorimetry = COLOR_METRY_ITU_2020;
}
if(hd->colorimetry != colorimetry)
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s: change bt2020 %d", __FUNCTION__, colorimetry);
ret = drmModeAtomicAddProperty(pset, connector->id(), connector->hdmi_output_colorimetry_property().id(), colorimetry);
if (ret < 0) {
ALOGE("%s:line=%d Failed to add prop[%d] to [%d]", __FUNCTION__, __LINE__, connector->hdmi_output_colorimetry_property().id(), connector->id());
}
}
}
drmModeAtomicCommit(ctx->drm.fd(), pset, DRM_MODE_ATOMIC_ALLOW_MODESET, &ctx->drm);
if (ret < 0) {
ALOGE("%s:line=%d Failed to commit pset ret=%d\n", __FUNCTION__, __LINE__, ret);
drmModeAtomicFree(pset);
return false;
}
else
{
memcpy(&hd->last_hdr_metadata, hdr_metadata, sizeof(hdr_metadata_s));
hd->colorimetry = colorimetry;
}
if (blob_id)
ctx->drm.DestroyPropertyBlob(blob_id);
drmModeAtomicFree(pset);
return true;
}
else
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s: hdmi don't support hdr metadata", __FUNCTION__);
return false;
}
}
#if RK_RGA_PREPARE_ASYNC
static int PrepareRgaBuffer(DrmRgaBuffer &rgaBuffer, DrmHwcLayer &layer) {
int rga_transform = 0;
int src_l=0,src_t=0,src_w=0,src_h=0;
int dst_l=0,dst_t=0,dst_r=0,dst_b=0;
int ret;
int dst_w,dst_h,dst_stride;
rga_info_t src, dst;
int alloc_format = 0;
memset(&src, 0, sizeof(rga_info_t));
memset(&dst, 0, sizeof(rga_info_t));
src.fd = -1;
dst.fd = -1;
#if 0
ret = rgaBuffer.WaitReleased(-1);
if (ret) {
ALOGE("Failed to wait for rga buffer release %d", ret);
return ret;
}
rgaBuffer.set_release_fence_fd(-1);
#endif
src_l = (int)layer.source_crop.left;
src_t = (int)layer.source_crop.top;
src_w = (int)(layer.source_crop.right - layer.source_crop.left);
src_h = (int)(layer.source_crop.bottom - layer.source_crop.top);
src_l = ALIGN_DOWN(src_l, 2);
src_t = ALIGN_DOWN(src_t, 2);
dst_l = 0;
dst_t = 0;
#if !RK_RGA_SCALE_AND_ROTATE
if(layer.transform & DrmHwcTransform::kRotate90 || layer.transform & DrmHwcTransform::kRotate270)
{
dst_r = (int)(layer.source_crop.bottom - layer.source_crop.top);
dst_b = (int)(layer.source_crop.right - layer.source_crop.left);
src_h = ALIGN_DOWN(src_h, 8);
src_w = ALIGN_DOWN(src_w, 2);
}
else
{
dst_r = (int)(layer.source_crop.right - layer.source_crop.left);
dst_b = (int)(layer.source_crop.bottom - layer.source_crop.top);
src_w = ALIGN_DOWN(src_w, 8);
src_h = ALIGN_DOWN(src_h, 2);
}
dst_w = dst_r - dst_l;
dst_h = dst_b - dst_t;
int dst_raw_w = dst_w;
int dst_raw_h = dst_h;
dst_w = ALIGN_DOWN(dst_w, 8);
dst_h = ALIGN_DOWN(dst_h, 2);
#else
UN_USED(dst_r);
UN_USED(dst_b);
src_w = ALIGN_DOWN(src_w, 2);
src_h = ALIGN_DOWN(src_h, 2);
dst_w = layer.rect_merge.right - layer.rect_merge.left;
dst_h = layer.rect_merge.bottom - layer.rect_merge.top;
dst_w = ALIGN(dst_w, 8);
dst_h = ALIGN(dst_h, 2);
#endif
if(dst_w < 0 || dst_h <0 )
ALOGE("RGA invalid dst_w=%d,dst_h=%d",dst_w,dst_h);
//If the layer's format is NV12_10,then use RGA to switch it to NV12.
if(layer.format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
alloc_format = HAL_PIXEL_FORMAT_YCrCb_NV12;
else
alloc_format = layer.format;
if (!rgaBuffer.Allocate(dst_w, dst_h, alloc_format)) {
ALOGE("Failed to allocate rga buffer with size %dx%d", dst_w, dst_h);
return -ENOMEM;
}
dst_stride = rgaBuffer.buffer()->getStride();
//DumpLayer("rga", layer.sf_handle);
if(layer.transform & DrmHwcTransform::kRotate90) {
rga_transform = DRM_RGA_TRANSFORM_ROT_90;
}
else if(layer.transform & DrmHwcTransform::kRotate270) {
rga_transform = DRM_RGA_TRANSFORM_ROT_270;
}
else if(layer.transform & DrmHwcTransform::kRotate180) {
rga_transform = DRM_RGA_TRANSFORM_ROT_180;
}
else if(layer.transform & DrmHwcTransform::kRotate0) {
rga_transform = DRM_RGA_TRANSFORM_ROT_0;
}
else if(layer.transform & DrmHwcTransform::kFlipH) {
rga_transform = DRM_RGA_TRANSFORM_FLIP_H;
}
else if(layer.transform & DrmHwcTransform::kFlipV) {
rga_transform = DRM_RGA_TRANSFORM_FLIP_V;
}
else {
ALOGE("%s: line=%d, wrong transform=0x%x", __FUNCTION__, __LINE__, layer.transform);
ret = -1;
return ret;
}
if(rga_transform != DRM_RGA_TRANSFORM_FLIP_H && layer.transform & DrmHwcTransform::kFlipH)
rga_transform |= DRM_RGA_TRANSFORM_FLIP_H;
if (rga_transform != DRM_RGA_TRANSFORM_FLIP_V && layer.transform & DrmHwcTransform::kFlipV)
rga_transform |= DRM_RGA_TRANSFORM_FLIP_V;
//rga async mode,flush in Composite thread.
src.sync_mode = RGA_BLIT_ASYNC;
rga_set_rect(&src.rect,
src_l, src_t, src_w, src_h,
layer.stride, layer.height, layer.format);
rga_set_rect(&dst.rect, dst_l, dst_t, dst_w, dst_h, dst_stride, dst_h, alloc_format);
ALOGD_IF(log_level(DBG_DEBUG),"RK_RGA_PREPARE_ASYNC rgaRotateScale : src[x=%d,y=%d,w=%d,h=%d,ws=%d,hs=%d,format=0x%x],dst[x=%d,y=%d,w=%d,h=%d,ws=%d,hs=%d,format=0x%x]",
src.rect.xoffset, src.rect.yoffset, src.rect.width, src.rect.height, src.rect.wstride, src.rect.hstride, src.rect.format,
dst.rect.xoffset, dst.rect.yoffset, dst.rect.width, dst.rect.height, dst.rect.wstride, dst.rect.hstride, dst.rect.format);
ALOGD_IF(log_level(DBG_DEBUG),"RK_RGA_PREPARE_ASYNC rgaRotateScale : src hnd=%p,dst hnd=%p, format=0x%x, transform=0x%x\n",
(void*)layer.sf_handle, (void*)(rgaBuffer.buffer()->handle), layer.format, rga_transform);
src.hnd = layer.sf_handle;
dst.hnd = rgaBuffer.buffer()->handle;
src.rotation = rga_transform;
RockchipRga& rkRga(RockchipRga::get());
ret = rkRga.RkRgaBlit(&src, &dst, NULL);
if(ret) {
ALOGE("rgaRotateScale error : src[x=%d,y=%d,w=%d,h=%d,ws=%d,hs=%d,format=0x%x],dst[x=%d,y=%d,w=%d,h=%d,ws=%d,hs=%d,format=0x%x]",
src.rect.xoffset, src.rect.yoffset, src.rect.width, src.rect.height, src.rect.wstride, src.rect.hstride, src.rect.format,
dst.rect.xoffset, dst.rect.yoffset, dst.rect.width, dst.rect.height, dst.rect.wstride, dst.rect.hstride, dst.rect.format);
ALOGE("rgaRotateScale error : %s,src hnd=%p,dst hnd=%p",
strerror(errno), (void*)layer.sf_handle, (void*)(rgaBuffer.buffer()->handle));
}
DumpLayer("rga", dst.hnd);
//instead of the original DrmHwcLayer
layer.is_rotate_by_rga = true;
layer.buffer.Clear();
layer.source_crop = DrmHwcRect<float>(dst_l,dst_t,dst_w,dst_h);
//The dst layer's format is NV12.
if(layer.format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
layer.format = HAL_PIXEL_FORMAT_YCrCb_NV12;
layer.sf_handle = rgaBuffer.buffer()->handle;
#if RK_VIDEO_SKIP_LINE
layer.SkipLine = 0;
#endif
layer.rga_handle = rgaBuffer.buffer()->handle;
return ret;
}
static int ApplyPreRotate(hwc_drm_display_t *hd, DrmHwcLayer &layer) {
int ret = 0;
ALOGD_IF(log_level(DBG_DEBUG), "%s:rgaBuffer_index=%d", __FUNCTION__, hd->rgaBuffer_index);
DrmRgaBuffer &rga_buffer = hd->rgaBuffers[hd->rgaBuffer_index];
ret = PrepareRgaBuffer(rga_buffer, layer);
if (ret) {
ALOGE("Failed to prepare rga buffer for RGA rotate %d", ret);
return ret;
}
#if 0
ret = display_comp->CreateNextTimelineFence("ApplyPreRotate");
if (ret <= 0) {
ALOGE("Failed to create RGA rotate release fence %d", ret);
return ret;
}
rga_buffer.set_release_fence_fd(ret);
#endif
return 0;
}
static void freeRgaBuffers(hwc_drm_display_t *hd) {
for(int i = 0; i < MaxRgaBuffers; i++) {
hd->rgaBuffers[i].Clear();
}
}
#endif
static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
hwc_display_contents_1_t **display_contents) {
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
int ret = -1;
#ifdef USE_PLANE_RESERVED
int win1_reserved = hwc_get_int_property( PROPERTY_TYPE ".hwc.win1.reserved", "0");
#endif
#ifdef USE_HWC2
DrmConnector *extend = ctx->drm.GetConnectorFromType(HWC_DISPLAY_EXTERNAL);
//Fake handle event if the hotplug happen earlyer than hwc thread.
if(get_frame() == 1 && !g_hasHotplug && extend && (extend->raw_state() == DRM_MODE_CONNECTED))
{
pthread_t hotplug_event;
if (pthread_create(&hotplug_event, NULL, hotplug_event_thread, ctx))
{
ALOGE("Create hotplug_event thread error .");
}
}
#endif
//Update LUT from baseparameter at boot time
if(get_frame() == 1){
hwc_SetGamma(&ctx->drm);
}
init_log_level();
hwc_dump_fps();
ALOGD_IF(log_level(DBG_VERBOSE),"----------------------------frame=%d start ----------------------------",get_frame());
ctx->layer_contents.clear();
ctx->layer_contents.reserve(num_displays);
ctx->comp_plane_group.clear();
ctx->drm.UpdateDisplayRoute();
DetectAuxStatus(ctx);
for (int i = 0; i < (int)num_displays; ++i) {
bool use_framebuffer_target = false;
if (!display_contents[i])
continue;
ALOGD_IF(log_level(DBG_VERBOSE), "************** display=%d **************", i);
int num_layers = display_contents[i]->numHwLayers;
for (int j = 0; j < num_layers; j++) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
dump_layer(ctx->gralloc, false, layer, j);
}
if(i == HWC_DISPLAY_VIRTUAL)
{
for (int j = 0; j < num_layers; ++j) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
layer->compositionType = HWC_FRAMEBUFFER;
}
continue;
}
ctx->layer_contents.emplace_back();
DrmHwcDisplayContents &layer_content = ctx->layer_contents.back();
ctx->comp_plane_group.emplace_back();
DrmCompositionDisplayPlane &comp_plane = ctx->comp_plane_group.back();
comp_plane.display = i;
if(ctx->fb_blanked == FB_BLANK_POWERDOWN){
ALOGD_IF(log_level(DBG_DEBUG),"%s: display=%d fb_blanked = %s,line = %d",__FUNCTION__,i,
ctx->fb_blanked == FB_BLANK_POWERDOWN ? "POWERDOWN" : "ACTIVE",__LINE__);
hwc_list_nodraw(display_contents[i]);
continue;
}
DrmConnector *connector = ctx->drm.GetConnectorFromType(i);
if (!connector) {
ALOGE("%s:Failed to get connector for display %d line=%d",__FUNCTION__, i,__LINE__);
hwc_list_nodraw(display_contents[i]);
continue;
}
hwc_drm_display_t *hd = &ctx->displays[connector->display()];
DrmCrtc *crtc = ctx->drm.GetCrtcFromConnector(connector);
if (connector->state() != DRM_MODE_CONNECTED || !crtc) {
ALOGE("%s: display=%d, connector[%d] is disconnect type=%s",__FUNCTION__,i,
connector->display(),ctx->drm.connector_type_str(connector->get_type()));
hwc_list_nodraw(display_contents[i]);
continue;
}
#if RK_3D_VIDEO
hd->stereo_mode = NON_3D;
int bk_is_3d = hd->is_3d;
hd->is_3d = detect_3d_mode(hd, display_contents[i], i);
if(bk_is_3d != hd->is_3d)
{
int timeline = 0;
char acTimelie[10];
timeline = property_get_int32( PROPERTY_TYPE ".display.timeline", -1);
timeline++;
snprintf(acTimelie,10,"%d",timeline);
property_set( PROPERTY_TYPE ".display.timeline", acTimelie);
}
#endif
update_hdmi_output_format(ctx, connector, i, hd);
update_display_bestmode(hd, i, connector);
DrmMode mode = connector->best_mode();
connector->set_current_mode(mode);
hd->rel_xres = mode.h_display();
hd->rel_yres = mode.v_display();
hd->v_total = mode.v_total();
hd->w_scale = (float)mode.h_display() / hd->framebuffer_width;
hd->h_scale = (float)mode.v_display() / hd->framebuffer_height;
int fbSize = hd->framebuffer_width * hd->framebuffer_height;
//get plane size for display
std::vector<PlaneGroup *>& plane_groups = ctx->drm.GetPlaneGroups();
hd->iPlaneSize = 0;
hd->hasEotfPlane = false;
hd->is_interlaced = (mode.interlaced()>0) ? true:false;
hd->bPreferMixDown = false;
for (std::vector<PlaneGroup *> ::const_iterator iter = plane_groups.begin();
iter != plane_groups.end(); ++iter)
{
#ifdef USE_PLANE_RESERVED
if (win1_reserved > 0 && GetCrtcSupported(*crtc, (*iter)->possible_crtcs) &&
((*iter)->planes.at(0)->type() == DRM_PLANE_TYPE_OVERLAY) &&
(*iter)->planes.at(0)->get_yuv())
{
(*iter)->b_reserved = true;
for(std::vector<DrmPlane*> ::const_iterator iter_plane = (*iter)->planes.begin();
iter_plane != (*iter)->planes.end(); ++iter_plane)
{
(*iter_plane)->set_reserved(true);
}
ALOGD_IF(log_level(DBG_DEBUG),"Enable USE_PLANE_RESERVED, plane share_id = %" PRIu64 "", (*iter)->share_id);
continue;
}
#endif
if(hd->is_interlaced && (*iter)->planes.size() > 2)
{
(*iter)->b_reserved = true;
// continue;
}
else if(GetCrtcSupported(*crtc, (*iter)->possible_crtcs))
{
(*iter)->b_reserved = false;
hd->iPlaneSize++;
if(!hd->hasEotfPlane)
{
for(std::vector<DrmPlane*> ::const_iterator iter_plane = (*iter)->planes.begin();
iter_plane != (*iter)->planes.end(); ++iter_plane)
{
if((*iter_plane)->get_hdr2sdr())
{
hd->hasEotfPlane = true;
break;
}
}
}
}
}
#if SKIP_BOOT
if(g_boot_cnt < BOOT_COUNT)
{
hwc_list_nodraw(display_contents[i]);
ALOGD_IF(log_level(DBG_DEBUG),"prepare skip %d",g_boot_cnt);
return 0;
}
#endif
for (int j = 0; j < num_layers-1; j++) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
if(layer->handle)
{
if(layer->compositionType == HWC_NODRAW)
layer->compositionType = HWC_FRAMEBUFFER;
}
}
int format = 0;
int usage = 0;
bool isHdr = false;
hd->is10bitVideo = false;
hd->isVideo = false;
for (int j = 0; j < num_layers-1; j++) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
if(layer->handle)
{
#if (!RK_PER_MODE && RK_DRM_GRALLOC)
format = hwc_get_handle_attibute(ctx->gralloc,layer->handle, ATT_FORMAT);
#else
format = hwc_get_handle_format(ctx->gralloc,layer->handle);
#endif
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12)
{
hd->isVideo = true;
}
if(format == HAL_PIXEL_FORMAT_YCrCb_NV12_10)
{
hd->is10bitVideo = true;
hd->isVideo = true;
usage = hwc_get_handle_usage(ctx->gralloc,layer->handle);
ALOGD_IF(log_level(DBG_VERBOSE),"%s:line=%d usage = %x",__FUNCTION__,__LINE__,
usage);
ALOGD_IF(log_level(DBG_VERBOSE),"%s:line=%d isSupportSt2084 = %d, isSupportHLG = %d",__FUNCTION__,__LINE__,
connector->isSupportSt2084(),connector->isSupportHLG() );
if((usage & 0x0F000000) == HDR_ST2084_USAGE || (usage & 0x0F000000) == HDR_HLG_USAGE)
{
isHdr = true;
//vop limit: hdr video must in the bottom.
if(j != 0)
{
ALOGD_IF(log_level(DBG_DEBUG),"hdr video must in the bottom of layer list,go to GPU GLES at line=%d", __LINE__);
use_framebuffer_target = true;
}
if(hd->isHdr != isHdr && connector->is_hdmi_support_hdr())
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s:line=%d isSupportSt2084 = %d, isSupportHLG = %d",__FUNCTION__,__LINE__,
connector->isSupportSt2084(),connector->isSupportHLG() );
uint32_t android_colorspace = hwc_get_layer_colorspace(layer);
hdr_metadata_s hdr_metadata;
memset(&hdr_metadata, 0, sizeof(hdr_metadata_s));
if((android_colorspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_ST2084
&& connector->isSupportSt2084())
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s:line=%d has st2084",__FUNCTION__,__LINE__);
HDR_METADATA_EOTF_T(hdr_metadata) = SMPTE_ST2084;
}
else if((android_colorspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_HLG
&& connector->isSupportHLG())
{
ALOGD_IF(log_level(DBG_VERBOSE),"%s:line=%d has HLG",__FUNCTION__,__LINE__);
HDR_METADATA_EOTF_T(hdr_metadata) = HLG;
}
else
{
//ALOGE("Unknow etof %d",eotf);
HDR_METADATA_EOTF_T(hdr_metadata) = TRADITIONAL_GAMMA_SDR;
}
set_hdmi_hdr_meta(ctx, connector, &hdr_metadata, hd, android_colorspace);
}
break;
}
}
}
}
bool force_not_invalid_refresh = false;
for (int j = 0; j < num_layers-1; j++) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
if(layer->handle)
{
#if RK_DRM_GRALLOC
format = hwc_get_handle_attibute(ctx->gralloc,layer->handle, ATT_FORMAT);
#else
format = hwc_get_handle_format(ctx->gralloc,layer->handle);
#endif
#if RK_PRINT_LAYER_NAME
char layername[100];
#ifdef USE_HWC2
HWC_GET_HANDLE_LAYERNAME(ctx->gralloc,layer,layer->handle, layername, 100);
#else
strcpy(layername, layer->LayerName);
#endif
#endif
int src_l,src_t,src_w,src_h;
src_l = (int)layer->sourceCropf.left;
src_t = (int)layer->sourceCropf.top;
src_w = (int)(layer->sourceCropf.right - layer->sourceCropf.left);
src_h = (int)(layer->sourceCropf.bottom - layer->sourceCropf.top);
if(!force_not_invalid_refresh && src_w > src_h && src_w >= 3840
&& format != HAL_PIXEL_FORMAT_YCrCb_NV12 && format != HAL_PIXEL_FORMAT_YCrCb_NV12_10)
{
force_not_invalid_refresh = true;
}
/*
* VOP can't display layer size < 16 pixel , so set layer HWC_NODRAW in 1080P
*/
if( hd->rel_xres * hd->rel_yres > 2073600 && (src_w * src_h < 16 ))
{
layer->compositionType = HWC_NODRAW;
//layer->flags |= HWC_SKIP_LAYER;
ALOGD_IF(log_level(DBG_DEBUG),
"%s:line=%d layer size[%d,%d] too small ,set HWC_NODRAW",
__FUNCTION__,__LINE__,src_w,src_h);
}
/*
* VOP can't scale layer width or height < 4 pixel , so set layer HWC_SKIP_LAYER to
* compose by GPU.
*/
if( src_w < 4 || src_h < 4 )
{
layer->compositionType = HWC_FRAMEBUFFER;
layer->flags |= HWC_SKIP_LAYER;
ALOGD_IF(log_level(DBG_DEBUG),
"%s:line=%d layer size[%d,%d] too small ,set HWC_SKIP_LAYER",
__FUNCTION__,__LINE__,src_w,src_h);
}
#if RK_PRINT_LAYER_NAME
if(strstr(layername,"drawpath"))
{
hd->bPreferMixDown = true;
ALOGD_IF(log_level(DBG_DEBUG),"%s:line=%d in drawpath mode prefer use mix down policy",
__FUNCTION__,__LINE__);
}
#endif
}
}
#if RK_INVALID_REFRESH
if(ctx->mOneWinOpt && force_not_invalid_refresh && hd->rel_xres >= 3840 && hd->rel_xres != hd->framebuffer_width)
{
ALOGD_IF(log_level(DBG_DEBUG),"disable static timer");
ctx->mOneWinOpt = false;
}
if(hd->isHdr){
ALOGD_IF(log_level(DBG_DEBUG),"HDR video mode,disable static timer");
ctx->mOneWinOpt = false;
}
#endif
//Switch hdr mode
if(hd->isHdr != isHdr)
{
hd->isHdr = isHdr;
#if RK_HDR_PERF_MODE
if(hd->isHdr)
{
ALOGD_IF(log_level(DBG_DEBUG),"Enter hdr performance mode");
ctl_little_cpu(0);
ctl_cpu_performance(1, 1);
}
else
{
ALOGD_IF(log_level(DBG_DEBUG),"Exit hdr performance mode");
ctl_cpu_performance(0, 1);
ctl_little_cpu(1);
}
#endif
if(!hd->isHdr && connector->is_hdmi_support_hdr())
{
uint32_t android_colorspace = 0;
hdr_metadata_s hdr_metadata;
ALOGD_IF(log_level(DBG_VERBOSE),"disable hdmi hdr meta");
memset(&hdr_metadata, 0, sizeof(hdr_metadata_s));
set_hdmi_hdr_meta(ctx, connector, &hdr_metadata, hd, android_colorspace);
}
}
#if RK_3D_VIDEO
int iLastFps = num_layers-1;
if(hd->stereo_mode == FPS_3D)
{
for(int j=num_layers-1; j>=0; j--) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
int32_t alreadyStereo = 0;
#ifdef USE_HWC2
if(layer->handle)
{
alreadyStereo = hwc_get_handle_alreadyStereo(ctx->gralloc, layer->handle);
if(alreadyStereo < 0)
{
ALOGE("hwc_get_handle_alreadyStereo fail");
alreadyStereo = 0;
}
}
#else
alreadyStereo = layer->alreadyStereo;
#endif
if(alreadyStereo == FPS_3D) {
iLastFps = j;
break;
}
}
for (int j = 0; j < iLastFps; j++)
{
display_contents[i]->hwLayers[j].compositionType = HWC_NODRAW;
}
}
#endif
#if RK_VIDEO_UI_OPT
video_ui_optimize(ctx->gralloc, display_contents[i], &ctx->displays[connector->display()]);
#endif
if(!use_framebuffer_target)
use_framebuffer_target = is_use_gles_comp(ctx, connector, display_contents[i], connector->display());
bool bHasFPS_3D_UI = false;
int index = 0;
for (int j = 0; j < num_layers; j++) {
hwc_layer_1_t *sf_layer = &display_contents[i]->hwLayers[j];
if(!(sf_layer->flags & HWC_SKIP_LAYER) && sf_layer->compositionType != HWC_FRAMEBUFFER_TARGET && sf_layer->handle == NULL)
continue;
if(sf_layer->compositionType == HWC_NODRAW)
continue;
#if RK_3D_VIDEO
if(hd->stereo_mode == FPS_3D && iLastFps < num_layers-1)
{
int32_t alreadyStereo = 0, displayStereo = 0;
#ifdef USE_HWC2
alreadyStereo = hwc_get_handle_alreadyStereo(ctx->gralloc, sf_layer->handle);
if(alreadyStereo < 0)
{
ALOGE("hwc_get_handle_alreadyStereo fail");
alreadyStereo = 0;
}
displayStereo = hwc_get_handle_displayStereo(ctx->gralloc, sf_layer->handle);
if(displayStereo < 0)
{
ALOGE("hwc_get_handle_alreadyStereo fail");
displayStereo = 0;
}
#else
alreadyStereo = sf_layer->alreadyStereo;
displayStereo = sf_layer->displayStereo;
#endif
if(j>iLastFps && alreadyStereo!= FPS_3D && displayStereo)
{
bHasFPS_3D_UI = true;
}
}
#endif
layer_content.layers.emplace_back();
DrmHwcLayer &layer = layer_content.layers.back();
ret = layer.InitFromHwcLayer(ctx, i, sf_layer, ctx->importer.get(), ctx->gralloc, false);
if (ret) {
ALOGE("Failed to init composition from layer %d", ret);
return ret;
}
layer.index = j;
index = j;
std::ostringstream out;
layer.dump_drm_layer(j,&out);
ALOGD_IF(log_level(DBG_DEBUG),"%s",out.str().c_str());
}
#if RK_3D_VIDEO
if(bHasFPS_3D_UI)
{
hwc_layer_1_t *sf_layer = &display_contents[i]->hwLayers[num_layers-1];
if(sf_layer->handle == NULL)
continue;
layer_content.layers.emplace_back();
DrmHwcLayer &layer = layer_content.layers.back();
ret = layer.InitFromHwcLayer(ctx, i, sf_layer, ctx->importer.get(), ctx->gralloc, true);
if (ret) {
ALOGE("Failed to init composition from layer %d", ret);
return ret;
}
index++;
layer.index = index;
std::ostringstream out;
layer.dump_drm_layer(index,&out);
ALOGD_IF(log_level(DBG_DEBUG),"clone layer: %s",out.str().c_str());
}
#endif
//vop limit: If vop cann't support alpha scale,it should go into gles.
if(!crtc->get_alpha_scale())
{
for (size_t j = 0; j < layer_content.layers.size(); j++) {
DrmHwcLayer& layer = layer_content.layers[j];
if(layer.format == HAL_PIXEL_FORMAT_RGBA_8888 || layer.format == HAL_PIXEL_FORMAT_BGRA_8888)
{
if(layer.h_scale_mul != 1.0 || layer.v_scale_mul != 1.0)
{
use_framebuffer_target = true;
ALOGD_IF(log_level(DBG_DEBUG),"alpha scale is not support,format=0x%x,h_scale=%f,v_scale=%f,go to GPU GLES at line=%d",
layer.format, layer.h_scale_mul, layer.v_scale_mul, __LINE__);
break;
}
if(layer.alpha != 0xff)
{
use_framebuffer_target = true;
ALOGD_IF(log_level(DBG_DEBUG),"per-pixel alpha with global alpha is not support,global alpha=0x%x,go to GPU GLES at line=%d",
layer.alpha, __LINE__);
break;
}
}
}
}
if(!use_framebuffer_target)
{
int iRgaCnt = 0;
for (size_t j = 0; j < layer_content.layers.size(); j++) {
DrmHwcLayer& layer = layer_content.layers[j];
if(layer.mlayer->compositionType == HWC_FRAMEBUFFER_TARGET)
continue;
#if !RK_RGA_SCALE_AND_ROTATE
if(layer.h_scale_mul > 1.0 && (int)(layer.display_frame.right - layer.display_frame.left) > 2560)
{
ALOGD_IF(log_level(DBG_DEBUG),"On rk3368 don't use rga for scale, go to GPU GLES at line=%d", __LINE__);
use_framebuffer_target = true;
break;
}
#endif
if(layer.transform!=DrmHwcTransform::kRotate0
#if RK_RGA_SCALE_AND_ROTATE
|| (layer.h_scale_mul > 1.0 && (int)(layer.display_frame.right - layer.display_frame.left) > 2560)
#endif
)
{
iRgaCnt++;
}
}
if(iRgaCnt > 1)
{
ALOGD_IF(log_level(DBG_DEBUG),"rga cnt = %d, go to GPU GLES at line=%d", iRgaCnt, __LINE__);
use_framebuffer_target = true;
}
}
if(!use_framebuffer_target)
{
bool bAllMatch = false;
hd->mixMode = HWC_DEFAULT;
if(crtc && layer_content.layers.size()>0)
{
bAllMatch = mix_policy(&ctx->drm, crtc, &ctx->displays[connector->display()],layer_content.layers,
hd->iPlaneSize, fbSize, comp_plane.composition_planes);
}
if(!bAllMatch)
{
ALOGD_IF(log_level(DBG_DEBUG),"mix_policy failed,go to GPU GLES at line=%d", __LINE__);
use_framebuffer_target = true;
}
}
for (int j = 0; j < num_layers; ++j) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
if (!use_framebuffer_target && layer->compositionType != HWC_MIX) {
// If the layer is off the screen, don't earmark it for an overlay.
// We'll leave it as-is, which effectively just drops it from the frame
const hwc_rect_t *frame = &layer->displayFrame;
if ((frame->right - frame->left) <= 0 ||
(frame->bottom - frame->top) <= 0 ||
frame->right <= 0 || frame->bottom <= 0 ||
frame->left >= (int)hd->framebuffer_width ||
frame->top >= (int)hd->framebuffer_height)
{
continue;
}
if (layer->compositionType == HWC_FRAMEBUFFER)
layer->compositionType = HWC_OVERLAY;
} else {
switch (layer->compositionType) {
case HWC_MIX:
case HWC_OVERLAY:
case HWC_BACKGROUND:
case HWC_SIDEBAND:
case HWC_CURSOR_OVERLAY:
layer->compositionType = HWC_FRAMEBUFFER;
break;
}
}
#if DUAL_VIEW_MODE
if(hd->bDualViewMode && i == HWC_DISPLAY_EXTERNAL && layer->compositionType != HWC_FRAMEBUFFER_TARGET)
{
layer->compositionType = HWC_NODRAW;
}
#endif
}
#if RK_RGA_PREPARE_ASYNC
if(!use_framebuffer_target && ctx->drm.isSupportRkRga())
{
bool bUseRga = false;
for (size_t j = 0; j < layer_content.layers.size(); j++) {
DrmHwcLayer& layer = layer_content.layers[j];
if((layer.is_yuv && layer.transform!=DrmHwcTransform::kRotate0))
{
ret = ApplyPreRotate(hd,layer);
if (ret)
{
freeRgaBuffers(hd);
hd->mUseRga = hd->mUseRga ? false : hd->mUseRga;
return ret;
}
hd->rgaBuffer_index = (hd->rgaBuffer_index + 1) % MaxRgaBuffers;
bUseRga = true;
hd->mUseRga = hd->mUseRga ? hd->mUseRga : true;
}
}
if(hd->mUseRga && !bUseRga)
{
freeRgaBuffers(hd);
hd->mUseRga = false;
}
}
#endif
if(use_framebuffer_target)
ctx->isGLESComp = true;
else
ctx->isGLESComp = false;
if(ctx->isGLESComp)
{
#if RK_ROTATE_VIDEO_MODE
if(hd->bRotateVideoMode)
{
ALOGD_IF(log_level(DBG_DEBUG), "Exit Rotate video Mode mode");
set_cpu_min_freq(hd->original_min_freq);
hd->bRotateVideoMode = false;
}
#endif
//remove all layers except fb layer
for (auto k = layer_content.layers.begin(); k != layer_content.layers.end();)
{
//remove gles layers
if((*k).mlayer->compositionType != HWC_FRAMEBUFFER_TARGET)
k = layer_content.layers.erase(k);
else
k++;
}
//match plane for gles composer.
bool bAllMatch = match_process(&ctx->drm, crtc, hd->is_interlaced ,layer_content.layers,
hd->iPlaneSize, fbSize, comp_plane.composition_planes);
if(!bAllMatch)
ALOGE("Fetal error when match plane for fb layer");
}
else
{
#if RK_ROTATE_VIDEO_MODE
if(hd->transform_nv12==1 && !hd->bRotateVideoMode)
{
ALOGD_IF(log_level(DBG_DEBUG), "Enter Rotate video Mode mode");
hd->original_min_freq = set_cpu_min_freq(408);
hd->bRotateVideoMode = true;
}
else if(hd->transform_nv12!=1 && hd->bRotateVideoMode)
{
ALOGD_IF(log_level(DBG_DEBUG), "Exit Rotate video Mode mode");
set_cpu_min_freq(hd->original_min_freq);
hd->bRotateVideoMode = false;
}
#endif
}
for (int j = 0; j < num_layers; ++j) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
char layername[100];
#if RK_PRINT_LAYER_NAME
#ifdef USE_HWC2
if(layer->handle == NULL)
{
strcpy(layername,"");
}
else
{
HWC_GET_HANDLE_LAYERNAME(ctx->gralloc,layer,layer->handle, layername, 100);
}
#else
strcpy(layername, layer->LayerName);
#endif
#endif
if(layer->compositionType==HWC_FRAMEBUFFER)
ALOGD_IF(log_level(DBG_DEBUG),"%s: HWC_FRAMEBUFFER",layername);
else if(layer->compositionType==HWC_OVERLAY)
ALOGD_IF(log_level(DBG_DEBUG),"%s: HWC_OVERLAY",layername);
else
ALOGD_IF(log_level(DBG_DEBUG),"%s: HWC_OTHER",layername);
}
}
#if RK_INVALID_REFRESH
if(ctx->mOneWinOpt)
ctx->mOneWinOpt = false;
#endif
return 0;
}
static void hwc_add_layer_to_retire_fence(
hwc_layer_1_t *layer, hwc_display_contents_1_t *display_contents) {
if (layer->releaseFenceFd < 0)
return;
if (display_contents->retireFenceFd >= 0) {
int old_retire_fence = display_contents->retireFenceFd;
display_contents->retireFenceFd =
sync_merge("dc_retire", old_retire_fence, layer->releaseFenceFd);
close(old_retire_fence);
} else {
display_contents->retireFenceFd = dup(layer->releaseFenceFd);
}
}
/* rk:
* acquireFenceFd may transfer from hwc_layer_1_t to DrmHwcLayer.
* So we signal acquire_fence of DrmHwcLayer at first.
* Then we try to signal acquireFenceFd of hwc_layer_1_t.
*/
void signal_all_fence(DrmHwcDisplayContents &display_contents,hwc_display_contents_1_t *dc)
{
for (size_t j=0; j< display_contents.layers.size(); j++) {
DrmHwcLayer &layer = display_contents.layers[j];
int acquire_fence = layer.acquire_fence.get();
if(acquire_fence >= 0)
{
int ret = sync_wait(acquire_fence, 1000);
if (ret) {
ALOGE("signal_all_fence Failed to wait for acquire %d/%d 1000ms", acquire_fence, ret);
continue;
}
layer.acquire_fence.Close();
}
}
hwc_sync_release(dc);
}
static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
hwc_display_contents_1_t **sf_display_contents) {
ATRACE_CALL();
#ifdef USE_HWC2
g_waitHwcSetHotplug = true;
#endif
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
int ret = 0;
inc_frame();
std::vector<CheckedOutputFd> checked_output_fences;
std::vector<DrmHwcDisplayContents> displays_contents;
std::vector<DrmCompositionDisplayLayersMap> layers_map;
std::vector<std::vector<size_t>> layers_indices;
std::vector<uint32_t> fail_displays;
DrmComposition* composition = NULL;
// layers_map.reserve(num_displays);
layers_indices.reserve(num_displays);
// Phase one does nothing that would cause errors. Only take ownership of FDs.
for (size_t i = 0; i < num_displays; ++i) {
hwc_display_contents_1_t *dc = sf_display_contents[i];
DrmHwcDisplayContents &display_contents = ctx->layer_contents[i];
displays_contents.emplace_back();
DrmHwcDisplayContents &display_contents_tmp = displays_contents.back();
layers_indices.emplace_back();
if (!sf_display_contents[i])
continue;
#if SKIP_BOOT
if(g_boot_cnt < BOOT_COUNT) {
hwc_sync_release(sf_display_contents[i]);
if(0 == i)
g_boot_cnt++;
ALOGD_IF(log_level(DBG_DEBUG),"set skip %d",g_boot_cnt);
return 0;
}
#endif
if (i == HWC_DISPLAY_VIRTUAL) {
ctx->virtual_compositor_worker.QueueComposite(dc);
continue;
}
if(ctx->fb_blanked == FB_BLANK_POWERDOWN){
ALOGD_IF(log_level(DBG_DEBUG),"%s: display=%zu fb_blanked = %s,line = %d",__FUNCTION__,i,
ctx->fb_blanked == FB_BLANK_POWERDOWN ? "POWERDOWN" : "ACTIVE",__LINE__);
hwc_sync_release(sf_display_contents[i]);
ctx->drm.ClearDisplay(i);
continue;
}
DrmConnector *c = ctx->drm.GetConnectorFromType(i);
size_t num_dc_layers = dc->numHwLayers;
if (!c || c->state() != DRM_MODE_CONNECTED || num_dc_layers==1) {
if(c)
ALOGD_IF(log_level(DBG_DEBUG),"hwc_set connector is disconnect,type=%s",ctx->drm.connector_type_str(c->get_type()));
if(num_dc_layers==1)
ALOGD_IF(log_level(DBG_DEBUG), "%s display=%zu layer is null", __FUNCTION__, i);
hwc_sync_release(sf_display_contents[i]);
ctx->drm.ClearDisplay(i);
continue;
}
DumpLayerList(dc,ctx->gralloc);
std::ostringstream display_index_formatter;
display_index_formatter << "retire fence for display " << i;
std::string display_fence_description(display_index_formatter.str());
checked_output_fences.emplace_back(&dc->retireFenceFd,
display_fence_description.c_str(),
ctx->dummy_timeline);
display_contents.retire_fence = OutputFd(&dc->retireFenceFd);
int framebuffer_target_index = -1;
for (size_t j = 0; j < num_dc_layers; ++j) {
hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET) {
framebuffer_target_index = j;
break;
}
}
for (size_t j = 0; j < num_dc_layers; ++j) {
size_t k = 0;
hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
// In prepare() we marked all layers FRAMEBUFFER between SKIP_LAYER's.
// This means we should insert the FB_TARGET layer in the composition
// stack at the location of the first skip layer, and ignore the rest.
if (sf_layer->flags & HWC_SKIP_LAYER) {
//rk: SurfaceFlinger will create acquireFenceFd for nodraw skip layer.
// Close it here to avoid anon_inode:sync_fence fd leak.
if(sf_layer->compositionType == HWC_NODRAW)
{
if(sf_layer->acquireFenceFd >= 0)
{
close(sf_layer->acquireFenceFd);
sf_layer->acquireFenceFd = -1;
}
}
if (framebuffer_target_index < 0)
continue;
int idx = framebuffer_target_index;
framebuffer_target_index = -1;
hwc_layer_1_t *fbt_layer = &dc->hwLayers[idx];
if (!fbt_layer->handle || (fbt_layer->flags & HWC_SKIP_LAYER)) {
ALOGE("Invalid HWC_FRAMEBUFFER_TARGET with HWC_SKIP_LAYER present");
continue;
}
continue;
}
char value[PROPERTY_VALUE_MAX];
property_get( PROPERTY_TYPE ".hwc.force_wait_acquireFence", value, "0");
if(atoi(value) != 0){
// rk: wait acquireFenceFd at hwc_set.
if(sf_layer->acquireFenceFd > 0)
{
sync_wait(sf_layer->acquireFenceFd, -1);
close(sf_layer->acquireFenceFd);
sf_layer->acquireFenceFd = -1;
}
}
for (k = 0; k < display_contents.layers.size(); ++k)
{
DrmHwcLayer &layer = display_contents.layers[k];
if(j == layer.index)
{
// sf_layer = layer.raw_sf_layer;
layer.acquire_fence.Set(sf_layer->acquireFenceFd);
sf_layer->acquireFenceFd = -1;
std::ostringstream layer_fence_formatter;
layer_fence_formatter << "release fence for layer " << j << " of display "
<< i;
std::string layer_fence_description(layer_fence_formatter.str());
checked_output_fences.emplace_back(&sf_layer->releaseFenceFd,
layer_fence_description.c_str(),
ctx->dummy_timeline);
layer.release_fence = OutputFd(&sf_layer->releaseFenceFd);
break;
}
}
if(k == display_contents.layers.size())
{
display_contents_tmp.layers.emplace_back();
DrmHwcLayer &layer = display_contents_tmp.layers.back();
layer.acquire_fence.Set(sf_layer->acquireFenceFd);
sf_layer->acquireFenceFd = -1;
std::ostringstream layer_fence_formatter;
layer_fence_formatter << "release fence for layer " << j << " of display "
<< i;
std::string layer_fence_description(layer_fence_formatter.str());
checked_output_fences.emplace_back(&sf_layer->releaseFenceFd,
layer_fence_description.c_str(),
ctx->dummy_timeline);
layer.release_fence = OutputFd(&sf_layer->releaseFenceFd);
}
}
if(display_contents.layers.size() == 0 && framebuffer_target_index >= 0)
{
hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index];
if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) {
ALOGE(
"Expected valid layer with HWC_FRAMEBUFFER_TARGET when all "
"HWC_OVERLAY layers are skipped.");
fail_displays.emplace_back(i);
ret = -EINVAL;
}
}
}
#if 0
if (ret)
return ret;
#endif
int fail_displays_count = 0;
for (size_t i = 0; i < num_displays; ++i) {
hwc_display_contents_1_t *dc = sf_display_contents[i];
DrmHwcDisplayContents &display_contents = ctx->layer_contents[i];
bool bFindDisplay = false;
if (!sf_display_contents[i] || i == HWC_DISPLAY_VIRTUAL)
continue;
for (auto &fail_display : fail_displays) {
if( i == fail_display )
{
bFindDisplay = true;
fail_displays_count ++;
ALOGD_IF(log_level(DBG_VERBOSE),"%s:line=%d,Find fail display %zu",__FUNCTION__,__LINE__,i);
break;
}
}
if(bFindDisplay)
continue;
size_t num_dc_layers = dc->numHwLayers;
DrmConnector *c = ctx->drm.GetConnectorFromType(i);
if (!c || c->state() != DRM_MODE_CONNECTED || num_dc_layers==1) {
ALOGD_IF(log_level(DBG_VERBOSE),
"%s,display %zu Connector is NULL or disconnect ,layer_list is NULL",__FUNCTION__,i);
continue;
}
/*
* DUAL_VIEW_MODE
* Primary layers -> Primary Device
* |
* -> Extend Device
*/
#if DUAL_VIEW_MODE
static int primaryAcquirFenceDup = -1;
hwc_drm_display_t *hd = &ctx->displays[c->display()];
if(hd->bDualViewMode){
DrmHwcDisplayContents &display_contents_pri = ctx->layer_contents[0];
layers_map.emplace_back();
DrmCompositionDisplayLayersMap &map = layers_map.back();
map.display = i;
map.geometry_changed =
(dc->flags & HWC_GEOMETRY_CHANGED) == HWC_GEOMETRY_CHANGED;
for (size_t j=0; j< display_contents.layers.size(); j++) {
DrmHwcLayer &layer = display_contents.layers[j];
DrmHwcLayer &layer_pri = display_contents_pri.layers[j];
//Dup primary acquireFence to extend, should wait acquireFence before commmit.
if( i == HWC_DISPLAY_PRIMARY ){
if( primaryAcquirFenceDup > 0){
close(primaryAcquirFenceDup);
primaryAcquirFenceDup = -1;
}
if(layer_pri.acquire_fence.get() > 0){
primaryAcquirFenceDup = dup(layer_pri.acquire_fence.get());
}
}else if( i == HWC_DISPLAY_EXTERNAL ){
if(primaryAcquirFenceDup > 0){
layer.acquire_fence.Set(primaryAcquirFenceDup);
primaryAcquirFenceDup = -1;
}
}
if(!layer_pri.sf_handle && layer_pri.raw_sf_layer->handle)
{
layer_pri.sf_handle = layer_pri.raw_sf_layer->handle;
#if (!RK_PER_MODE && RK_DRM_GRALLOC)
layer.width = hwc_get_handle_attibute(ctx->gralloc,layer_pri.sf_handle,ATT_WIDTH);
layer.height = hwc_get_handle_attibute(ctx->gralloc,layer_pri.sf_handle,ATT_HEIGHT);
layer.stride = hwc_get_handle_attibute(ctx->gralloc,layer_pri.sf_handle,ATT_STRIDE);
layer.format = hwc_get_handle_attibute(ctx->gralloc,layer_pri.sf_handle,ATT_FORMAT);
#else
layer.width = hwc_get_handle_width(ctx->gralloc,layer_pri.sf_handle);
layer.height = hwc_get_handle_height(ctx->gralloc,layer_pri.sf_handle);
layer.stride = hwc_get_handle_stride(ctx->gralloc,layer_pri.sf_handle);
layer.format = hwc_get_handle_format(ctx->gralloc,layer_pri.sf_handle);
#endif
}
if(!layer_pri.sf_handle)
{
ALOGE("%s: disply=%zu sf_handle is null,maybe fb target is null",__FUNCTION__,i);
signal_all_fence(display_contents, dc);
ctx->drm.ClearDisplay(i);
std::vector<DrmCompositionDisplayLayersMap>::iterator iter = layers_map.begin()+i - fail_displays_count;
layers_map.erase(iter);
break;
}
if(!layer_pri.bClone_)
{
#if RK_RGA_PREPARE_ASYNC
if(!layer_pri.is_rotate_by_rga)
#endif
layer.ImportBuffer(ctx, layer_pri.raw_sf_layer, ctx->importer.get());
#if RK_RGA_PREPARE_ASYNC
else
{
ret = layer.buffer.ImportBuffer(layer_pri.rga_handle,
ctx->importer.get()
#if RK_VIDEO_SKIP_LINE
, layer_pri.SkipLine
#endif
);
if (ret) {
ALOGE("Failed to import rga buffer ret=%d", ret);
goto err;
}
ret = layer_pri.handle.CopyBufferHandle(layer_pri.rga_handle, ctx->gralloc);
if (ret) {
ALOGE("Failed to copy rga handle ret=%d", ret);
goto err;
}
}
#endif
}
map.layers.emplace_back(std::move(layer));
}
}else
#endif //DUAL_VIEW_MODE
{
layers_map.emplace_back();
DrmCompositionDisplayLayersMap &map = layers_map.back();
map.display = i;
map.geometry_changed =
(dc->flags & HWC_GEOMETRY_CHANGED) == HWC_GEOMETRY_CHANGED;
for (size_t j=0; j< display_contents.layers.size(); j++) {
DrmHwcLayer &layer = display_contents.layers[j];
if(!layer.sf_handle && layer.raw_sf_layer && layer.raw_sf_layer->handle)
{
layer.sf_handle = layer.raw_sf_layer->handle;
#if (!RK_PER_MODE && RK_DRM_GRALLOC)
layer.width = hwc_get_handle_attibute(ctx->gralloc,layer.sf_handle,ATT_WIDTH);
layer.height = hwc_get_handle_attibute(ctx->gralloc,layer.sf_handle,ATT_HEIGHT);
layer.stride = hwc_get_handle_attibute(ctx->gralloc,layer.sf_handle,ATT_STRIDE);
layer.format = hwc_get_handle_attibute(ctx->gralloc,layer.sf_handle,ATT_FORMAT);
#else
layer.width = hwc_get_handle_width(ctx->gralloc,layer.sf_handle);
layer.height = hwc_get_handle_height(ctx->gralloc,layer.sf_handle);
layer.stride = hwc_get_handle_stride(ctx->gralloc,layer.sf_handle);
layer.format = hwc_get_handle_format(ctx->gralloc,layer.sf_handle);
#endif
}
if(!layer.sf_handle)
{
ALOGE("%s: disply=%zu sf_handle is null,maybe fb target is null",__FUNCTION__,i);
signal_all_fence(display_contents, dc);
ctx->drm.ClearDisplay(i);
std::vector<DrmCompositionDisplayLayersMap>::iterator iter = layers_map.begin()+i - fail_displays_count;
layers_map.erase(iter);
break;
}
if(!layer.raw_sf_layer)
{
ALOGE("%s: disply=%zu raw_sf_handle is null, hw_layer init error",__FUNCTION__,i);
signal_all_fence(display_contents, dc);
ctx->drm.ClearDisplay(i);
std::vector<DrmCompositionDisplayLayersMap>::iterator iter = layers_map.begin()+i - fail_displays_count;
layers_map.erase(iter);
break;
}
if(!layer.bClone_)
{
#if RK_RGA_PREPARE_ASYNC
if(!layer.is_rotate_by_rga)
#endif
layer.ImportBuffer(ctx, layer.raw_sf_layer, ctx->importer.get());
#if RK_RGA_PREPARE_ASYNC
else
{
ret = layer.buffer.ImportBuffer(layer.rga_handle,
ctx->importer.get()
#if RK_VIDEO_SKIP_LINE
, layer.SkipLine
#endif
);
if (ret) {
ALOGE("Failed to import rga buffer ret=%d", ret);
goto err;
}
ret = layer.handle.CopyBufferHandle(layer.rga_handle, ctx->gralloc);
if (ret) {
ALOGE("Failed to copy rga handle ret=%d", ret);
goto err;
}
}
#endif
}
map.layers.emplace_back(std::move(layer));
}
}
}
if(layers_map.size() == 0)
{
ALOGD("%s: layers_map size is 0",__FUNCTION__);
goto err;
}
ctx->drm.UpdateDisplayRoute();
ctx->drm.UpdatePropertys();
ctx->drm.ClearDisplay();
composition = ctx->drm.compositor()->CreateComposition(ctx->importer.get(), get_frame());
if (!composition) {
ALOGE("%s: Drm composition init failed",__FUNCTION__);
goto err;
}
ret = composition->SetLayers(layers_map.size(), layers_map.data());
if (ret) {
ALOGD("%s: SetLayers fail",__FUNCTION__);
goto err;
}
for (size_t i = 0; i < num_displays; ++i) {
if (!sf_display_contents[i] || i == HWC_DISPLAY_VIRTUAL)
continue;
DrmConnector *c = ctx->drm.GetConnectorFromType(i);
if (!c || c->state() != DRM_MODE_CONNECTED) {
continue;
}
hwc_drm_display_t *hd = &ctx->displays[c->display()];
composition->SetMode3D(i, hd->stereo_mode);
}
for (size_t i = 0; i < ctx->comp_plane_group.size(); ++i) {
if(ctx->comp_plane_group[i].composition_planes.size() > 0)
{
ret = composition->SetCompPlanes(ctx->comp_plane_group[i].display, ctx->comp_plane_group[i].composition_planes);
if (ret) {
ALOGE("%s: SetCompPlanes fail",__FUNCTION__);
goto err;
}
}
else
{
DrmHwcDisplayContents &display_contents = ctx->layer_contents[i];
if (sf_display_contents[i])
{
signal_all_fence(display_contents, sf_display_contents[i]);
ctx->drm.ClearDisplay(i);
}
}
}
/* rk:
* we use loop to call QueueComposition to avoid the release fence leak.
* Before:
* QueueComposition
* DrmComposition::Plan
* DrmDisplayComposition::Plan[0]---> return ok,it will create release fences for display 0
* DrmDisplayComposition::Plan[1]---> return err
* return err to DrmComposition::Plan,then return err to QueueComposition,
* it has no change to call DrmDisplayCompositor::QueueComposition(push composition in composite Queue.)
* So even you call ClearDisplay,the release fences of display 0 still cann't be signal.
* There are two workrounds:
* 1. You can call SignalCompositionDone or DrmDisplayComposition.reset(NULL) for display 0 before return to QueueComposition.
* Tip: DrmDisplayComposition.reset(NULL) will call SignalCompositionDone in ~DrmDisplayComposition.
* 2. Use loop to separate the success and the error processing.(<----current workround.)
*
*/
for (size_t i = 0; i < HWC_NUM_PHYSICAL_DISPLAY_TYPES; ++i) {
if (!sf_display_contents[i])
continue;
ret = ctx->drm.compositor()->QueueComposition(composition, i);
if (ret) {
ALOGE("%s: QueueComposition fail for display=%zu",__FUNCTION__,i);
DrmHwcDisplayContents &display_contents = ctx->layer_contents[i];
signal_all_fence(display_contents, sf_display_contents[i]);
ctx->drm.ClearDisplay(i);
}
}
for (size_t i = 0; i < num_displays; ++i) {
hwc_display_contents_1_t *dc = sf_display_contents[i];
bool bFindDisplay = false;
if (!dc || i == HWC_DISPLAY_VIRTUAL)
continue;
DrmConnector *c = ctx->drm.GetConnectorFromType(i);
if (!c || c->state() != DRM_MODE_CONNECTED) {
DrmHwcDisplayContents &display_contents = ctx->layer_contents[i];
signal_all_fence(display_contents, sf_display_contents[i]);
ctx->drm.ClearDisplay(i);
continue;
}
hwc_drm_display_t *hd = &ctx->displays[c->display()];
for (auto &fail_display : fail_displays) {
if( i == fail_display )
{
bFindDisplay = true;
ALOGD_IF(log_level(DBG_DEBUG),"%s:line=%d,Find fail display %zu",__FUNCTION__,__LINE__,i);
break;
}
}
if(bFindDisplay)
continue;
size_t num_dc_layers = dc->numHwLayers;
for (size_t j = 0; j < num_dc_layers; ++j) {
hwc_layer_1_t *layer = &dc->hwLayers[j];
if (layer->flags & HWC_SKIP_LAYER)
continue;
hwc_add_layer_to_retire_fence(layer, dc);
}
}
delete composition;
composition = NULL;
#if RK_INVALID_REFRESH
hwc_static_screen_opt_set(ctx->isGLESComp);
#endif
ALOGD_IF(log_level(DBG_VERBOSE),"----------------------------frame=%d end----------------------------",get_frame());
return ret;
err:
ALOGE("%s: not normal frame happen",__FUNCTION__);
for (size_t i = 0; i < num_displays; ++i) {
hwc_display_contents_1_t *dc = sf_display_contents[i];
if (!dc || i == HWC_DISPLAY_VIRTUAL)
continue;
int num_layers = dc->numHwLayers;
for (int j = 0; j < num_layers; j++) {
hwc_layer_1_t *layer = &dc->hwLayers[j];
dump_layer(ctx->gralloc, true, layer, j);
}
DrmHwcDisplayContents &display_contents = ctx->layer_contents[i];
signal_all_fence(display_contents, sf_display_contents[i]);
}
if(NULL != composition)
{
delete composition;
composition = NULL;
}
ctx->drm.ClearAllDisplay();
return -EINVAL;
}
static int hwc_event_control(struct hwc_composer_device_1 *dev, int display,
int event, int enabled) {
if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
return -EINVAL;
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
if (display == HWC_DISPLAY_PRIMARY)
return ctx->primary_vsync_worker.VSyncControl(enabled);
else if (display == HWC_DISPLAY_EXTERNAL)
return ctx->extend_vsync_worker.VSyncControl(enabled);
ALOGE("Can't support vsync control for display %d\n", display);
return -EINVAL;
}
static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
int mode) {
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
uint64_t dpmsValue = 0;
switch (mode) {
case HWC_POWER_MODE_OFF:
dpmsValue = DRM_MODE_DPMS_OFF;
break;
/* We can't support dozing right now, so go full on */
case HWC_POWER_MODE_DOZE:
case HWC_POWER_MODE_DOZE_SUSPEND:
case HWC_POWER_MODE_NORMAL:
dpmsValue = DRM_MODE_DPMS_ON;
break;
};
int fb_blank = 0;
if(dpmsValue == DRM_MODE_DPMS_OFF)
fb_blank = FB_BLANK_POWERDOWN;
else if(dpmsValue == DRM_MODE_DPMS_ON)
fb_blank = FB_BLANK_UNBLANK;
else
ALOGE("dpmsValue is invalid value= %" PRIu64 "",dpmsValue);
if(fb_blank != ctx->fb_blanked && ctx->fb_fd > 0){
int err = ioctl(ctx->fb_fd, FBIOBLANK, fb_blank);
ALOGD_IF(log_level(DBG_DEBUG),"%s Notice fb_blank to fb=%d", __FUNCTION__, fb_blank);
if (err < 0) {
if (errno == EBUSY)
ALOGD("fb_blank ioctl failed display=%d,fb_blank=%d,dpmsValue=%" PRIu64 "",
display,fb_blank,dpmsValue);
else
ALOGE("fb_blank ioctl failed(%s) display=%d,fb_blank=%d,dpmsValue=%" PRIu64 "",
strerror(errno),display,fb_blank,dpmsValue);
return -errno;
}
}
ctx->fb_blanked = fb_blank;
DrmConnector *connector = ctx->drm.GetConnectorFromType(display);
if (!connector) {
ALOGE("%s:Failed to get connector for display %d line=%d", __FUNCTION__,display,__LINE__);
return -ENODEV;
}
//In tv mode, we still need update the hdmi force_disconnect.
//Pg: sleep(force_disconnect will be true) ==> plug out HDMI(switch to tv mode) ==> wake up ==> plug in HDMI(force_disconnect still be true)
//Workround: ==> update HDMI's force_disconnect
if(connector->get_type() == DRM_MODE_CONNECTOR_TV)
{
for (auto &conn : ctx->drm.connectors())
{
if(conn->get_type() == DRM_MODE_CONNECTOR_HDMIA)
{
conn->force_disconnect(dpmsValue == DRM_MODE_DPMS_OFF);
break;
}
}
}
connector->force_disconnect(dpmsValue == DRM_MODE_DPMS_OFF);
//If process of device boot have two connector's status is connected,
//the first setPowerMode will to set drmMode-id for every connector
//in order to avoid some initialization problems.
for (int i = 0; i < HWC_NUM_PHYSICAL_DISPLAY_TYPES; i++) {
DrmConnector *conn = ctx->drm.GetConnectorFromType(i);
if (!conn || conn->state() != DRM_MODE_CONNECTED)
continue;
hwc_drm_display_t *hd = &ctx->displays[conn->display()];
update_display_bestmode(hd, i, conn);
DrmMode drmmode = conn->best_mode();
conn->set_current_mode(drmmode);
}
ctx->drm.DisplayChanged();
ctx->drm.UpdateDisplayRoute();
ctx->drm.ClearDisplay();
return 0;
}
static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
int *value) {
switch (what) {
case HWC_BACKGROUND_LAYER_SUPPORTED:
*value = 0; /* TODO: We should do this */
break;
case HWC_VSYNC_PERIOD:
ALOGW("Query for deprecated vsync value, returning 60Hz");
*value = 1000 * 1000 * 1000 / 60;
break;
case HWC_DISPLAY_TYPES_SUPPORTED:
*value = HWC_DISPLAY_PRIMARY_BIT | HWC_DISPLAY_EXTERNAL_BIT |
HWC_DISPLAY_VIRTUAL_BIT;
break;
}
return 0;
}
static void hwc_register_procs(struct hwc_composer_device_1 *dev,
hwc_procs_t const *procs) {
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
ctx->procs = procs;
ctx->primary_vsync_worker.SetProcs(procs);
ctx->extend_vsync_worker.SetProcs(procs);
ctx->hotplug_handler.Init(&ctx->displays, &ctx->drm, procs);
ctx->drm.event_listener()->RegisterHotplugHandler(&ctx->hotplug_handler);
}
static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
int display, uint32_t *configs,
size_t *num_configs) {
if (!num_configs)
return 0;
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
DrmConnector *connector = ctx->drm.GetConnectorFromType(display);
if (!connector) {
ALOGE("%s:Failed to get connector for display %d line=%d", __FUNCTION__,display,__LINE__);
return -ENODEV;
}
hwc_drm_display_t *hd = &ctx->displays[connector->display()];
if (!hd->active)
return -ENODEV;
int ret = connector->UpdateModes();
if (ret) {
ALOGE("Failed to update display modes %d", ret);
return ret;
}
if (connector->state() != DRM_MODE_CONNECTED && display == HWC_DISPLAY_EXTERNAL) {
ALOGE("connector is not connected with display %d", display);
return -ENODEV;
}
update_display_bestmode(hd, display, connector);
DrmMode mode = connector->best_mode();
connector->set_current_mode(mode);
char framebuffer_size[PROPERTY_VALUE_MAX];
uint32_t width = 0, height = 0 , vrefresh = 0 ;
if (display == HWC_DISPLAY_PRIMARY)
property_get("persist." PROPERTY_TYPE ".framebuffer.main", framebuffer_size, "use_baseparameter");
else if(display == HWC_DISPLAY_EXTERNAL)
property_get("persist." PROPERTY_TYPE ".framebuffer.aux", framebuffer_size, "use_baseparameter");
/*
* if unset framebuffer_size, get it from baseparameter , by libin
*/
if(hwc_have_baseparameter() && !strcmp(framebuffer_size,"use_baseparameter")){
int res = 0;
res = hwc_get_baseparameter_config(framebuffer_size,display,BP_FB_SIZE,0);
if(res)
ALOGW("BP: hwc get baseparameter config err ,res = %d",res);
}
sscanf(framebuffer_size, "%dx%d@%d", &width, &height, &vrefresh);
if (width && height) {
hd->framebuffer_width = width;
hd->framebuffer_height = height;
hd->vrefresh = vrefresh ? vrefresh : 60;
} else if (mode.h_display() && mode.v_display() && mode.v_refresh()) {
hd->framebuffer_width = mode.h_display();
hd->framebuffer_height = mode.v_display();
hd->vrefresh = mode.v_refresh();
/*
* Limit to 1080p if large than 2160p
*/
if (hd->framebuffer_height >= 2160 && hd->framebuffer_width >= hd->framebuffer_height) {
hd->framebuffer_width = hd->framebuffer_width * (1080.0 / hd->framebuffer_height);
hd->framebuffer_height = 1080;
}
} else {
hd->framebuffer_width = 1920;
hd->framebuffer_height = 1080;
hd->vrefresh = 60;
ALOGE("Failed to find available display mode for display %d\n", display);
}
hd->rel_xres = mode.h_display();
hd->rel_yres = mode.v_display();
hd->v_total = mode.v_total();
// AFBDC limit
bool disable_afbdc = false;
if(display == HWC_DISPLAY_PRIMARY){
#ifdef TARGET_BOARD_PLATFORM_RK3399
if(hd->framebuffer_width > 2560 || hd->framebuffer_width % 16 != 0 || hd->framebuffer_height % 8 != 0)
disable_afbdc = true;
#elif TARGET_BOARD_PLATFORM_RK3368
if(hd->framebuffer_width > 2048 || hd->framebuffer_width % 16 != 0 || hd->framebuffer_height % 4 != 0)
disable_afbdc = true;
#elif TARGET_BOARD_PLATFORM_RK3326
if(hd->framebuffer_width > 1920 || hd->framebuffer_width % 16 != 0 || hd->framebuffer_height % 8 != 0)
disable_afbdc = true;
#endif
if(disable_afbdc){
#ifdef USE_GRALLOC_4 // Android 11 use Gralloc 4.0
property_set("vendor.gralloc.no_afbc_for_fb_target_layer", "1");
#else
property_set( PROPERTY_TYPE ".gralloc.disable_afbc", "1");
#endif
ALOGI("%s:line=%d primary framebuffer size %dx%d not support AFBDC, to disable AFBDC\n",
__FUNCTION__, __LINE__, hd->framebuffer_width,hd->framebuffer_height);
}
}
*num_configs = 1;
configs[0] = connector->display();
return 0;
}
static float getDefaultDensity(uint32_t width, uint32_t height) {
// Default density is based on TVs: 1080p displays get XHIGH density,
// lower-resolution displays get TV density. Maybe eventually we'll need
// to update it for 4K displays, though hopefully those just report
// accurate DPI information to begin with. This is also used for virtual
// displays and even primary displays with older hwcomposers, so be
// careful about orientation.
uint32_t h = width < height ? width : height;
if (h >= 1080) return ACONFIGURATION_DENSITY_XHIGH;
else return ACONFIGURATION_DENSITY_TV;
}
static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
int display, uint32_t config,
const uint32_t *attributes,
int32_t *values) {
UN_USED(config);
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
DrmConnector *c = ctx->drm.GetConnectorFromType(display);
if (!c) {
ALOGE("Failed to get DrmConnector for display %d", display);
return -ENODEV;
}
hwc_drm_display_t *hd = &ctx->displays[c->display()];
if (!hd->active)
return -ENODEV;
uint32_t mm_width = c->mm_width();
uint32_t mm_height = c->mm_height();
int w = hd->framebuffer_width;
int h = hd->framebuffer_height;
int vrefresh = hd->vrefresh;
for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
switch (attributes[i]) {
case HWC_DISPLAY_VSYNC_PERIOD:
values[i] = 1000 * 1000 * 1000 / vrefresh;
break;
case HWC_DISPLAY_WIDTH:
values[i] = w;
break;
case HWC_DISPLAY_HEIGHT:
values[i] = h;
break;
case HWC_DISPLAY_DPI_X:
/* Dots per 1000 inches */
values[i] = mm_width ? (w * UM_PER_INCH) / mm_width : getDefaultDensity(w,h)*1000;
break;
case HWC_DISPLAY_DPI_Y:
/* Dots per 1000 inches */
values[i] =
mm_height ? (h * UM_PER_INCH) / mm_height : getDefaultDensity(w,h)*1000;
break;
}
}
return 0;
}
static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
int display) {
UN_USED(dev);
UN_USED(display);
return 0;
}
static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
int index) {
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
UN_USED(index);
DrmConnector *c = ctx->drm.GetConnectorFromType(display);
if (!c) {
ALOGE("%s:Failed to get connector for display %d line=%d", __FUNCTION__,display,__LINE__);
return -ENODEV;
}
if (c->state() != DRM_MODE_CONNECTED) {
/*
* fake primary display if primary is not connected.
*/
if (display == HWC_DISPLAY_PRIMARY)
return 0;
return -ENODEV;
}
hwc_drm_display_t *hd = &ctx->displays[c->display()];
DrmMode mode = c->best_mode();
if (!mode.id()) {
ALOGE("Could not find active mode for display=%d", display);
return -ENOENT;
}
hd->w_scale = (float)mode.h_display() / hd->framebuffer_width;
hd->h_scale = (float)mode.v_display() / hd->framebuffer_height;
c->set_current_mode(mode);
ctx->drm.UpdateDisplayRoute();
return 0;
}
static int hwc_device_close(struct hw_device_t *dev) {
struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
#if RK_CTS_WORKROUND
if(ctx->regFile)
{
fclose(ctx->regFile);
ctx->regFile = NULL;
}
#endif
#if RK_INVALID_REFRESH
free_thread_pamaters(&ctx->mRefresh);
#endif
#if 0
if(ctx->fd_3d >= 0)
{
close(ctx->fd_3d);
ctx->fd_3d = -1;
}
free_thread_pamaters(&ctx->mControlStereo);
#endif
delete ctx;
return 0;
}
/*
* TODO: This function sets the active config to the first one in the list. This
* should be fixed such that it selects the preferred mode for the display, or
* some other, saner, method of choosing the config.
*/
static int hwc_set_initial_config(struct hwc_context_t *ctx, int display) {
uint32_t config;
size_t num_configs = 1;
int ret = hwc_get_display_configs(&ctx->device, display, &config,
&num_configs);
if (ret || !num_configs)
return 0;
ret = hwc_set_active_config(&ctx->device, display, 0);
if (ret) {
ALOGE("Failed to set active config d=%d ret=%d", display, ret);
return ret;
}
return ret;
}
static int hwc_initialize_display(struct hwc_context_t *ctx, int display) {
hwc_drm_display_t *hd = &ctx->displays[display];
hd->ctx = ctx;
hd->gralloc = ctx->gralloc;
#if RK_VIDEO_UI_OPT
hd->iUiFd = -1;
hd->bHideUi = false;
#endif
hd->framebuffer_width = 0;
hd->framebuffer_height = 0;
hd->rel_xres = 0;
hd->rel_yres = 0;
hd->v_total = 0;
hd->w_scale = 1.0;
hd->h_scale = 1.0;
hd->active = true;
hd->last_hdmi_status = HDMI_ON;
hd->isHdr = false;
memset(&hd->last_hdr_metadata, 0, sizeof(hd->last_hdr_metadata));
hd->colorimetry = 0;
hd->hotplug_timeline = 0;
hd->display_timeline = 0;
hd->is_3d = false;
hd->hasEotfPlane = false;
hd->bPreferMixDown = false;
#if RK_RGA_PREPARE_ASYNC
hd->rgaBuffer_index = 0;
hd->mUseRga = false;
#endif
#if RK_ROTATE_VIDEO_MODE
hd->bRotateVideoMode = false;
#endif
return 0;
}
static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
int ret, num_connectors = 0;
for (auto &conn : ctx->drm.connectors()) {
ret = hwc_initialize_display(ctx, conn->display());
if (ret) {
ALOGE("Failed to initialize display %d", conn->display());
return ret;
}
num_connectors++;
}
#if 0
ret = hwc_set_initial_config(ctx, HWC_DISPLAY_PRIMARY);
if (ret) {
ALOGE("Failed to set initial config for primary display ret=%d", ret);
return ret;
}
ret = hwc_set_initial_config(ctx, HWC_DISPLAY_EXTERNAL);
if (ret) {
ALOGE("Failed to set initial config for extend display ret=%d", ret);
// return ret;
}
#endif
ret = ctx->primary_vsync_worker.Init(&ctx->drm, HWC_DISPLAY_PRIMARY);
if (ret) {
ALOGE("Failed to create event worker for primary display %d\n", ret);
return ret;
}
if (num_connectors > 1) {
ret = ctx->extend_vsync_worker.Init(&ctx->drm, HWC_DISPLAY_EXTERNAL);
if (ret) {
ALOGE("Failed to create event worker for extend display %d\n", ret);
return ret;
}
}
ret = ctx->virtual_compositor_worker.Init();
if (ret) {
ALOGE("Failed to initialize virtual compositor worker");
return ret;
}
return 0;
}
#if RK_INVALID_REFRESH
static void hwc_static_screen_opt_handler(int sig)
{
hwc_context_t* ctx = g_ctx;
if (sig == SIGALRM) {
ctx->mOneWinOpt = true;
pthread_mutex_lock(&ctx->mRefresh.mlk);
ctx->mRefresh.count = 100;
ALOGD_IF(log_level(DBG_VERBOSE),"hwc_static_screen_opt_handler:mRefresh.count=%d",ctx->mRefresh.count);
pthread_mutex_unlock(&ctx->mRefresh.mlk);
pthread_cond_signal(&ctx->mRefresh.cond);
}
return;
}
void *invalidate_refresh(void *arg)
{
hwc_context_t* ctx = (hwc_context_t*)arg;
int count = 0;
int nMaxCnt = 25;
unsigned int nSleepTime = 200;
pthread_cond_wait(&ctx->mRefresh.cond,&ctx->mRefresh.mtx);
while(true) {
for(count = 0; count < nMaxCnt; count++) {
usleep(nSleepTime*1000);
pthread_mutex_lock(&ctx->mRefresh.mlk);
count = ctx->mRefresh.count;
ctx->mRefresh.count ++;
ALOGD_IF(log_level(DBG_VERBOSE),"invalidate_refresh mRefresh.count=%d",ctx->mRefresh.count);
pthread_mutex_unlock(&ctx->mRefresh.mlk);
ctx->procs->invalidate(ctx->procs);
}
pthread_cond_wait(&ctx->mRefresh.cond,&ctx->mRefresh.mtx);
count = 0;
}
pthread_exit(NULL);
return NULL;
}
#endif
#if 0
void* hwc_control_3dmode_thread(void *arg)
{
hwc_context_t* ctx = (hwc_context_t*)arg;
int ret = -1;
int needStereo = 0;
ALOGD("hwc_control_3dmode_thread creat");
pthread_cond_wait(&ctx->mControlStereo.cond,&ctx->mControlStereo.mtx);
while(true) {
pthread_mutex_lock(&ctx->mControlStereo.mlk);
needStereo = ctx->mControlStereo.count;
pthread_mutex_unlock(&ctx->mControlStereo.mlk);
ret = hwc_control_3dmode(ctx->fb_3d, 2, READ_3D_MODE);
if(needStereo != ret) {
hwc_control_3dmode(ctx, needStereo,WRITE_3D_MODE);
ALOGI_IF(log_level(DBG_VERBOSE),"change stereo mode %d to %d",ret,needStereo);
}
ALOGD_IF(log_level(DBG_VERBOSE),"mControlStereo.count=%d",needStereo);
pthread_cond_wait(&ctx->mControlStereo.cond,&ctx->mControlStereo.mtx);
}
ALOGD("hwc_control_3dmode_thread exit");
pthread_exit(NULL);
return NULL;
}
#endif
static int hwc_device_open(const struct hw_module_t *module, const char *name,
struct hw_device_t **dev) {
if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
ALOGE("Invalid module name- %s", name);
return -EINVAL;
}
init_rk_debug();
hwc_get_baseparameter_config(NULL,0,BP_UPDATE,0);
std::unique_ptr<hwc_context_t> ctx(new hwc_context_t());
if (!ctx) {
ALOGE("Failed to allocate hwc context");
return -ENOMEM;
}
int ret = ctx->drm.Init();
if (ret) {
ALOGE("Can't initialize Drm object %d", ret);
return ret;
}
#if USE_GRALLOC_4
ctx->gralloc = NULL;
#else // USE_GRALLOC_4
ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
(const hw_module_t **)&ctx->gralloc);
if (ret) {
ALOGE("Failed to open gralloc module %d", ret);
return ret;
}
#endif // USE_GRALLOC_4
ctx->drm.setGralloc(ctx->gralloc);
ret = ctx->dummy_timeline.Init();
if (ret) {
ALOGE("Failed to create dummy sw sync timeline %d", ret);
return ret;
}
ctx->importer.reset(Importer::CreateInstance(&ctx->drm));
if (!ctx->importer) {
ALOGE("Failed to create importer instance");
return ret;
}
ret = hwc_enumerate_displays(ctx.get());
if (ret) {
ALOGE("Failed to enumerate displays: %s", strerror(ret));
return ret;
}
ctx->device.common.tag = HARDWARE_DEVICE_TAG;
ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
ctx->device.common.module = const_cast<hw_module_t *>(module);
ctx->device.common.close = hwc_device_close;
ctx->device.dump = hwc_dump;
ctx->device.prepare = hwc_prepare;
ctx->device.set = hwc_set;
ctx->device.eventControl = hwc_event_control;
ctx->device.setPowerMode = hwc_set_power_mode;
ctx->device.query = hwc_query;
ctx->device.registerProcs = hwc_register_procs;
ctx->device.getDisplayConfigs = hwc_get_display_configs;
ctx->device.getDisplayAttributes = hwc_get_display_attributes;
ctx->device.getActiveConfig = hwc_get_active_config;
ctx->device.setActiveConfig = hwc_set_active_config;
ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
g_ctx = ctx.get();
ctx->fb_fd = open("/dev/graphics/fb0", O_RDWR, 0);
if(ctx->fb_fd < 0)
{
ALOGE("Open fb0 fail in %s",__FUNCTION__);
}
ctx->hdmi_status_fd = open(HDMI_STATUS_PATH, O_RDWR, 0);
if(ctx->hdmi_status_fd < 0)
{
ALOGE("Open hdmi_status_fd fail in %s",__FUNCTION__);
//return -1;
}
ctx->dp_status_fd = open(DP_STATUS_PATH, O_RDWR, 0);
if(ctx->hdmi_status_fd < 0)
{
ALOGE("Open hdmi_status_fd fail in %s",__FUNCTION__);
//return -1;
}
#if RK_CTS_WORKROUND
ctx->regFile = fopen(VIEW_CTS_FILE, "r");
if(ctx->regFile == NULL)
{
ALOGE("%s open fail errno=0x%x (%s)",__FUNCTION__, errno,strerror(errno));
}
#endif
hwc_init_version();
ctx->hdr_video_compose_by_gles = hwc_get_bool_property( PROPERTY_TYPE ".hwc.hdr_video_by_gles","false");
ALOGI("HWC property : hdr_video_by_gles = %s",ctx->hdr_video_compose_by_gles ? "True" : "False");
#if RK_INVALID_REFRESH
ctx->mOneWinOpt = false;
ctx->isGLESComp = false;
init_thread_pamaters(&ctx->mRefresh);
pthread_t invalidate_refresh_th;
if (pthread_create(&invalidate_refresh_th, NULL, invalidate_refresh, ctx.get()))
{
ALOGE("Create invalidate_refresh_th thread error .");
}
signal(SIGALRM, hwc_static_screen_opt_handler);
#endif
#if 0
init_thread_pamaters(&ctx->mControlStereo);
ctx->fd_3d = open("/sys/class/display/HDMI/3dmode", O_RDWR, 0);
if(ctx->fd_3d < 0){
ALOGE("open /sys/class/display/HDMI/3dmode fail");
}
pthread_t thread_3d;
if (pthread_create(&thread_3d, NULL, hwc_control_3dmode_thread, ctx.get()))
{
ALOGE("Create hwc_control_3dmode_thread thread error .");
}
#endif
*dev = &ctx->device.common;
ctx.release();
return 0;
}
}
static struct hw_module_methods_t hwc_module_methods = {
.open = android::hwc_device_open
};
hwc_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = HWC_HARDWARE_MODULE_ID,
.name = "DRM hwcomposer module",
.author = "The Android Open Source Project",
.methods = &hwc_module_methods,
.dso = NULL,
.reserved = {0},
}
};