aboutsummaryrefslogtreecommitdiff
path: root/virtualcompositorworker.cpp
diff options
context:
space:
mode:
authorHaixia Shi <hshi@chromium.org>2015-10-05 14:35:09 -0700
committerHaixia Shi <hshi@chromium.org>2015-10-07 16:03:10 -0700
commitd21f528156b17c9e069bfb4e215d7e399c94795b (patch)
tree3774d9aa41472d237df92583a07feefcbae47ba6 /virtualcompositorworker.cpp
parentc9d98e57d47177b8ce1b5eff8e8f490e9bdbc16f (diff)
downloaddrm_hwcomposer-marshmallow-dr-dev.tar.gz
drm_hwcomposer: support virtual displaysmarshmallow-dr-dev
Virtual display support is mandatory for HWC version 1.4. As a minimal implementation, we use frambuffer target and let SF take care of GLES composition. We still need to handle the acquire and release fences for both the virtual display and all layers in a separate worker thread. BUG=24609829 TEST=screen casting to chromecast Change-Id: Idb962f4b5bb852c9ec9ebcaa1679a653c01737fb
Diffstat (limited to 'virtualcompositorworker.cpp')
-rw-r--r--virtualcompositorworker.cpp175
1 files changed, 175 insertions, 0 deletions
diff --git a/virtualcompositorworker.cpp b/virtualcompositorworker.cpp
new file mode 100644
index 0000000..e7acef0
--- /dev/null
+++ b/virtualcompositorworker.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-virtual-compositor-worker"
+
+#include "virtualcompositorworker.h"
+#include "worker.h"
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <cutils/log.h>
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+#include <sched.h>
+#include <sw_sync.h>
+#include <sync/sync.h>
+
+namespace android {
+
+static const int kMaxQueueDepth = 3;
+static const int kAcquireWaitTimeoutMs = 50;
+
+VirtualCompositorWorker::VirtualCompositorWorker()
+ : Worker("virtual-compositor", HAL_PRIORITY_URGENT_DISPLAY)
+ , timeline_fd_(-1)
+ , timeline_(0)
+ , timeline_current_(0) {
+}
+
+VirtualCompositorWorker::~VirtualCompositorWorker() {
+ if (timeline_fd_ >= 0) {
+ FinishComposition(timeline_);
+ close(timeline_fd_);
+ timeline_fd_ = -1;
+ }
+}
+
+int VirtualCompositorWorker::Init() {
+ int ret = sw_sync_timeline_create();
+ if (ret < 0) {
+ ALOGE("Failed to create sw sync timeline %d", ret);
+ return ret;
+ }
+ timeline_fd_ = ret;
+ return InitWorker();
+}
+
+void VirtualCompositorWorker::QueueComposite(hwc_display_contents_1_t *dc) {
+ std::unique_ptr<VirtualComposition> composition(new VirtualComposition);
+
+ composition->outbuf_acquire_fence.Set(dc->outbufAcquireFenceFd);
+ dc->outbufAcquireFenceFd = -1;
+ if (dc->retireFenceFd >= 0)
+ close(dc->retireFenceFd);
+ dc->retireFenceFd = CreateNextTimelineFence();
+
+ for (size_t i = 0; i < dc->numHwLayers; ++i) {
+ hwc_layer_1_t *layer = &dc->hwLayers[i];
+ if (layer->flags & HWC_SKIP_LAYER)
+ continue;
+ composition->layer_acquire_fences.emplace_back(layer->acquireFenceFd);
+ layer->acquireFenceFd = -1;
+ if (layer->releaseFenceFd >= 0)
+ close(layer->releaseFenceFd);
+ layer->releaseFenceFd = CreateNextTimelineFence();
+ }
+
+ composition->release_timeline = timeline_;
+
+ Lock();
+ while (composite_queue_.size() >= kMaxQueueDepth) {
+ Unlock();
+ sched_yield();
+ Lock();
+ }
+
+ composite_queue_.push(std::move(composition));
+ SignalLocked();
+ Unlock();
+}
+
+void VirtualCompositorWorker::Routine() {
+ int ret = Lock();
+ if (ret) {
+ ALOGE("Failed to lock worker, %d", ret);
+ return;
+ }
+
+ int wait_ret = 0;
+ if (composite_queue_.empty()) {
+ wait_ret = WaitForSignalOrExitLocked();
+ }
+
+ std::unique_ptr<VirtualComposition> composition;
+ if (!composite_queue_.empty()) {
+ composition = std::move(composite_queue_.front());
+ composite_queue_.pop();
+ }
+
+ ret = Unlock();
+ if (ret) {
+ ALOGE("Failed to unlock worker, %d", ret);
+ return;
+ }
+
+ if (wait_ret == -EINTR) {
+ return;
+ } else if (wait_ret) {
+ ALOGE("Failed to wait for signal, %d", wait_ret);
+ return;
+ }
+
+ Compose(std::move(composition));
+}
+
+int VirtualCompositorWorker::CreateNextTimelineFence() {
+ ++timeline_;
+ return sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
+}
+
+int VirtualCompositorWorker::FinishComposition(int point) {
+ int timeline_increase = point - timeline_current_;
+ if (timeline_increase <= 0)
+ return 0;
+ int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
+ if (ret)
+ ALOGE("Failed to increment sync timeline %d", ret);
+ else
+ timeline_current_ = point;
+ return ret;
+}
+
+void VirtualCompositorWorker::Compose(
+ std::unique_ptr<VirtualComposition> composition) {
+ if (!composition.get())
+ return;
+
+ int ret;
+ int outbuf_acquire_fence = composition->outbuf_acquire_fence.get();
+ if (outbuf_acquire_fence >= 0) {
+ ret = sync_wait(outbuf_acquire_fence, kAcquireWaitTimeoutMs);
+ if (ret) {
+ ALOGE("Failed to wait for acquire %d/%d", outbuf_acquire_fence, ret);
+ return;
+ }
+ composition->outbuf_acquire_fence.Close();
+ }
+ for (size_t i = 0; i < composition->layer_acquire_fences.size(); ++i) {
+ int layer_acquire_fence = composition->layer_acquire_fences[i].get();
+ if (layer_acquire_fence >= 0) {
+ ret = sync_wait(layer_acquire_fence, kAcquireWaitTimeoutMs);
+ if (ret) {
+ ALOGE("Failed to wait for acquire %d/%d", layer_acquire_fence, ret);
+ return;
+ }
+ composition->layer_acquire_fences[i].Close();
+ }
+ }
+ FinishComposition(composition->release_timeline);
+}
+}