From: Kalyan Kondapally Date: Sun, 19 Feb 2017 22:50:46 +0000 (-0800) Subject: Move Display Commits to a separate thread. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a3c69cd1435863af2d92a9bfdb29a70bbce33828;p=android-x86%2Fexternal-IA-Hardware-Composer.git Move Display Commits to a separate thread. This should ensure that any waits we do on KMS Fences doesn't block the main thread. Jira: None. Test: No regressions on Linux and Android. Signed-off-by: Kalyan Kondapally --- diff --git a/Android.mk b/Android.mk index 774730a..e5cb23b 100644 --- a/Android.mk +++ b/Android.mk @@ -58,6 +58,7 @@ LOCAL_SRC_FILES := \ common/display/display.cpp \ common/display/displayplane.cpp \ common/display/displayplanemanager.cpp \ + common/display/displayqueue.cpp \ common/display/headless.cpp \ common/display/pageflipeventhandler.cpp \ common/display/virtualdisplay.cpp \ diff --git a/Makefile.sources b/Makefile.sources index fb828a1..96ea15d 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -10,6 +10,7 @@ common_SOURCES = \ common/core/overlaybuffer.cpp \ common/core/overlaylayer.cpp \ common/display/display.cpp \ + common/display/displayqueue.cpp \ common/display/displayplane.cpp \ common/display/displayplanemanager.cpp \ common/display/headless.cpp \ diff --git a/common/compositor/gl/egloffscreencontext.cpp b/common/compositor/gl/egloffscreencontext.cpp index 8c78d82..b0de404 100644 --- a/common/compositor/gl/egloffscreencontext.cpp +++ b/common/compositor/gl/egloffscreencontext.cpp @@ -114,6 +114,9 @@ EGLint EGLOffScreenContext::GetSyncFD() { } eglDestroySyncKHR(egl_display_, egl_sync); +#else + // Lets ensure every thing is flushed. + eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_ctx_); #endif return sync_fd; } diff --git a/common/core/gpudevice.cpp b/common/core/gpudevice.cpp index 465cb69..614e563 100644 --- a/common/core/gpudevice.cpp +++ b/common/core/gpudevice.cpp @@ -51,7 +51,7 @@ namespace hwcomposer { class GpuDevice::DisplayManager : public HWCThread { public: DisplayManager(); - ~DisplayManager(); + ~DisplayManager() override; bool Init(uint32_t fd); diff --git a/common/display/display.cpp b/common/display/display.cpp index 5b2585d..096e655 100644 --- a/common/display/display.cpp +++ b/common/display/display.cpp @@ -20,9 +20,7 @@ #include #include -#include "displayplanemanager.h" -#include "nativesync.h" -#include "overlaylayer.h" +#include "displayqueue.h" namespace hwcomposer { @@ -34,32 +32,19 @@ Display::Display(uint32_t gpu_fd, NativeBufferHandler &buffer_handler, crtc_id_(crtc_id), pipe_(pipe_id), connector_(0), - blob_id_(0), - old_blob_id_(0), gpu_fd_(gpu_fd), is_connected_(false), is_powered_off_(true) { } Display::~Display() { - if (blob_id_) - drmModeDestroyPropertyBlob(gpu_fd_, blob_id_); - - if (old_blob_id_) - drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_); + display_queue_->Exit(); } bool Display::Initialize() { - ScopedDrmObjectPropertyPtr crtc_props( - drmModeObjectGetProperties(gpu_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC)); - GetDrmObjectProperty("ACTIVE", crtc_props, &active_prop_); - GetDrmObjectProperty("MODE_ID", crtc_props, &mode_id_prop_); -#ifndef DISABLE_EXPLICIT_SYNC - GetDrmObjectProperty("OUT_FENCE_PTR", crtc_props, &out_fence_ptr_prop_); -#endif frame_ = 0; flip_handler_.reset(new PageFlipEventHandler()); - compositor_.Init(); + display_queue_.reset(new DisplayQueue(gpu_fd_, crtc_id_)); return true; } @@ -73,42 +58,27 @@ bool Display::Connect(const drmModeModeInfo &mode_info, is_connected_ = true; return true; } - ScopedSpinLock lock(spin_lock_); + IHOTPLUGEVENTTRACE("Display is being connected to a new connector."); - mode_ = mode_info; connector_ = connector->connector_id; - width_ = mode_.hdisplay; - height_ = mode_.vdisplay; - refresh_ = (mode_.clock * 1000.0f) / (mode_.htotal * mode_.vtotal); + width_ = mode_info.hdisplay; + height_ = mode_info.vdisplay; + refresh_ = + (mode_info.clock * 1000.0f) / (mode_info.htotal * mode_info.vtotal); dpix_ = connector->mmWidth ? (width_ * kUmPerInch) / connector->mmWidth : -1; dpiy_ = connector->mmHeight ? (height_ * kUmPerInch) / connector->mmHeight : -1; - ScopedDrmObjectPropertyPtr connector_props(drmModeObjectGetProperties( - gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR)); - if (!connector_props) { - ETRACE("Unable to get connector properties."); - return false; - } - - GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_); - GetDrmObjectProperty("CRTC_ID", connector_props, &crtc_prop_); is_powered_off_ = false; is_connected_ = true; - display_plane_manager_.reset( - new DisplayPlaneManager(gpu_fd_, pipe_, crtc_id_)); - if (!display_plane_manager_->Initialize(&buffer_handler_, width_, height_)) { - ETRACE("Failed to initialize Display Manager."); + if (!display_queue_->Initialize(width_, height_, pipe_, connector_, mode_info, + &buffer_handler_)) { + ETRACE("Failed to initialize Display Queue."); return false; } flip_handler_->Init(refresh_, gpu_fd_, pipe_); - dpms_mode_ = DRM_MODE_DPMS_ON; - drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_, - DRM_MODE_DPMS_ON); - pending_operations_ |= PendingModeset::kModeset; - return true; } @@ -120,31 +90,10 @@ void Display::DisConnect() { void Display::ShutDown() { if (is_powered_off_) return; - ScopedSpinLock lock(spin_lock_); + IHOTPLUGEVENTTRACE("Display::ShutDown recieved."); + display_queue_->Exit(); is_powered_off_ = true; - dpms_mode_ = DRM_MODE_DPMS_OFF; - drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_, - DRM_MODE_DPMS_OFF); - previous_layers_.clear(); - previous_plane_state_.clear(); - - ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc()); - if (!pset) { - ETRACE("Failed to allocate property set %d", -ENOMEM); - return; - } - - bool active = false; - int ret = - drmModeAtomicAddProperty(pset.get(), crtc_id_, active_prop_, active) < 0; - if (ret) { - ETRACE("Failed to set display to inactive"); - return; - } - - display_plane_manager_->DisablePipe(pset.get()); - display_plane_manager_.reset(nullptr); } bool Display::GetDisplayAttribute(uint32_t /*config*/, @@ -216,181 +165,12 @@ bool Display::GetActiveConfig(uint32_t *config) { } bool Display::SetDpmsMode(uint32_t dpms_mode) { - ScopedSpinLock lock(spin_lock_); - if (dpms_mode_ == dpms_mode) - return true; - - dpms_mode_ = dpms_mode; - drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_, dpms_mode); - return true; -} - -bool Display::ApplyPendingModeset(drmModeAtomicReqPtr property_set, - NativeSync *sync, uint64_t *out_fence) { - if (pending_operations_ & kModeset) { - if (old_blob_id_) { - drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_); - old_blob_id_ = 0; - } - - drmModeCreatePropertyBlob(gpu_fd_, &mode_, sizeof(drmModeModeInfo), - &blob_id_); - if (blob_id_ == 0) - return false; - - bool active = true; - - int ret = drmModeAtomicAddProperty(property_set, crtc_id_, mode_id_prop_, - blob_id_) < 0 || - drmModeAtomicAddProperty(property_set, connector_, crtc_prop_, - crtc_id_) < 0 || - drmModeAtomicAddProperty(property_set, crtc_id_, active_prop_, - active) < 0; - if (ret) { - ETRACE("Failed to add blob %d to pset", blob_id_); - return false; - } - - pending_operations_ &= ~kModeset; - old_blob_id_ = blob_id_; - blob_id_ = 0; - } else { -#ifndef DISABLE_EXPLICIT_SYNC - if (out_fence_ptr_prop_ != 0) { - int ret = drmModeAtomicAddProperty( - property_set, crtc_id_, out_fence_ptr_prop_, (uintptr_t)out_fence); - if (ret < 0) { - ETRACE("Failed to add OUT_FENCE_PTR property to pset: %d", ret); - return false; - } - } -#else - *out_fence = sync->CreateNextTimelineFence(); -#endif - } - - return true; -} - -void Display::GetDrmObjectProperty(const char *name, - const ScopedDrmObjectPropertyPtr &props, - uint32_t *id) const { - uint32_t count_props = props->count_props; - for (uint32_t i = 0; i < count_props; i++) { - ScopedDrmPropertyPtr property(drmModeGetProperty(gpu_fd_, props->props[i])); - if (property && !strcmp(property->name, name)) { - *id = property->prop_id; - break; - } - } - if (!(*id)) - ETRACE("Could not find property %s", name); + return display_queue_->SetDpmsMode(dpms_mode); } bool Display::Present(std::vector &source_layers) { CTRACE(); - ScopedSpinLock lock(spin_lock_); - if (is_powered_off_) { - IHOTPLUGEVENTTRACE("Trying to update an Disconnected Display."); - return false; - } - - bool needs_modeset = pending_operations_ & kModeset; - // Create a Sync object for this Composition. - std::unique_ptr sync_object(new NativeSync()); - if (!sync_object->Init()) { - ETRACE("Failed to create sync object."); - return false; - } - - std::vector layers; - std::vector> layers_rects; - - int ret = 0; - size_t size = source_layers.size(); - for (size_t layer_index = 0; layer_index < size; layer_index++) { - HwcLayer *layer = source_layers.at(layer_index); - layers.emplace_back(); - OverlayLayer &overlay_layer = layers.back(); - overlay_layer.SetNativeHandle(layer->GetNativeHandle()); - overlay_layer.SetTransform(layer->GetTransform()); - overlay_layer.SetAlpha(layer->GetAlpha()); - overlay_layer.SetBlending(layer->GetBlending()); - overlay_layer.SetSourceCrop(layer->GetSourceCrop()); - overlay_layer.SetDisplayFrame(layer->GetDisplayFrame()); - overlay_layer.SetIndex(layer_index); - overlay_layer.SetAcquireFence(layer->acquire_fence.Release()); - layers_rects.emplace_back(layer->GetDisplayFrame()); - int ret = - layer->release_fence.Reset(sync_object->CreateNextTimelineFence()); - if (ret < 0) - ETRACE("Failed to create fence for layer, error: %s", PRINTERROR()); - } - - // Reset any Display Manager and Compositor state. - if (!display_plane_manager_->BeginFrameUpdate(layers)) { - ETRACE("Failed to import needed buffers in DisplayManager."); - return false; - } - - DisplayPlaneStateList current_composition_planes; - bool render_layers; - // Validate Overlays and Layers usage. - std::tie(render_layers, current_composition_planes) = - display_plane_manager_->ValidateLayers( - layers, previous_layers_, previous_plane_state_, needs_modeset); - - DUMP_CURRENT_COMPOSITION_PLANES(); - - if (!compositor_.BeginFrame()) { - ETRACE("Failed to initialize compositor."); - return false; - } - - if (render_layers) { - // Prepare for final composition. - if (!compositor_.Draw(current_composition_planes, layers, layers_rects)) { - ETRACE("Failed to prepare for the frame composition ret=%d", ret); - return false; - } - } - - // Do the actual commit. - ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc()); - - if (!pset) { - ETRACE("Failed to allocate property set %d", -ENOMEM); - return false; - } - - uint64_t fence = 0; - if (!ApplyPendingModeset(pset.get(), sync_object.get(), &fence)) { - ETRACE("Failed to Modeset"); - return false; - } - - bool succesful_commit = true; - - if (!display_plane_manager_->CommitFrame(current_composition_planes, - pset.get(), needs_modeset, - sync_object, out_fence_)) { - succesful_commit = false; - } else { - display_plane_manager_->EndFrameUpdate(); - previous_layers_.swap(layers); - previous_plane_state_.swap(current_composition_planes); - } - - if (!succesful_commit || needs_modeset) - return succesful_commit; - - - compositor_.InsertFence(dup(fence)); - - if (fence > 0) - out_fence_.Reset(fence); - - return true; + return display_queue_->QueueUpdate(source_layers); } int Display::RegisterVsyncCallback(std::shared_ptr callback, diff --git a/common/display/display.h b/common/display/display.h index 523fac7..a2a92a1 100644 --- a/common/display/display.h +++ b/common/display/display.h @@ -14,12 +14,11 @@ // limitations under the License. */ -#ifndef INTERNAL_DISPLAY_H_ -#define INTERNAL_DISPLAY_H_ +#ifndef DISPLAY_H_ +#define DISPLAY_H_ #include "platformdefines.h" -#include #include #include @@ -27,14 +26,13 @@ #include #include -#include "compositor.h" #include "pageflipeventhandler.h" #include "scopedfd.h" -#include "spinlock.h" namespace hwcomposer { class DisplayPlaneState; class DisplayPlaneManager; +class DisplayQueue; class GpuDevice; class NativeSync; struct HwcLayer; @@ -43,7 +41,7 @@ class Display : public NativeDisplay { public: Display(uint32_t gpu_fd, NativeBufferHandler &handler, uint32_t pipe_id, uint32_t crtc_id); - ~Display(); + ~Display() override; bool Initialize() override; @@ -101,33 +99,13 @@ class Display : public NativeDisplay { void ShutDown() override; private: - enum PendingModeset { kNone = 0, kModeset = 1 << 0 }; - void ShutDownPipe(); - void InitializeResources(); - bool ApplyPendingModeset(drmModeAtomicReqPtr property_set, NativeSync *sync, - uint64_t *out_fence); - - void GetDrmObjectProperty(const char *name, - const ScopedDrmObjectPropertyPtr &props, - uint32_t *id) const; NativeBufferHandler &buffer_handler_; - Compositor compositor_; - drmModeModeInfo mode_; uint32_t frame_; - uint32_t dpms_prop_; - uint32_t crtc_prop_; - uint32_t active_prop_; - uint32_t mode_id_prop_; - uint32_t out_fence_ptr_prop_; uint32_t crtc_id_; uint32_t pipe_; - uint32_t dpms_mode_ = DRM_MODE_DPMS_ON; uint32_t connector_; - uint32_t pending_operations_ = kNone; - uint32_t blob_id_ = 0; - uint32_t old_blob_id_ = 0; int32_t width_; int32_t height_; int32_t dpix_; @@ -136,13 +114,9 @@ class Display : public NativeDisplay { bool is_connected_; bool is_powered_off_; float refresh_; - ScopedFd out_fence_ = -1; std::unique_ptr flip_handler_; - std::unique_ptr display_plane_manager_; - SpinLock spin_lock_; - std::vector previous_layers_; - DisplayPlaneStateList previous_plane_state_; + std::unique_ptr display_queue_; }; } // namespace hwcomposer -#endif // INTERNAL_DISPLAY_H_ +#endif // DISPLAY_H_ diff --git a/common/display/displayplanemanager.cpp b/common/display/displayplanemanager.cpp index f8b8593..38d65eb 100644 --- a/common/display/displayplanemanager.cpp +++ b/common/display/displayplanemanager.cpp @@ -328,8 +328,9 @@ bool DisplayPlaneManager::CommitFrame(DisplayPlaneStateList &comp_planes, } } +#ifndef DISABLE_EXPLICIT_SYNC fence.Close(); - +#endif if (ret) { ETRACE("Failed to commit pset ret=%s\n", PRINTERROR()); return false; diff --git a/common/display/displayqueue.cpp b/common/display/displayqueue.cpp new file mode 100644 index 0000000..9f41310 --- /dev/null +++ b/common/display/displayqueue.cpp @@ -0,0 +1,351 @@ +/* +// Copyright (c) 2017 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 "displayqueue.h" + +#include +#include +#include + +#include + +#include "displayplanemanager.h" +#include "overlaylayer.h" +#include "pageflipeventhandler.h" + +namespace hwcomposer { + +DisplayQueue::DisplayQueue(uint32_t gpu_fd, uint32_t crtc_id) + : HWCThread(-8, "DisplayQueue"), + crtc_id_(crtc_id), + gpu_fd_(gpu_fd), + blob_id_(0), + old_blob_id_(0) { + compositor_.Init(); + ScopedDrmObjectPropertyPtr crtc_props( + drmModeObjectGetProperties(gpu_fd_, crtc_id_, DRM_MODE_OBJECT_CRTC)); + GetDrmObjectProperty("ACTIVE", crtc_props, &active_prop_); + GetDrmObjectProperty("MODE_ID", crtc_props, &mode_id_prop_); +#ifndef DISABLE_EXPLICIT_SYNC + GetDrmObjectProperty("OUT_FENCE_PTR", crtc_props, &out_fence_ptr_prop_); +#endif +} + +DisplayQueue::~DisplayQueue() { + if (blob_id_) + drmModeDestroyPropertyBlob(gpu_fd_, blob_id_); + + if (old_blob_id_) + drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_); +} + +bool DisplayQueue::Initialize(uint32_t width, uint32_t height, uint32_t pipe, + uint32_t connector, + const drmModeModeInfo& mode_info, + NativeBufferHandler* buffer_handler) { + ScopedSpinLock lock(spin_lock_); + frame_ = 0; + previous_layers_.clear(); + previous_plane_state_.clear(); + display_plane_manager_.reset( + new DisplayPlaneManager(gpu_fd_, pipe, crtc_id_)); + + if (!display_plane_manager_->Initialize(buffer_handler, width, height)) { + ETRACE("Failed to initialize DisplayQueue Manager."); + return false; + } + + connector_ = connector; + mode_ = mode_info; + + ScopedDrmObjectPropertyPtr connector_props(drmModeObjectGetProperties( + gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR)); + if (!connector_props) { + ETRACE("Unable to get connector properties."); + return false; + } + + GetDrmObjectProperty("DPMS", connector_props, &dpms_prop_); + GetDrmObjectProperty("CRTC_ID", connector_props, &crtc_prop_); + + dpms_mode_ = DRM_MODE_DPMS_ON; + drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_, + DRM_MODE_DPMS_ON); + + needs_modeset_ = true; + lock.Reset(); + if (!InitWorker()) { + ETRACE("Failed to initalize thread for DisplayQueue. %s", PRINTERROR()); + return false; + } + + return true; +} + +void DisplayQueue::Exit() { + IHOTPLUGEVENTTRACE("DisplayQueue::Exit recieved."); + HWCThread::Exit(); +} + +bool DisplayQueue::GetFence(ScopedDrmAtomicReqPtr& property_set, + uint64_t* out_fence) { +#ifndef DISABLE_EXPLICIT_SYNC + if (out_fence_ptr_prop_ != 0) { + int ret = + drmModeAtomicAddProperty(property_set.get(), crtc_id_, + out_fence_ptr_prop_, (uintptr_t)out_fence); + if (ret < 0) { + ETRACE("Failed to add OUT_FENCE_PTR property to pset: %d", ret); + return false; + } + } +#else + *out_fence = -1; +#endif + + return true; +} + +bool DisplayQueue::ApplyPendingModeset(drmModeAtomicReqPtr property_set) { + if (old_blob_id_) { + drmModeDestroyPropertyBlob(gpu_fd_, old_blob_id_); + old_blob_id_ = 0; + } + + drmModeCreatePropertyBlob(gpu_fd_, &mode_, sizeof(drmModeModeInfo), + &blob_id_); + if (blob_id_ == 0) + return false; + + bool active = true; + + int ret = drmModeAtomicAddProperty(property_set, crtc_id_, mode_id_prop_, + blob_id_) < 0 || + drmModeAtomicAddProperty(property_set, connector_, crtc_prop_, + crtc_id_) < 0 || + drmModeAtomicAddProperty(property_set, crtc_id_, active_prop_, + active) < 0; + if (ret) { + ETRACE("Failed to add blob %d to pset", blob_id_); + return false; + } + + old_blob_id_ = blob_id_; + blob_id_ = 0; + + return true; +} + +bool DisplayQueue::SetDpmsMode(uint32_t dpms_mode) { + ScopedSpinLock lock(spin_lock_); + if (dpms_mode_ == dpms_mode) + return true; + + dpms_mode_ = dpms_mode; + if (dpms_mode_ == DRM_MODE_DPMS_OFF) { + Exit(); + return true; + } + + if (dpms_mode_ == DRM_MODE_DPMS_ON) { + needs_modeset_ = true; + if (!InitWorker()) { + ETRACE("Failed to initalize thread for DisplayQueue. %s", PRINTERROR()); + return false; + } + } + + drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_, dpms_mode); + + return true; +} + +bool DisplayQueue::QueueUpdate(std::vector& source_layers) { + CTRACE(); + ScopedSpinLock lock(display_queue_); + if (!display_plane_manager_) { + IHOTPLUGEVENTTRACE("Trying to update an Disconnected Display."); + return false; + } + + queue_.emplace(); + DisplayQueueItem& queue_item = queue_.back(); + // Create a Sync object for this Composition. + queue_item.sync_object_.reset(new NativeSync()); + if (!queue_item.sync_object_->Init()) { + ETRACE("Failed to create sync object."); + return false; + } + + size_t size = source_layers.size(); + + for (size_t layer_index = 0; layer_index < size; layer_index++) { + HwcLayer* layer = source_layers.at(layer_index); + queue_item.layers_.emplace_back(); + OverlayLayer& overlay_layer = queue_item.layers_.back(); + overlay_layer.SetNativeHandle(layer->GetNativeHandle()); + overlay_layer.SetTransform(layer->GetTransform()); + overlay_layer.SetAlpha(layer->GetAlpha()); + overlay_layer.SetBlending(layer->GetBlending()); + overlay_layer.SetSourceCrop(layer->GetSourceCrop()); + overlay_layer.SetDisplayFrame(layer->GetDisplayFrame()); + overlay_layer.SetIndex(layer_index); + overlay_layer.SetAcquireFence(layer->acquire_fence.Release()); + queue_item.layers_rects_.emplace_back(layer->GetDisplayFrame()); + int ret = layer->release_fence.Reset( + queue_item.sync_object_->CreateNextTimelineFence()); + if (ret < 0) + ETRACE("Failed to create fence for layer, error: %s", PRINTERROR()); + } + + Resume(); + return true; +} + +void DisplayQueue::HandleUpdateRequest(DisplayQueueItem& queue_item) { + CTRACE(); + ScopedSpinLock lock(spin_lock_); + // Reset any DisplayQueue Manager and Compositor state. + if (!display_plane_manager_->BeginFrameUpdate(queue_item.layers_)) { + ETRACE("Failed to import needed buffers in DisplayQueueManager."); + return; + } + + bool needs_modeset = needs_modeset_; + needs_modeset_ = false; + + DisplayPlaneStateList current_composition_planes; + bool render_layers; + // Validate Overlays and Layers usage. + std::tie(render_layers, current_composition_planes) = + display_plane_manager_->ValidateLayers( + queue_item.layers_, previous_layers_, previous_plane_state_, + needs_modeset); + + DUMP_CURRENT_COMPOSITION_PLANES(); + + if (!compositor_.BeginFrame()) { + ETRACE("Failed to initialize compositor."); + return; + } + + if (render_layers) { + // Prepare for final composition. + if (!compositor_.Draw(current_composition_planes, queue_item.layers_, + queue_item.layers_rects_)) { + ETRACE("Failed to prepare for the frame composition. "); + return; + } + } + + // Do the actual commit. + bool succesful_commit = true; + uint64_t fence = 0; + // Do the actual commit. + ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc()); + + if (!pset) { + ETRACE("Failed to allocate property set %d", -ENOMEM); + return; + } + + if (needs_modeset && !ApplyPendingModeset(pset.get())) { + ETRACE("Failed to Modeset."); + return; + } + + GetFence(pset, &fence); + if (!display_plane_manager_->CommitFrame( + current_composition_planes, pset.get(), needs_modeset, + queue_item.sync_object_, out_fence_)) { + succesful_commit = false; + } else { + display_plane_manager_->EndFrameUpdate(); + previous_layers_.swap(queue_item.layers_); + previous_plane_state_.swap(current_composition_planes); + } + + if (!succesful_commit || needs_modeset) + return; + + compositor_.InsertFence(dup(fence)); + + if (fence > 0) + out_fence_.Reset(fence); +} + +void DisplayQueue::HandleRoutine() { + display_queue_.lock(); + size_t size = queue_.size(); + + if (size <= 0) { + display_queue_.unlock(); + ConditionalSuspend(); + return; + } + + DisplayQueueItem& queue_item = queue_.front(); + DisplayQueueItem item; + item.layers_.swap(queue_item.layers_); + item.layers_rects_.swap(queue_item.layers_rects_); + item.sync_object_.reset(queue_item.sync_object_.release()); + queue_.pop(); + display_queue_.unlock(); + + HandleUpdateRequest(item); +} + +void DisplayQueue::HandleExit() { + ScopedSpinLocks lock(spin_lock_, display_queue_); + ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc()); + if (!pset) { + ETRACE("Failed to allocate property set %d", -ENOMEM); + return; + } + + bool active = false; + int ret = + drmModeAtomicAddProperty(pset.get(), crtc_id_, active_prop_, active) < 0; + if (ret) { + ETRACE("Failed to set display to inactive"); + return; + } + display_plane_manager_->DisablePipe(pset.get()); + dpms_mode_ = DRM_MODE_DPMS_OFF; + drmModeConnectorSetProperty(gpu_fd_, connector_, dpms_prop_, + DRM_MODE_DPMS_OFF); + previous_layers_.clear(); + previous_plane_state_.clear(); + display_plane_manager_.reset(nullptr); + std::queue().swap(queue_); +} + +void DisplayQueue::GetDrmObjectProperty(const char* name, + const ScopedDrmObjectPropertyPtr& props, + uint32_t* id) const { + uint32_t count_props = props->count_props; + for (uint32_t i = 0; i < count_props; i++) { + ScopedDrmPropertyPtr property(drmModeGetProperty(gpu_fd_, props->props[i])); + if (property && !strcmp(property->name, name)) { + *id = property->prop_id; + break; + } + } + if (!(*id)) + ETRACE("Could not find property %s", name); +} + +} // namespace hwcomposer diff --git a/common/display/displayqueue.h b/common/display/displayqueue.h new file mode 100644 index 0000000..5574409 --- /dev/null +++ b/common/display/displayqueue.h @@ -0,0 +1,96 @@ +/* +// Copyright (c) 2017 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 DISPLAY_QUEUE_H_ +#define DISPLAY_QUEUE_H_ + +#include + +#include "platformdefines.h" + +#include + +#include "compositor.h" +#include "hwcthread.h" +#include "nativesync.h" +#include "scopedfd.h" +#include "spinlock.h" + +namespace hwcomposer { +class DisplayPlaneManager; +struct HwcLayer; +class NativeBufferHandler; +class PageFlipEventHandler; + +class DisplayQueue : public HWCThread { + public: + DisplayQueue(uint32_t gpu_fd, uint32_t crtc_id); + ~DisplayQueue() override; + + bool Initialize(uint32_t width, uint32_t height, uint32_t pipe, + uint32_t connector, const drmModeModeInfo& mode_info, + NativeBufferHandler* buffer_handler); + + void Exit(); + + bool QueueUpdate(std::vector& source_layers); + bool SetDpmsMode(uint32_t dpms_mode); + + protected: + void HandleRoutine() override; + void HandleExit() override; + + private: + struct DisplayQueueItem { + std::vector layers_; + std::vector> layers_rects_; + std::unique_ptr sync_object_; + }; + + void HandleUpdateRequest(DisplayQueueItem& queue_item); + bool ApplyPendingModeset(drmModeAtomicReqPtr property_set); + bool GetFence(ScopedDrmAtomicReqPtr& property_set, uint64_t* out_fence); + void GetDrmObjectProperty(const char* name, + const ScopedDrmObjectPropertyPtr& props, + uint32_t* id) const; + + Compositor compositor_; + drmModeModeInfo mode_; + uint32_t frame_; + uint32_t dpms_prop_; + uint32_t dpms_mode_ = DRM_MODE_DPMS_ON; + uint32_t out_fence_ptr_prop_; + uint32_t active_prop_; + uint32_t mode_id_prop_; + uint32_t crtc_id_; + uint32_t connector_; + uint32_t crtc_prop_; + uint32_t blob_id_ = 0; + uint32_t old_blob_id_ = 0; + uint32_t gpu_fd_; + bool needs_modeset_ = false; + std::unique_ptr flip_handler_; + std::unique_ptr display_plane_manager_; + SpinLock spin_lock_; + SpinLock display_queue_; + std::queue queue_; + std::vector previous_layers_; + DisplayPlaneStateList previous_plane_state_; + ScopedFd out_fence_ = -1; +}; + +} // namespace hwcomposer +#endif // DISPLAY_QUEUE_H_ diff --git a/common/display/headless.h b/common/display/headless.h index cfd5281..9bade7c 100644 --- a/common/display/headless.h +++ b/common/display/headless.h @@ -27,7 +27,7 @@ class Headless : public NativeDisplay { public: Headless(uint32_t gpu_fd, NativeBufferHandler &handler, uint32_t pipe_id, uint32_t crtc_id); - ~Headless(); + ~Headless() override; bool Initialize() override; diff --git a/common/display/pageflipeventhandler.h b/common/display/pageflipeventhandler.h index 260db72..eeeb6e0 100644 --- a/common/display/pageflipeventhandler.h +++ b/common/display/pageflipeventhandler.h @@ -29,7 +29,7 @@ namespace hwcomposer { class PageFlipEventHandler : public HWCThread { public: PageFlipEventHandler(); - ~PageFlipEventHandler(); + ~PageFlipEventHandler() override; void Init(float refresh, int fd, int pipe); diff --git a/common/display/virtualdisplay.h b/common/display/virtualdisplay.h index a2e0622..92288f6 100644 --- a/common/display/virtualdisplay.h +++ b/common/display/virtualdisplay.h @@ -30,7 +30,7 @@ class VirtualDisplay : public Headless { public: VirtualDisplay(uint32_t gpu_fd, NativeBufferHandler &handler, uint32_t pipe_id, uint32_t crtc_id); - ~VirtualDisplay(); + ~VirtualDisplay() override; void InitVirtualDisplay(uint32_t width, uint32_t height) override; diff --git a/common/utils/hwcthread.cpp b/common/utils/hwcthread.cpp index fb00147..d5b05d1 100644 --- a/common/utils/hwcthread.cpp +++ b/common/utils/hwcthread.cpp @@ -36,34 +36,62 @@ bool HWCThread::InitWorker() { if (initialized_) return true; + initialized_ = true; + exit_ = false; thread_ = std::unique_ptr( new std::thread(&HWCThread::ProcessThread, this)); - initialized_ = true; + return true; } +void HWCThread::Resume() { + if (!suspended_ || exit_) + return; + + mutex_.lock(); + suspended_ = false; + mutex_.unlock(); + + cond_.notify_one(); +} + void HWCThread::Exit() { - ScopedSpinLock lock(spin_lock_); if (!initialized_) return; - thread_->join(); + mutex_.lock(); initialized_ = false; exit_ = true; + mutex_.unlock(); + + cond_.notify_one(); + thread_->join(); +} + +void HWCThread::HandleExit() { } void HWCThread::ProcessThread() { setpriority(PRIO_PROCESS, 0, priority_); prctl(PR_SET_NAME, name_.c_str()); + std::unique_lock lk(mutex_, std::defer_lock); while (true) { - spin_lock_.lock(); - if (exit_) + lk.lock(); + if (exit_) { + HandleExit(); return; - spin_lock_.unlock(); + } + if (suspended_) { + cond_.wait(lk); + } + lk.unlock(); HandleRoutine(); } } +void HWCThread::ConditionalSuspend() { + suspended_ = true; +} } diff --git a/common/utils/hwcthread.h b/common/utils/hwcthread.h index 7864069..51487a3 100644 --- a/common/utils/hwcthread.h +++ b/common/utils/hwcthread.h @@ -17,6 +17,7 @@ #ifndef HWC_THREAD_H_ #define HWC_THREAD_H_ +#include #include #include @@ -31,9 +32,12 @@ class HWCThread { bool InitWorker(); + void Resume(); void Exit(); + void ConditionalSuspend(); virtual void HandleRoutine() = 0; + virtual void HandleExit(); bool initialized_; @@ -42,8 +46,10 @@ class HWCThread { int priority_; std::string name_; - bool exit_; - SpinLock spin_lock_; + bool exit_ = false; + bool suspended_ = false; + std::mutex mutex_; + std::condition_variable cond_; std::unique_ptr thread_; }; diff --git a/public/spinlock.h b/public/spinlock.h index bc0005b..121c23e 100644 --- a/public/spinlock.h +++ b/public/spinlock.h @@ -18,6 +18,7 @@ #define SPIN_LOCK_H_ #include +#include namespace hwcomposer { @@ -40,14 +41,41 @@ class ScopedSpinLock { public: ScopedSpinLock(SpinLock& lock) : lock_(lock) { lock_.lock(); + locked_ = true; } ~ScopedSpinLock() { - lock_.unlock(); + Reset(); + } + + void Reset() { + if (locked_) { + lock_.unlock(); + locked_ = false; + } } private: SpinLock& lock_; + bool locked_; +}; + +class ScopedSpinLocks { + public: + ScopedSpinLocks(SpinLock& lock1, SpinLock& lock2) + : lock1_(lock1), lock2_(lock2) { + lock1_.lock(); + lock2_.lock(); + } + + ~ScopedSpinLocks() { + lock1_.unlock(); + lock2_.unlock(); + } + + private: + SpinLock& lock1_; + SpinLock& lock2_; }; } // namespace hwcomposer