From f41040590ef08171eed00c48182985dd9b8b6510 Mon Sep 17 00:00:00 2001 From: Wan Shuang Date: Mon, 21 Jan 2019 19:52:55 +0800 Subject: [PATCH] Added the support of panorama view mode in AaaG HWC. This feature support combining 1 physical display and 1 SOS display like one wide resolution display to AOSP framework. HWC be responsible to feed the part of screen into physical display and SOS accordingly. Change-Id: I25bd1b6cf78d8d6b8e6f6c4e73454640e758a3cb Tracked-On: https://jira.devtools.intel.com/browse/OAM-70254 Tests: AaaG be able to split screen and sharing part of it with SOS. Signed-off-by: Wan Shuang --- Android.common.mk | 4 + common/Android.mk | 5 + common/core/gpudevice.cpp | 180 ++++++++++- common/core/mosaicdisplay.cpp | 24 ++ common/core/mosaicdisplay.h | 10 + common/display/hyperdmadisplay.h | 61 ++++ common/display/virtualdisplay.h | 37 +-- common/display/virtualpanoramadisplay.cpp | 513 ++++++++++++++++++++++++++++++ common/display/virtualpanoramadisplay.h | 131 ++++++++ hwc_display_virt.ini | 7 + public/gpudevice.h | 14 + public/hwclayer.h | 4 + wsi/Android.mk | 4 + wsi/displaymanager.h | 5 + wsi/drm/drmdisplaymanager.cpp | 17 + wsi/drm/drmdisplaymanager.h | 7 + 16 files changed, 984 insertions(+), 39 deletions(-) create mode 100644 common/display/hyperdmadisplay.h create mode 100644 common/display/virtualpanoramadisplay.cpp create mode 100644 common/display/virtualpanoramadisplay.h diff --git a/Android.common.mk b/Android.common.mk index f51499d..6576fa9 100644 --- a/Android.common.mk +++ b/Android.common.mk @@ -47,6 +47,10 @@ $(info "ANDROID_VERSION $(ANDROID_VERSION)") LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) +ifeq ($(strip $(ENABLE_HYPER_DMABUF_SHARING)), true) +LOCAL_CPPFLAGS += -DENABLE_PANORAMA +endif + LOCAL_SHARED_LIBRARIES := \ libcutils \ libdrm \ diff --git a/common/Android.mk b/common/Android.mk index 8bdf2b4..0925c43 100644 --- a/common/Android.mk +++ b/common/Android.mk @@ -86,6 +86,11 @@ LOCAL_SRC_FILES := \ utils/hwcutils.cpp \ utils/disjoint_layers.cpp +ifeq ($(strip $(ENABLE_HYPER_DMABUF_SHARING)), true) +LOCAL_CPPFLAGS += -DENABLE_PANORAMA +LOCAL_SRC_FILES += display/virtualpanoramadisplay.cpp +endif + ifneq ($(strip $(HWC_DISABLE_VA_DRIVER)), true) LOCAL_SHARED_LIBRARIES += \ libva \ diff --git a/common/core/gpudevice.cpp b/common/core/gpudevice.cpp index 4188660..7aa501e 100644 --- a/common/core/gpudevice.cpp +++ b/common/core/gpudevice.cpp @@ -172,6 +172,137 @@ void GpuDevice::ParsePlaneReserveSettings(std::string &value) { } } +#ifdef ENABLE_PANORAMA +void GpuDevice::ParsePanoramaDisplayConfig( + std::string &value, std::vector> &panorama_displays) { + std::istringstream i_value(value); + std::string i_panorama_split_str; + std::vector panorama_duplicate_check; + // Got panorama sub display num + std::vector panorama_display; + while (std::getline(i_value, i_panorama_split_str, '+')) { + if (i_panorama_split_str.empty() || + i_panorama_split_str.find_first_not_of("0123456789") != + std::string::npos) + continue; + size_t i_panorama_split_num = atoi(i_panorama_split_str.c_str()); + // Check and skip if the display already been used in other panorama + bool skip_duplicate_display = false; + size_t panorama_size = panorama_duplicate_check.size(); + for (size_t i = 0; i < panorama_size; i++) { + if (panorama_duplicate_check.at(i) == i_panorama_split_num) { + skip_duplicate_display = true; + break; + } + } + if (!skip_duplicate_display) { + // save the sub display num for the panorama display (don't care if + // the physical/logical display is existing/connected here) + panorama_display.emplace_back(i_panorama_split_num); + panorama_duplicate_check.emplace_back(i_panorama_split_num); + } + } + panorama_displays.emplace_back(panorama_display); +} + +void GpuDevice::ParsePanoramaSOSDisplayConfig( + std::string &value, + std::vector> &panorama_sos_displays) { + std::istringstream i_value(value); + std::string i_panorama_sos_split_str; + + std::vector panorama_sos_duplicate_check; + // Got panorama sub display num + std::vector panorama_sos_display; + while (std::getline(i_value, i_panorama_sos_split_str, '+')) { + if (i_panorama_sos_split_str.empty() || + i_panorama_sos_split_str.find_first_not_of("0123456789") != + std::string::npos) + continue; + size_t i_panorama_sos_split_num = atoi(i_panorama_sos_split_str.c_str()); + // Check and skip if the display already been used in other panorama + bool skip_duplicate_display = false; + size_t panorama_sos_size = panorama_sos_duplicate_check.size(); + for (size_t i = 0; i < panorama_sos_size; i++) { + if (panorama_sos_duplicate_check.at(i) == i_panorama_sos_split_num) { + skip_duplicate_display = true; + break; + } + } + if (!skip_duplicate_display) { + // save the sub display num for the panorama display (don't care if + // the physical/logical display is existing/connected here) + panorama_sos_display.emplace_back(i_panorama_sos_split_num); + panorama_sos_duplicate_check.emplace_back(i_panorama_sos_split_num); + } + } + panorama_sos_displays.emplace_back(panorama_sos_display); +} + +void GpuDevice::PanoramaInit( + std::vector &total_displays_, + std::vector &temp_displays, + std::vector> &panorama_displays, + std::vector> &panorama_sos_displays, + std::vector &available_displays) { + std::vector i_available_panorama_displays; + temp_displays.swap(total_displays_); + // Add the virtual panorama displays mapping the SOS virtual displays. + size_t sos_displays_size = panorama_sos_displays.size(); + for (size_t sos_it = 0; sos_it < sos_displays_size; sos_it++) { + NativeDisplay *virtualdisp = display_manager_->CreateVirtualPanoramaDisplay( + panorama_sos_displays.at(0).at(sos_it)); + virtualdisp->InitVirtualDisplay(1920, 1080); + i_available_panorama_displays.emplace_back(virtualdisp); + } + + // Add the native displays + size_t displays_size = temp_displays.size(); + for (size_t t = 0; t < displays_size; t++) { + // Skip the displays which already be marked in other panorama + if (!available_displays.at(t)) { + ETRACE("display: %u is not present in the vector of avaialble_displays"); + continue; + } + bool skip_display = false; + size_t panorama_size = panorama_displays.size(); + for (size_t m = 0; m < panorama_size; m++) { + size_t panorama_inner_size = panorama_displays.at(m).size(); + for (size_t l = 0; l < panorama_inner_size; l++) { + // Check if the logical display is in panorama, keep the order of + // logical displays list + // Get the smallest logical num of the panorama for order keeping + if (t == panorama_displays.at(m).at(l)) { + if (panorama_displays.at(m).at(l) < displays_size) { + // Skip the disconnected display here + i_available_panorama_displays.emplace_back( + temp_displays.at(panorama_displays.at(m).at(l))); + // Add tag for panorama-ed displays + available_displays.at(panorama_displays.at(m).at(l)) = false; + } + skip_display = true; + break; + } + } + if (skip_display) + break; + } + } + // Create panorama for those logical displays + if (i_available_panorama_displays.size() > 0) { + std::unique_ptr panorama( + new MosaicDisplay(i_available_panorama_displays)); + panorama->SetPanoramaMode(true); + panorama->SetExtraDispInfo((int)panorama_displays.size(), + (int)panorama_sos_displays.size()); + panorama_displays_.emplace_back(std::move(panorama)); + // Save the panorama to the final displays list + total_displays_.emplace_back(panorama_displays_.back().get()); + } +} + +#endif + void GpuDevice::HandleHWCSettings() { // Handle config file reading const char *hwc_dp_cfg_path = HWC_DISPLAY_INI_PATH; @@ -189,6 +320,12 @@ void GpuDevice::HandleHWCSettings() { std::vector> float_displays; std::vector> cloned_displays; std::vector> mosaic_displays; +#ifdef ENABLE_PANORAMA + bool use_panorama = false; + std::vector> panorama_displays; + std::vector> panorama_sos_displays; +#endif + std::ifstream fin(hwc_dp_cfg_path); std::string cfg_line; std::string key_logical("LOGICAL"); @@ -203,6 +340,11 @@ void GpuDevice::HandleHWCSettings() { std::string key_physical_display_rotation("PHYSICAL_DISPLAY_ROTATION"); std::string key_clone_display("CLONE_DISPLAY"); std::string key_float_display("FLOAT_DISPLAY"); +#ifdef ENABLE_PANORAMA + std::string key_panorama("PANORAMA"); + std::string key_panorama_display("PANORAMA_DISPLAY"); + std::string key_panorama_sos_display("PANORAMA_SOS_DISPLAY"); +#endif std::string key_reserved_drm_plane("DRM_PLANE_RESERVED"); @@ -234,6 +376,13 @@ void GpuDevice::HandleHWCSettings() { if (!value.compare(enable_str)) { use_mosaic = true; } +#ifdef ENABLE_PANORAMA + // Got panorama switch + } else if (!key.compare(key_panorama)) { + if (!value.compare(enable_str)) { + use_panorama = true; + } +#endif // Got clone switch } else if (!key.compare(key_clone)) { if (!value.compare(enable_str)) { @@ -310,6 +459,16 @@ void GpuDevice::HandleHWCSettings() { } } mosaic_displays.emplace_back(mosaic_display); +#ifdef ENABLE_PANORAMA + // Got panorama config + } else if (!key.compare(key_panorama_display)) { + ParsePanoramaDisplayConfig(value, panorama_displays); + size_t panorama_displays_size = panorama_displays.size(); + // Got panorama sos config + } else if (!key.compare(key_panorama_sos_display)) { + ParsePanoramaSOSDisplayConfig(value, panorama_sos_displays); + size_t panorama_sos_displays_size = panorama_sos_displays.size(); +#endif } else if (!key.compare(key_physical_display)) { std::istringstream i_value(value); std::string physical_split_str; @@ -598,7 +757,18 @@ void GpuDevice::HandleHWCSettings() { total_displays_.swap(temp_displays); } +#ifdef ENABLE_PANORAMA + if (use_panorama && !use_mosaic && !use_cloned && !use_float) { + PanoramaInit(total_displays_, temp_displays, panorama_displays, + panorama_sos_displays, available_displays); + } +#endif + +#ifdef ENABLE_PANORAMA + if (use_cloned && !use_mosaic && !use_logical && !use_panorama) { +#else if (use_cloned && !use_mosaic && !use_logical) { +#endif std::vector temp_displays; size_t displays_size = total_displays_.size(); size_t cloned_displays_size = cloned_displays.size(); @@ -641,10 +811,14 @@ void GpuDevice::HandleHWCSettings() { temp_displays.swap(total_displays_); } - // Now set floating display configuration - // Get the floating display index and the respective rectangle - // TODO Logical display on & mosaic display on scenario +// Now set floating display configuration +// Get the floating display index and the respective rectangle +// TODO Logical display on & mosaic display on scenario +#ifdef ENABLE_PANORAMA + if (use_float && !use_logical && !use_mosaic && !use_panorama) { +#else if (use_float && !use_logical && !use_mosaic) { +#endif bool ret = false; size_t size = float_display_indices.size(); size_t num_displays = total_displays_.size(); diff --git a/common/core/mosaicdisplay.cpp b/common/core/mosaicdisplay.cpp index f32794a..8ade9a9 100644 --- a/common/core/mosaicdisplay.cpp +++ b/common/core/mosaicdisplay.cpp @@ -349,7 +349,19 @@ void MosaicDisplay::HotPlugUpdate(bool connected) { } vsync_counter_ = total_connected_displays; + +#ifdef ENABLE_PANORAMA + if (panorama_mode_) { + vsync_divisor_ = num_physical_displays_; + if (vsync_divisor_ < 1) { + vsync_divisor_ = 1; + } + } else { + vsync_divisor_ = vsync_counter_; + } +#else vsync_divisor_ = vsync_counter_; +#endif if (connected_ == connected) { lock_.unlock(); @@ -528,4 +540,16 @@ bool MosaicDisplay::ContainConnector(const uint32_t connector_id) { return false; } +#ifdef ENABLE_PANORAMA +void MosaicDisplay::SetPanoramaMode(bool mode) { + panorama_mode_ = mode; +} + +void MosaicDisplay::SetExtraDispInfo(int num_physical_displays, + int num_virtual_displays) { + num_physical_displays_ = num_physical_displays; + num_virtual_displays_ = num_virtual_displays; +} +#endif + } // namespace hwcomposer diff --git a/common/core/mosaicdisplay.h b/common/core/mosaicdisplay.h index b1c4716..c078b8e 100644 --- a/common/core/mosaicdisplay.h +++ b/common/core/mosaicdisplay.h @@ -115,6 +115,11 @@ class MosaicDisplay : public NativeDisplay { bool ContainConnector(const uint32_t connector_id) override; +#ifdef ENABLE_PANORAMA + void SetPanoramaMode(bool mode); + void SetExtraDispInfo(int num_physical_displays, int num_virtual_displays); +#endif + private: std::vector physical_displays_; std::vector connected_displays_; @@ -136,6 +141,11 @@ class MosaicDisplay : public NativeDisplay { bool connected_ = false; bool pending_vsync_ = false; bool update_connected_displays_ = true; +#ifdef ENABLE_PANORAMA + bool panorama_mode_ = false; + int32_t num_physical_displays_ = 1; + int32_t num_virtual_displays_ = 1; +#endif SpinLock lock_; }; diff --git a/common/display/hyperdmadisplay.h b/common/display/hyperdmadisplay.h new file mode 100644 index 0000000..607e49d --- /dev/null +++ b/common/display/hyperdmadisplay.h @@ -0,0 +1,61 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// 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. +*/ + +#ifndef COMMON_DISPLAY_HYPERDMABUF_H_ +#define COMMON_DISPLAY_HYPERDMABUF_H_ + +#include +#include + +#include +#include +#include "drmbuffer.h" +#include "hwctrace.h" +#define SURFACE_NAME_LENGTH 64 +#define HYPER_DMABUF_PATH "/dev/hyper_dmabuf" + +namespace hwcomposer { + +struct vm_header { + int32_t version; + int32_t output; + int32_t counter; + int32_t n_buffers; + int32_t disp_w; + int32_t disp_h; +}; + +struct vm_buffer_info { + int32_t surf_index; + int32_t width, height; + int32_t format; + int32_t pitch[3]; + int32_t offset[3]; + int32_t tile_format; + int32_t rotation; + int32_t status; + int32_t counter; + union { + hyper_dmabuf_id_t hyper_dmabuf_id; + unsigned long ggtt_offset; + }; + char surface_name[SURFACE_NAME_LENGTH]; + uint64_t surface_id; + int32_t bbox[4]; +}; + +} // namespace hwcomposer +#endif // COMMON_DISPLAY_HYPERDMABUF_H_ diff --git a/common/display/virtualdisplay.h b/common/display/virtualdisplay.h index b40bdf3..75e3692 100644 --- a/common/display/virtualdisplay.h +++ b/common/display/virtualdisplay.h @@ -25,12 +25,7 @@ #include "compositor.h" #include "resourcemanager.h" #ifdef HYPER_DMABUF_SHARING -#include -#include -#include "drmbuffer.h" -#include "hwctrace.h" -#define SURFACE_NAME_LENGTH 64 -#define HYPER_DMABUF_PATH "/dev/hyper_dmabuf" +#include "hyperdmadisplay.h" #endif namespace hwcomposer { @@ -38,36 +33,6 @@ struct HwcLayer; class FrameBufferManager; class NativeBufferHandler; -#ifdef HYPER_DMABUF_SHARING -struct vm_header { - int32_t version; - int32_t output; - int32_t counter; - int32_t n_buffers; - int32_t disp_w; - int32_t disp_h; -}; - -struct vm_buffer_info { - int32_t surf_index; - int32_t width, height; - int32_t format; - int32_t pitch[3]; - int32_t offset[3]; - int32_t tile_format; - int32_t rotation; - int32_t status; - int32_t counter; - union { - hyper_dmabuf_id_t hyper_dmabuf_id; - unsigned long ggtt_offset; - }; - char surface_name[SURFACE_NAME_LENGTH]; - uint64_t surface_id; - int32_t bbox[4]; -}; -#endif - class VirtualDisplay : public NativeDisplay { public: VirtualDisplay(uint32_t gpu_fd, NativeBufferHandler *buffer_handler, diff --git a/common/display/virtualpanoramadisplay.cpp b/common/display/virtualpanoramadisplay.cpp new file mode 100644 index 0000000..4762a48 --- /dev/null +++ b/common/display/virtualpanoramadisplay.cpp @@ -0,0 +1,513 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// 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. +*/ + +#include "virtualpanoramadisplay.h" + +#include + +#include +#include + +#include +#include + +#include "hwctrace.h" +#include "overlaylayer.h" + +#include "hwcutils.h" + +namespace hwcomposer { + +VirtualPanoramaDisplay::VirtualPanoramaDisplay( + uint32_t gpu_fd, NativeBufferHandler *buffer_handler, + FrameBufferManager *frame_buffer_manager, uint32_t pipe_id, + uint32_t /*crtc_id*/) + : output_handle_(0), + acquire_fence_(-1), + width_(0), + height_(0), + display_index_(pipe_id) { + resource_manager_.reset(new ResourceManager(buffer_handler)); + if (!resource_manager_) { + ETRACE("Failed to construct hwc layer buffer manager"); + } + fb_manager_ = frame_buffer_manager; + compositor_.Init(resource_manager_.get(), gpu_fd, fb_manager_); +} + +void VirtualPanoramaDisplay::InitHyperDmaBuf() { + if (hyper_dmabuf_initialized) + return; +#ifdef HYPER_DMABUF_SHARING + int ret; + struct ioctl_hyper_dmabuf_tx_ch_setup msg; + memset(&msg, 0, sizeof(ioctl_hyper_dmabuf_tx_ch_setup)); + + mHyperDmaBuf_Fd = open(HYPER_DMABUF_PATH, O_RDWR); + + if (mHyperDmaBuf_Fd < 0) + ETRACE("Hyper DmaBuf: open hyper dmabuf device node %s failed because %s", + HYPER_DMABUF_PATH, strerror(errno)); + else { + ITRACE("Hyper DmaBuf: open hyper dmabuf device node %s successfully!", + HYPER_DMABUF_PATH); + + /* TODO: add config option to specify which domains should be used, for + * now we share always with dom0 */ + msg.remote_domain = 0; + ret = ioctl(mHyperDmaBuf_Fd, IOCTL_HYPER_DMABUF_TX_CH_SETUP, &msg); + if (ret) { + ETRACE( + "Hyper DmaBuf:" + "IOCTL_HYPER_DMABUF_TX_CH_SETUP failed with error %d\n", + ret); + close(mHyperDmaBuf_Fd); + mHyperDmaBuf_Fd = -1; + } else + ITRACE("Hyper DmaBuf: IOCTL_HYPER_DMABUF_TX_CH_SETUP Done!\n"); + } +#endif + hyper_dmabuf_initialized = true; +} + +VirtualPanoramaDisplay::~VirtualPanoramaDisplay() { + if (acquire_fence_ > 0) { + close(acquire_fence_); + } + + if (handle_) { + ResourceHandle temp; + temp.handle_ = handle_; + resource_manager_->MarkResourceForDeletion(temp, false); + } + + delete output_handle_; + std::vector().swap(in_flight_layers_); + + resource_manager_->PurgeBuffer(); + compositor_.Reset(); +#ifdef HYPER_DMABUF_SHARING + if (mHyperDmaBuf_Fd > 0) { + auto it = mHyperDmaExportedBuffers.begin(); + for (; it != mHyperDmaExportedBuffers.end(); ++it) { + struct ioctl_hyper_dmabuf_unexport msg; + int ret; + msg.hid = it->second.hyper_dmabuf_id; + // Todo: find a reduced dmabuf free delay time + msg.delay_ms = 1000; + ret = ioctl(mHyperDmaBuf_Fd, IOCTL_HYPER_DMABUF_UNEXPORT, &msg); + if (ret) { + ETRACE( + "Hyper DmaBuf:" + "IOCTL_HYPER_DMABUF_UNEXPORT ioctl failed %d [0x%x]\n", + ret, it->second.hyper_dmabuf_id.id); + } else { + ITRACE("Hyper DmaBuf: IOCTL_HYPER_DMABUF_UNEXPORT ioctl Done [0x%x]!\n", + it->second.hyper_dmabuf_id.id); + mHyperDmaExportedBuffers.erase(it); + } + } + + close(mHyperDmaBuf_Fd); + mHyperDmaBuf_Fd = -1; + } +#endif +} + +void VirtualPanoramaDisplay::InitVirtualDisplay(uint32_t width, + uint32_t height) { + width_ = width; + height_ = height; + CreateOutBuffer(); +} + +bool VirtualPanoramaDisplay::GetActiveConfig(uint32_t *config) { + if (!config) + return false; + + config[0] = 1; + return true; +} + +bool VirtualPanoramaDisplay::SetActiveConfig(uint32_t /*config*/) { + return true; +} + +void VirtualPanoramaDisplay::HyperDmaExport() { +#ifdef HYPER_DMABUF_SHARING + int ret = 0; + size_t buffer_number = 0; + uint32_t surf_index = display_index_; + size_t info_size = sizeof(vm_buffer_info); + size_t header_size = sizeof(vm_header); + vm_header header; + vm_buffer_info info; + memset(&header, 0, header_size); + memset(&info, 0, info_size); + struct ioctl_hyper_dmabuf_export_remote msg; + char meta_data[header_size + info_size]; + uint32_t imported_fd = 0; + + header.n_buffers = 1; + header.version = 3; + header.output = display_index_; + header.counter = frame_count_++; + header.disp_w = width_; + header.disp_h = height_; + + std::shared_ptr buffer(NULL); + uint32_t gpu_fd = resource_manager_->GetNativeBufferHandler()->GetFd(); + uint32_t id = GetNativeBuffer(gpu_fd, output_handle_); + buffer = resource_manager_->FindCachedBuffer(id); + const uint32_t *pitches; + const uint32_t *offsets; + + if (buffer == NULL) { + buffer = OverlayBuffer::CreateOverlayBuffer(); + buffer->InitializeFromNativeHandle(output_handle_, resource_manager_.get(), + fb_manager_); + resource_manager_->RegisterBuffer(id, buffer); + imported_fd = buffer->GetPrimeFD(); + if (mHyperDmaBuf_Fd > 0 && imported_fd > 0) { + mHyperDmaExportedBuffers[imported_fd].width = buffer->GetWidth(); + mHyperDmaExportedBuffers[imported_fd].height = buffer->GetHeight(); + mHyperDmaExportedBuffers[imported_fd].format = buffer->GetFormat(); + pitches = buffer->GetPitches(); + offsets = buffer->GetOffsets(); + mHyperDmaExportedBuffers[imported_fd].pitch[0] = pitches[0]; + mHyperDmaExportedBuffers[imported_fd].pitch[1] = pitches[1]; + mHyperDmaExportedBuffers[imported_fd].pitch[2] = pitches[2]; + mHyperDmaExportedBuffers[imported_fd].offset[0] = offsets[0]; + mHyperDmaExportedBuffers[imported_fd].offset[1] = offsets[1]; + mHyperDmaExportedBuffers[imported_fd].offset[2] = offsets[2]; + mHyperDmaExportedBuffers[imported_fd].tile_format = + buffer->GetTilingMode(); + mHyperDmaExportedBuffers[imported_fd].rotation = 0; + mHyperDmaExportedBuffers[imported_fd].status = 0; + mHyperDmaExportedBuffers[imported_fd].counter = 0; + mHyperDmaExportedBuffers[imported_fd].surface_id = display_index_; + mHyperDmaExportedBuffers[imported_fd].bbox[0] = 0; + mHyperDmaExportedBuffers[imported_fd].bbox[1] = 0; + mHyperDmaExportedBuffers[imported_fd].bbox[2] = buffer->GetWidth(); + mHyperDmaExportedBuffers[imported_fd].bbox[3] = buffer->GetHeight(); + } + } + + msg.sz_priv = header_size + info_size; + msg.priv = meta_data; + + /* TODO: add more flexibility here, instead of hardcoded domain 0*/ + msg.remote_domain = 0; + msg.dmabuf_fd = buffer->GetPrimeFD(); + + char index[15]; + mHyperDmaExportedBuffers[buffer->GetPrimeFD()].surf_index = surf_index; + memset(index, 0, sizeof(index)); + sprintf(index, "Cluster_%d", surf_index); + strncpy(mHyperDmaExportedBuffers[buffer->GetPrimeFD()].surface_name, index, + SURFACE_NAME_LENGTH); + mHyperDmaExportedBuffers[buffer->GetPrimeFD()].hyper_dmabuf_id = + (hyper_dmabuf_id_t){-1, {-1, -1, -1}}; + memcpy(meta_data, &header, header_size); + memcpy(meta_data + header_size, + &mHyperDmaExportedBuffers[buffer->GetPrimeFD()], info_size); + + ret = ioctl(mHyperDmaBuf_Fd, IOCTL_HYPER_DMABUF_EXPORT_REMOTE, &msg); + if (ret) { + ETRACE("Hyper DmaBuf: Exporting hyper_dmabuf failed with error %d\n", ret); + return; + } + + resource_manager_->PreparePurgedResources(); + + std::vector purged_gl_resources; + std::vector purged_media_resources; + bool has_gpu_resource = false; + + resource_manager_->GetPurgedResources( + purged_gl_resources, purged_media_resources, &has_gpu_resource); + + size_t purged_size = purged_gl_resources.size(); + + if (purged_size != 0) { + const NativeBufferHandler *handler = + resource_manager_->GetNativeBufferHandler(); + + for (size_t i = 0; i < purged_size; i++) { + const ResourceHandle &handle = purged_gl_resources.at(i); + if (!handle.handle_) { + continue; + } + auto search = mHyperDmaExportedBuffers.find( + handle.handle_->imported_handle_->data[0]); + if (search != mHyperDmaExportedBuffers.end()) { + struct ioctl_hyper_dmabuf_unexport msg; + int ret; + msg.hid = search->second.hyper_dmabuf_id; + msg.delay_ms = 1000; + ret = ioctl(mHyperDmaBuf_Fd, IOCTL_HYPER_DMABUF_UNEXPORT, &msg); + if (ret) { + ETRACE( + "Hyper DmaBuf: IOCTL_HYPER_DMABUF_UNEXPORT ioctl failed %d " + "[0x%x]\n", + ret, search->second.hyper_dmabuf_id.id); + } else { + ITRACE( + "Hyper DmaBuf: IOCTL_HYPER_DMABUF_UNEXPORT ioctl Done [0x%x]!\n", + search->second.hyper_dmabuf_id.id); + } + mHyperDmaExportedBuffers.erase(search); + } + handler->ReleaseBuffer(handle.handle_); + handler->DestroyHandle(handle.handle_); + } + } +#endif +} + +bool VirtualPanoramaDisplay::Present(std::vector &source_layers, + int32_t *retire_fence, + PixelUploaderCallback * /*call_back*/, + bool handle_constraints) { + CTRACE(); + if (!hyper_dmabuf_initialized) { + InitHyperDmaBuf(); + } + + std::vector layers; + std::vector> layers_rects; + std::vector index; + int ret = 0; + size_t size = source_layers.size(); + size_t previous_size = in_flight_layers_.size(); + bool frame_changed = (size != previous_size); + bool layers_changed = frame_changed; + *retire_fence = -1; + uint32_t z_order = 0; + + resource_manager_->RefreshBufferCache(); + for (size_t layer_index = 0; layer_index < size; layer_index++) { + HwcLayer *layer = source_layers.at(layer_index); + layer->SetReleaseFence(-1); + if (!layer->IsVisible()) + continue; + if (discard_protected_video_) { + if (layer->GetNativeHandle() != NULL && + (layer->GetNativeHandle()->meta_data_.usage_ & + hwcomposer::kLayerProtected)) + continue; + } + + layers.emplace_back(); + OverlayLayer &overlay_layer = layers.back(); + OverlayLayer *previous_layer = NULL; + if (previous_size > z_order) { + previous_layer = &(in_flight_layers_.at(z_order)); + } + + handle_constraints = true; + + overlay_layer.InitializeFromHwcLayer( + layer, resource_manager_.get(), previous_layer, z_order, layer_index, + height_, kIdentity, handle_constraints, fb_manager_); + index.emplace_back(z_order); + layers_rects.emplace_back(overlay_layer.GetDisplayFrame()); + + z_order++; + + if (frame_changed) { + layer->Validate(); + continue; + } + + if (!previous_layer || overlay_layer.HasLayerContentChanged() || + overlay_layer.HasDimensionsChanged()) { + layers_changed = true; + } + + layer->Validate(); + } + + if (layers_changed) { + compositor_.BeginFrame(false); + // Prepare for final composition. + if (!compositor_.DrawOffscreen( + layers, layers_rects, index, resource_manager_.get(), fb_manager_, + width_, height_, output_handle_, acquire_fence_, retire_fence)) { + ETRACE("Failed to prepare for the frame composition ret=%d", ret); + return false; + } + + acquire_fence_ = 0; + + in_flight_layers_.swap(layers); + } + + int32_t fence = *retire_fence; + + if (fence > 0) { + for (size_t layer_index = 0; layer_index < size; layer_index++) { + HwcLayer *layer = source_layers.at(layer_index); + layer->SetReleaseFence(dup(fence)); + } + } else { + for (size_t layer_index = 0; layer_index < size; layer_index++) { + const OverlayLayer &overlay_layer = + in_flight_layers_.at(index.at(layer_index)); + HwcLayer *layer = source_layers.at(overlay_layer.GetLayerIndex()); + layer->SetReleaseFence(overlay_layer.ReleaseAcquireFence()); + } + } + if (resource_manager_->PreparePurgedResources()) { + compositor_.FreeResources(); + } + +#ifdef HYPER_DMABUF_SHARING + HyperDmaExport(); +#endif + + return true; +} + +void VirtualPanoramaDisplay::CreateOutBuffer() { + const NativeBufferHandler *handler = + resource_manager_->GetNativeBufferHandler(); + HWCNativeHandle native_handle = 0; + bool modifier_used = false; + uint32_t usage = hwcomposer::kLayerNormal; + + handler->CreateBuffer(width_, height_, DRM_FORMAT_BGRA8888, &native_handle, + usage, &modifier_used); + + DTRACE("Create Buffer handler :%p", native_handle); + SetOutputBuffer(native_handle, -1); +} + +void VirtualPanoramaDisplay::SetOutputBuffer(HWCNativeHandle buffer, + int32_t acquire_fence) { + if (!output_handle_ || output_handle_ != buffer) { + const NativeBufferHandler *handler = + resource_manager_->GetNativeBufferHandler(); + + if (handle_) { + handler->ReleaseBuffer(handle_); + handler->DestroyHandle(handle_); + } + + delete output_handle_; + output_handle_ = buffer; + handle_ = 0; + + if (output_handle_) { + handler->CopyHandle(output_handle_, &handle_); + } + } + + if (acquire_fence_ > 0) { + close(acquire_fence_); + acquire_fence_ = -1; + } + + if (acquire_fence > 0) { + acquire_fence_ = dup(acquire_fence); + } +} + +bool VirtualPanoramaDisplay::Initialize( + NativeBufferHandler * /*buffer_manager*/, + FrameBufferManager *frame_buffer_manager) { + return true; +} + +bool VirtualPanoramaDisplay::GetDisplayAttribute(uint32_t /*config*/, + HWCDisplayAttribute attribute, + int32_t *value) { + // We always get the values from preferred mode config. + switch (attribute) { + case HWCDisplayAttribute::kWidth: + *value = width_; + break; + case HWCDisplayAttribute::kHeight: + *value = height_; + break; + case HWCDisplayAttribute::kRefreshRate: + // in nanoseconds + *value = 16666666; + break; + case HWCDisplayAttribute::kDpiX: + // Dots per 1000 inches + *value = 1; + break; + case HWCDisplayAttribute::kDpiY: + // Dots per 1000 inches + *value = 1; + break; + default: + *value = -1; + return false; + } + + return true; +} + +bool VirtualPanoramaDisplay::GetDisplayConfigs(uint32_t *num_configs, + uint32_t *configs) { + if (!num_configs) + return false; + *num_configs = 1; + if (configs) + configs[0] = 0; + + return true; +} + +bool VirtualPanoramaDisplay::GetDisplayName(uint32_t *size, char *name) { + std::ostringstream stream; + stream << "Virtual Panorama:" << display_index_; + std::string string = stream.str(); + size_t length = string.length(); + if (!name) { + *size = length; + return true; + } + + *size = std::min(static_cast(length - 1), *size); + strncpy(name, string.c_str(), *size); + return true; +} + +int VirtualPanoramaDisplay::GetDisplayPipe() { + return -1; +} + +bool VirtualPanoramaDisplay::SetPowerMode(uint32_t /*power_mode*/) { + return true; +} + +int VirtualPanoramaDisplay::RegisterVsyncCallback( + std::shared_ptr /*callback*/, uint32_t /*display_id*/) { + // return 0; + return 1; +} + +void VirtualPanoramaDisplay::VSyncControl(bool /*enabled*/) { +} + +bool VirtualPanoramaDisplay::CheckPlaneFormat(uint32_t /*format*/) { + // assuming that virtual display supports the format + return true; +} +} // namespace hwcomposer diff --git a/common/display/virtualpanoramadisplay.h b/common/display/virtualpanoramadisplay.h new file mode 100644 index 0000000..6326528 --- /dev/null +++ b/common/display/virtualpanoramadisplay.h @@ -0,0 +1,131 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// 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. +*/ + +#ifndef COMMON_DISPLAY_VIRTUALPANORAMADISPLAY_H_ +#define COMMON_DISPLAY_VIRTUALPANORAMADISPLAY_H_ + +#include + +#include +#include + +#include "compositor.h" +#include "resourcemanager.h" +#ifdef HYPER_DMABUF_SHARING +#include "hyperdmadisplay.h" +#endif + +namespace hwcomposer { +struct HwcLayer; +class FrameBufferManager; +class NativeBufferHandler; + +class VirtualPanoramaDisplay : public NativeDisplay { + public: + VirtualPanoramaDisplay(uint32_t gpu_fd, NativeBufferHandler *buffer_handler, + FrameBufferManager *framebuffermanager, + uint32_t pipe_id, uint32_t crtc_id); + VirtualPanoramaDisplay(const VirtualPanoramaDisplay &) = delete; + VirtualPanoramaDisplay &operator=(const VirtualPanoramaDisplay &) = delete; + ~VirtualPanoramaDisplay() override; + + void InitVirtualDisplay(uint32_t width, uint32_t height) override; + + bool GetActiveConfig(uint32_t *config) override; + + bool SetActiveConfig(uint32_t config) override; + + bool Present(std::vector &source_layers, int32_t *retire_fence, + PixelUploaderCallback *call_back = NULL, + bool handle_constraints = false) override; + + void SetOutputBuffer(HWCNativeHandle buffer, int32_t acquire_fence) override; + + bool Initialize(NativeBufferHandler *buffer_handler, + FrameBufferManager *frame_buffer_manager) override; + + bool IsConnected() const override { + return true; + } + + void CreateOutBuffer(); + + void HyperDmaExport(); + + DisplayType Type() const override { + return DisplayType::kVirtual; + } + + uint32_t Width() const override { + return width_; + } + + uint32_t Height() const override { + return height_; + } + + uint32_t PowerMode() const override { + return 0; + } + + bool GetDisplayAttribute(uint32_t config, HWCDisplayAttribute attribute, + int32_t *value) override; + + bool GetDisplayConfigs(uint32_t *num_configs, uint32_t *configs) override; + bool GetDisplayName(uint32_t *size, char *name) override; + int GetDisplayPipe() override; + + bool SetPowerMode(uint32_t power_mode) override; + + int RegisterVsyncCallback(std::shared_ptr callback, + uint32_t display_id) override; + + void VSyncControl(bool enabled) override; + bool CheckPlaneFormat(uint32_t format) override; + void SetPAVPSessionStatus(bool enabled, uint32_t pavp_session_id, + uint32_t pavp_instance_id) override { + if (enabled) { + discard_protected_video_ = false; + } else { + discard_protected_video_ = true; + } + } + + private: + void InitHyperDmaBuf(); + HWCNativeHandle output_handle_; + int32_t acquire_fence_ = -1; + Compositor compositor_; + uint32_t width_ = 1; + uint32_t height_ = 1; + std::vector in_flight_layers_; + HWCNativeHandle handle_ = 0; + std::unique_ptr resource_manager_; + FrameBufferManager *fb_manager_ = NULL; + uint32_t display_index_ = 0; + bool discard_protected_video_ = false; + bool hyper_dmabuf_initialized = false; + +#ifdef HYPER_DMABUF_SHARING + int mHyperDmaBuf_Fd = -1; + std::map + mHyperDmaExportedBuffers; // Track the hyper dmabuf metadata info mapping + uint32_t frame_count_ = 0; +#endif +}; + +} // namespace hwcomposer +#endif // COMMON_DISPLAY_VIRTUALMOSAICDISPLAY_H_ diff --git a/hwc_display_virt.ini b/hwc_display_virt.ini index 02564ee..bcc3dff 100644 --- a/hwc_display_virt.ini +++ b/hwc_display_virt.ini @@ -4,6 +4,7 @@ LOGICAL="false" MOSAIC="false" CLONE="false" ROTATION="false" +PANORAMA="false" # The Order of Physical Displays. This along with connection status # will be used to determine the order. If display is first in this @@ -25,6 +26,12 @@ LOGICAL_DISPLAY="0:3" # sub-display-index: start from 0, should be the available displays number, follow the order of the connected logical displays MOSAIC_DISPLAY="0+1+2" +# Panorama display definitions, with format "sub-display-index+sub-display-index+sub-display-index....." +# sub-display-index: start from 0, should be the available displays number, follow the order of the connected logical displays +PANORAMA_DISPLAY="0+" +# Panorama SOS display defines the display index started in SOS side for servering display sharing request from AaaG. +PANORAMA_SOS_DISPLAY="2+" + # Clone display definitions, with format "physical-display-number:cloned-physical-display-number". This # setting is ignored if LOGICAL or MOSAIC is set to true. # physical-display-number: start from 0, included all display ports(whatever connected or disconnected) diff --git a/public/gpudevice.h b/public/gpudevice.h index b0cd8c7..32f5ccb 100644 --- a/public/gpudevice.h +++ b/public/gpudevice.h @@ -109,6 +109,20 @@ class GpuDevice : public HWCThread { std::unique_ptr display_manager_; std::vector> logical_display_manager_; std::vector> mosaic_displays_; +#ifdef ENABLE_PANORAMA + std::vector> panorama_displays_; + void ParsePanoramaDisplayConfig( + std::string& value, + std::vector>& panorama_displays); + void ParsePanoramaSOSDisplayConfig( + std::string& value, + std::vector>& panorama_sos_displays); + void PanoramaInit(std::vector& total_displays_, + std::vector& temp_displays, + std::vector>& panorama_displays, + std::vector>& panorama_sos_displays, + std::vector& available_displays); +#endif std::vector total_displays_; bool reserve_plane_ = false; diff --git a/public/hwclayer.h b/public/hwclayer.h index bb52058..f2dc0b3 100644 --- a/public/hwclayer.h +++ b/public/hwclayer.h @@ -302,6 +302,10 @@ struct HwcLayer { friend class PhysicalDisplay; friend class MosaicDisplay; +#ifdef ENABLE_PANORAMA + friend class VirtualPanoramaDisplay; +#endif + enum LayerState { kSurfaceDamageChanged = 1 << 0, kLayerContentChanged = 1 << 1, diff --git a/wsi/Android.mk b/wsi/Android.mk index a144f7d..8d1039b 100644 --- a/wsi/Android.mk +++ b/wsi/Android.mk @@ -64,6 +64,10 @@ ifeq ($(strip $(ENABLE_HYPER_DMABUF_SHARING)), true) LOCAL_CPPFLAGS += -DHYPER_DMABUF_SHARING endif +ifeq ($(strip $(ENABLE_HYPER_DMABUF_SHARING)), true) +LOCAL_CPPFLAGS += -DENABLE_PANORAMA +endif + ifeq ($(strip $(TARGET_USES_HWC2)), false) LOCAL_C_INCLUDES += \ system/core/libsync \ diff --git a/wsi/displaymanager.h b/wsi/displaymanager.h index ec71007..d538f2c 100644 --- a/wsi/displaymanager.h +++ b/wsi/displaymanager.h @@ -61,6 +61,11 @@ class DisplayManager { virtual NativeDisplay *CreateVirtualDisplay(uint32_t display_index) = 0; virtual void DestroyVirtualDisplay(uint32_t display_index) = 0; +#ifdef ENABLE_PANORAMA + virtual NativeDisplay *CreateVirtualPanoramaDisplay( + uint32_t display_index) = 0; +#endif + virtual std::vector GetAllDisplays() = 0; virtual void RegisterHotPlugEventCallback( diff --git a/wsi/drm/drmdisplaymanager.cpp b/wsi/drm/drmdisplaymanager.cpp index bde7be7..2822ed1 100644 --- a/wsi/drm/drmdisplaymanager.cpp +++ b/wsi/drm/drmdisplaymanager.cpp @@ -559,4 +559,21 @@ void DrmDisplayManager::RemoveUnreservedPlanes() { displays_.at(i)->SetPlanesUpdated(true); } } + +#ifdef ENABLE_PANORAMA +NativeDisplay *DrmDisplayManager::CreateVirtualPanoramaDisplay( + uint32_t display_index) { + spin_lock_.lock(); + NativeDisplay *latest_display; + std::unique_ptr display(new VirtualPanoramaDisplay( + fd_, buffer_handler_.get(), frame_buffer_manager_.get(), display_index, + 0)); + virtual_displays_.emplace_back(std::move(display)); + size_t size = virtual_displays_.size(); + latest_display = virtual_displays_.at(size - 1).get(); + spin_lock_.unlock(); + return latest_display; +} +#endif + } // namespace hwcomposer diff --git a/wsi/drm/drmdisplaymanager.h b/wsi/drm/drmdisplaymanager.h index 3590827..03726c5 100644 --- a/wsi/drm/drmdisplaymanager.h +++ b/wsi/drm/drmdisplaymanager.h @@ -33,6 +33,9 @@ #include "hwcthread.h" #include "vblankeventhandler.h" #include "virtualdisplay.h" +#ifdef ENABLE_PANORAMA +#include "virtualpanoramadisplay.h" +#endif namespace hwcomposer { @@ -54,6 +57,10 @@ class DrmDisplayManager : public HWCThread, public DisplayManager { NativeDisplay *CreateVirtualDisplay(uint32_t display_index) override; void DestroyVirtualDisplay(uint32_t display_index) override; +#ifdef ENABLE_PANORAMA + NativeDisplay *CreateVirtualPanoramaDisplay(uint32_t display_index) override; +#endif + std::vector GetAllDisplays() override; void RegisterHotPlugEventCallback( -- 2.11.0