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 \
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 \
}
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;
}
class GpuDevice::DisplayManager : public HWCThread {
public:
DisplayManager();
- ~DisplayManager();
+ ~DisplayManager() override;
bool Init(uint32_t fd);
#include <hwclayer.h>
#include <hwctrace.h>
-#include "displayplanemanager.h"
-#include "nativesync.h"
-#include "overlaylayer.h"
+#include "displayqueue.h"
namespace hwcomposer {
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;
}
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;
}
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*/,
}
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<HwcLayer *> &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<NativeSync> sync_object(new NativeSync());
- if (!sync_object->Init()) {
- ETRACE("Failed to create sync object.");
- return false;
- }
-
- std::vector<OverlayLayer> layers;
- std::vector<HwcRect<int>> 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<VsyncCallback> callback,
// limitations under the License.
*/
-#ifndef INTERNAL_DISPLAY_H_
-#define INTERNAL_DISPLAY_H_
+#ifndef DISPLAY_H_
+#define DISPLAY_H_
#include "platformdefines.h"
-#include <mutex>
#include <stdint.h>
#include <xf86drmMode.h>
#include <nativedisplay.h>
#include <nativebufferhandler.h>
-#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;
public:
Display(uint32_t gpu_fd, NativeBufferHandler &handler, uint32_t pipe_id,
uint32_t crtc_id);
- ~Display();
+ ~Display() override;
bool Initialize() override;
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_;
bool is_connected_;
bool is_powered_off_;
float refresh_;
- ScopedFd out_fence_ = -1;
std::unique_ptr<PageFlipEventHandler> flip_handler_;
- std::unique_ptr<DisplayPlaneManager> display_plane_manager_;
- SpinLock spin_lock_;
- std::vector<OverlayLayer> previous_layers_;
- DisplayPlaneStateList previous_plane_state_;
+ std::unique_ptr<DisplayQueue> display_queue_;
};
} // namespace hwcomposer
-#endif // INTERNAL_DISPLAY_H_
+#endif // DISPLAY_H_
}
}
+#ifndef DISABLE_EXPLICIT_SYNC
fence.Close();
-
+#endif
if (ret) {
ETRACE("Failed to commit pset ret=%s\n", PRINTERROR());
return false;
--- /dev/null
+/*
+// 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 <hwcdefs.h>
+#include <hwclayer.h>
+#include <hwctrace.h>
+
+#include <nativebufferhandler.h>
+
+#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<HwcLayer*>& 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<DisplayQueueItem>().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
--- /dev/null
+/*
+// 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 <queue>
+
+#include "platformdefines.h"
+
+#include <drmscopedtypes.h>
+
+#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<HwcLayer*>& source_layers);
+ bool SetDpmsMode(uint32_t dpms_mode);
+
+ protected:
+ void HandleRoutine() override;
+ void HandleExit() override;
+
+ private:
+ struct DisplayQueueItem {
+ std::vector<OverlayLayer> layers_;
+ std::vector<HwcRect<int>> layers_rects_;
+ std::unique_ptr<NativeSync> 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<PageFlipEventHandler> flip_handler_;
+ std::unique_ptr<DisplayPlaneManager> display_plane_manager_;
+ SpinLock spin_lock_;
+ SpinLock display_queue_;
+ std::queue<DisplayQueueItem> queue_;
+ std::vector<OverlayLayer> previous_layers_;
+ DisplayPlaneStateList previous_plane_state_;
+ ScopedFd out_fence_ = -1;
+};
+
+} // namespace hwcomposer
+#endif // DISPLAY_QUEUE_H_
public:
Headless(uint32_t gpu_fd, NativeBufferHandler &handler, uint32_t pipe_id,
uint32_t crtc_id);
- ~Headless();
+ ~Headless() override;
bool Initialize() override;
class PageFlipEventHandler : public HWCThread {
public:
PageFlipEventHandler();
- ~PageFlipEventHandler();
+ ~PageFlipEventHandler() override;
void Init(float refresh, int fd, int pipe);
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;
if (initialized_)
return true;
+ initialized_ = true;
+ exit_ = false;
thread_ = std::unique_ptr<std::thread>(
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<std::mutex> 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;
+}
}
#ifndef HWC_THREAD_H_
#define HWC_THREAD_H_
+#include <condition_variable>
#include <thread>
#include <string>
bool InitWorker();
+ void Resume();
void Exit();
+ void ConditionalSuspend();
virtual void HandleRoutine() = 0;
+ virtual void HandleExit();
bool initialized_;
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<std::thread> thread_;
};
#define SPIN_LOCK_H_
#include <atomic>
+#include <hwctrace.h>
namespace hwcomposer {
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