diff options
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | hwcomposer.cpp | 30 | ||||
-rw-r--r-- | virtualcompositorworker.cpp | 175 | ||||
-rw-r--r-- | virtualcompositorworker.h | 56 |
4 files changed, 256 insertions, 6 deletions
@@ -52,6 +52,7 @@ LOCAL_SRC_FILES := \ glworker.cpp \ hwcomposer.cpp \ seperate_rects.cpp \ + virtualcompositorworker.cpp \ vsyncworker.cpp \ worker.cpp diff --git a/hwcomposer.cpp b/hwcomposer.cpp index 3035362..a7c9e43 100644 --- a/hwcomposer.cpp +++ b/hwcomposer.cpp @@ -20,6 +20,7 @@ #include "drm_hwcomposer.h" #include "drmresources.h" #include "importer.h" +#include "virtualcompositorworker.h" #include "vsyncworker.h" #include <stdlib.h> @@ -133,6 +134,7 @@ struct hwc_context_t { } ~hwc_context_t() { + virtual_compositor_worker.Exit(); delete importer; } @@ -145,6 +147,7 @@ struct hwc_context_t { const gralloc_module_t *gralloc; DummySwSyncTimeline dummy_timeline; bool use_framebuffer_target; + VirtualCompositorWorker virtual_compositor_worker; }; static native_handle_t *dup_buffer_handle(buffer_handle_t handle) { @@ -346,17 +349,22 @@ static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays, if (!display_contents[i]) continue; - DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i); - if (!crtc) { - ALOGE("No crtc for display %d", i); - return -ENODEV; + bool use_framebuffer_target = ctx->use_framebuffer_target; + if (i == HWC_DISPLAY_VIRTUAL) { + use_framebuffer_target = true; + } else { + DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i); + if (!crtc) { + ALOGE("No crtc for display %d", i); + return -ENODEV; + } } int num_layers = display_contents[i]->numHwLayers; for (int j = 0; j < num_layers; j++) { hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j]; - if (!ctx->use_framebuffer_target) { + if (!use_framebuffer_target) { if (layer->compositionType == HWC_FRAMEBUFFER) layer->compositionType = HWC_OVERLAY; } else { @@ -415,6 +423,11 @@ static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays, if (!sf_display_contents[i]) continue; + if (i == HWC_DISPLAY_VIRTUAL) { + ctx->virtual_compositor_worker.QueueComposite(dc); + continue; + } + std::ostringstream display_index_formatter; display_index_formatter << "retire fence for display " << i; std::string display_fence_description(display_index_formatter.str()); @@ -576,7 +589,7 @@ static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what, *value = 1000 * 1000 * 1000 / 60; break; case HWC_DISPLAY_TYPES_SUPPORTED: - *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL; + *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL | HWC_DISPLAY_VIRTUAL; break; } return 0; @@ -789,6 +802,11 @@ static int hwc_enumerate_displays(struct hwc_context_t *ctx) { } } + ret = ctx->virtual_compositor_worker.Init(); + if (ret) { + ALOGE("Failed to initialize virtual compositor worker"); + return ret; + } return 0; } 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); +} +} diff --git a/virtualcompositorworker.h b/virtualcompositorworker.h new file mode 100644 index 0000000..4a15f0c --- /dev/null +++ b/virtualcompositorworker.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef ANDROID_VIRTUAL_COMPOSITOR_WORKER_H_ +#define ANDROID_VIRTUAL_COMPOSITOR_WORKER_H_ + +#include "drm_hwcomposer.h" +#include "worker.h" + +#include <queue> + +namespace android { + +class VirtualCompositorWorker : public Worker { + public: + VirtualCompositorWorker(); + ~VirtualCompositorWorker(); + + int Init(); + void QueueComposite(hwc_display_contents_1_t *dc); + + protected: + virtual void Routine(); + + private: + struct VirtualComposition { + UniqueFd outbuf_acquire_fence; + std::vector<UniqueFd> layer_acquire_fences; + int release_timeline; + }; + + int CreateNextTimelineFence(); + int FinishComposition(int timeline); + void Compose(std::unique_ptr<VirtualComposition> composition); + + std::queue<std::unique_ptr<VirtualComposition>> composite_queue_; + int timeline_fd_; + int timeline_; + int timeline_current_; +}; +} + +#endif |