aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPuneet Kumar <puneetster@google.com>2015-07-30 03:36:46 +0000
committerPuneet Kumar <puneetster@google.com>2015-07-30 03:36:46 +0000
commitd078e4cab78f81057cd25355199caba5a147342e (patch)
tree6bd39b93a08a71ce7cf5f392c4254e68671ad78e
parentabebc7a78fe8a4df6495c8e5064719dc92b04004 (diff)
downloaddrm_hwcomposer-d078e4cab78f81057cd25355199caba5a147342e.tar.gz
Revert "drm_hwcomposer: remove GLCompositor and the GLWorker thread"
This reverts commit abebc7a78fe8a4df6495c8e5064719dc92b04004. For now until we figure out a more stable solution for SF/hwc Change-Id: I7a505fc67873f943704e8b48db4167b9beca7691
-rw-r--r--Android.mk1
-rw-r--r--gl_compositor.cpp295
-rw-r--r--gl_compositor.h61
-rw-r--r--glworker.cpp192
-rw-r--r--glworker.h40
-rw-r--r--hwcomposer.cpp213
6 files changed, 801 insertions, 1 deletions
diff --git a/Android.mk b/Android.mk
index ccb230e..eadfe2b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -50,6 +50,7 @@ LOCAL_SRC_FILES := \
drmmode.cpp \
drmplane.cpp \
drmproperty.cpp \
+ gl_compositor.cpp \
glworker.cpp \
hwcomposer.cpp \
seperate_rects.cpp \
diff --git a/gl_compositor.cpp b/gl_compositor.cpp
new file mode 100644
index 0000000..0605c04
--- /dev/null
+++ b/gl_compositor.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "GLCompositor"
+
+#include <vector>
+
+#include <cutils/log.h>
+
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+
+#include <sync/sync.h>
+#include <sw_sync.h>
+
+#include "drm_hwcomposer.h"
+
+#include "gl_compositor.h"
+#include "glworker.h"
+
+namespace android {
+
+static const char *get_gl_error(void);
+static const char *get_egl_error(void);
+static bool has_extension(const char *extension, const char *extensions);
+
+template <typename T>
+int AllocResource(std::vector<T> &array) {
+ for (typename std::vector<T>::iterator it = array.begin(); it != array.end();
+ ++it) {
+ if (!it->is_some()) {
+ return std::distance(array.begin(), it);
+ }
+ }
+
+ array.push_back(T());
+ return array.size() - 1;
+}
+
+template <typename T>
+void FreeResource(std::vector<T> &array, int index) {
+ if (index == (int)array.size() - 1) {
+ array.pop_back();
+ } else if (index >= 0 && (unsigned)index < array.size()) {
+ array[index].Reset();
+ }
+}
+
+struct GLTarget {
+ sp<GraphicBuffer> fb;
+ bool forgotten;
+ unsigned composition_count;
+
+ GLTarget() : forgotten(true), composition_count(0) {
+ }
+
+ void Reset() {
+ fb.clear();
+ forgotten = true;
+ composition_count = 0;
+ }
+
+ bool is_some() const {
+ return fb != NULL;
+ }
+};
+
+struct GLCompositor::priv_data {
+ int current_target;
+ std::vector<GLTarget> targets;
+ std::vector<GLComposition *> compositions;
+
+ GLWorker worker;
+
+ priv_data() : current_target(-1) {
+ }
+};
+
+class GLComposition : public Composition {
+ public:
+ struct LayerData {
+ hwc_layer_1 layer;
+ hwc_drm_bo bo;
+ };
+
+ GLComposition(GLCompositor *owner, Importer *imp)
+ : compositor(owner), importer(imp), target_handle(-1), timeline_fd(-1) {
+ int ret = sw_sync_timeline_create();
+ if (ret < 0) {
+ ALOGE("Failed to create sw sync timeline %d", ret);
+ }
+ timeline_fd = ret;
+ }
+
+ virtual ~GLComposition() {
+ if (timeline_fd >= 0)
+ close(timeline_fd);
+
+ if (compositor == NULL) {
+ return;
+ }
+
+ // Removes this composition from the owning compositor automatically.
+ std::vector<GLComposition *> &compositions =
+ compositor->priv_->compositions;
+ std::vector<GLComposition *>::iterator it =
+ std::find(compositions.begin(), compositions.end(), this);
+ if (it != compositions.end()) {
+ compositions.erase(it);
+ }
+
+ GLTarget *target = &compositor->priv_->targets[target_handle];
+ target->composition_count--;
+ compositor->CheckAndDestroyTarget(target_handle);
+ }
+
+ virtual int AddLayer(int display, hwc_layer_1 *layer, hwc_drm_bo *bo) {
+ (void)display;
+ if (layer->compositionType != HWC_OVERLAY) {
+ ALOGE("Must add layers with compositionType == HWC_OVERLAY");
+ return 1;
+ }
+
+ if (layer->handle == 0) {
+ ALOGE("Must add layers with valid buffer handle");
+ return 1;
+ }
+
+ layer->releaseFenceFd = sw_sync_fence_create(
+ timeline_fd, "GLComposition release fence", layers.size() + 1);
+
+ layers.push_back(*layer);
+
+ return importer->ReleaseBuffer(bo);
+ }
+
+ virtual unsigned GetRemainingLayers(int display, unsigned num_needed) const {
+ (void)display;
+ return num_needed;
+ }
+
+ GLCompositor *compositor;
+ Importer *importer;
+ int target_handle;
+ int timeline_fd;
+ std::vector<hwc_layer_1> layers;
+};
+
+GLCompositor::GLCompositor() {
+ priv_ = new priv_data;
+}
+
+GLCompositor::~GLCompositor() {
+ for (std::vector<GLComposition *>::iterator it = priv_->compositions.end();
+ it != priv_->compositions.begin(); it = priv_->compositions.end()) {
+ --it;
+
+ // Prevents compositor from trying to erase itself
+ (*it)->compositor = NULL;
+ delete *it;
+ priv_->compositions.erase(it);
+ }
+
+ delete priv_;
+}
+
+int GLCompositor::Init() {
+ return priv_->worker.Init();
+}
+
+Targeting *GLCompositor::targeting() {
+ return (Targeting *)this;
+}
+
+int GLCompositor::CreateTarget(sp<GraphicBuffer> &buffer) {
+ int ret;
+
+ int target_handle = AllocResource(priv_->targets);
+ GLTarget *target = &priv_->targets[target_handle];
+
+ target->fb = buffer;
+ target->forgotten = false;
+
+ return target_handle;
+}
+
+void GLCompositor::SetTarget(int target_handle) {
+ if (target_handle >= 0 && (unsigned)target_handle < priv_->targets.size()) {
+ GLTarget *target = &priv_->targets[target_handle];
+ if (target->is_some()) {
+ priv_->current_target = target_handle;
+ return;
+ }
+ }
+
+ priv_->current_target = -1;
+}
+
+void GLCompositor::ForgetTarget(int target_handle) {
+ if (target_handle >= 0 && (unsigned)target_handle < priv_->targets.size()) {
+ if (target_handle == priv_->current_target) {
+ priv_->current_target = -1;
+ }
+
+ GLTarget *target = &priv_->targets[target_handle];
+ if (target->is_some()) {
+ target->forgotten = true;
+ CheckAndDestroyTarget(target_handle);
+ return;
+ }
+ }
+
+ ALOGE("Failed to forget target because of invalid handle");
+}
+
+void GLCompositor::CheckAndDestroyTarget(int target_handle) {
+ GLTarget *target = &priv_->targets[target_handle];
+ if (target->composition_count == 0 && target->forgotten) {
+ FreeResource(priv_->targets, target_handle);
+ }
+}
+
+Composition *GLCompositor::CreateComposition(Importer *importer) {
+ if (priv_->current_target >= 0 &&
+ (unsigned)priv_->current_target < priv_->targets.size()) {
+ GLTarget *target = &priv_->targets[priv_->current_target];
+ if (target->is_some()) {
+ GLComposition *composition = new GLComposition(this, importer);
+ composition->target_handle = priv_->current_target;
+ target->composition_count++;
+ priv_->compositions.push_back(composition);
+ return composition;
+ }
+ }
+
+ ALOGE("Failed to create composition because of invalid target handle %d",
+ priv_->current_target);
+
+ return NULL;
+}
+
+int GLCompositor::QueueComposition(Composition *composition) {
+ if (composition) {
+ GLComposition *gl_composition = (GLComposition *)composition;
+ int ret = DoComposition(gl_composition);
+ gl_composition->timeline_fd = -1;
+ delete composition;
+ return ret;
+ }
+
+ ALOGE("Failed to queue composition because of invalid composition handle");
+
+ return -EINVAL;
+}
+
+int GLCompositor::Composite() {
+ return 0;
+}
+
+int GLCompositor::DoComposition(GLComposition *composition) {
+ ATRACE_CALL();
+ int ret = 0;
+
+ GLTarget *target = &priv_->targets[composition->target_handle];
+ GLWorker::Work work;
+ work.layers = composition->layers.data();
+ work.num_layers = composition->layers.size();
+ work.timeline_fd = composition->timeline_fd;
+ work.framebuffer = target->fb;
+
+ ret = priv_->worker.DoWork(&work);
+
+ if (work.timeline_fd >= 0) {
+ sw_sync_timeline_inc(work.timeline_fd, work.num_layers + 1);
+ close(work.timeline_fd);
+ }
+
+ return ret;
+}
+
+} // namespace android
diff --git a/gl_compositor.h b/gl_compositor.h
new file mode 100644
index 0000000..450ca67
--- /dev/null
+++ b/gl_compositor.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <stdint.h>
+#include "compositor.h"
+
+struct hwc_layer_1;
+struct hwc_import_context;
+
+namespace android {
+
+class GLComposition;
+
+class GLCompositor : public Compositor, public Targeting {
+ public:
+ GLCompositor();
+ virtual ~GLCompositor();
+
+ virtual int Init();
+ virtual Targeting *targeting();
+ virtual int CreateTarget(sp<android::GraphicBuffer> &buffer);
+ virtual void SetTarget(int target);
+ virtual void ForgetTarget(int target);
+ virtual Composition *CreateComposition(Importer *importer);
+ virtual int QueueComposition(Composition *composition);
+ virtual int Composite();
+
+ private:
+ struct priv_data;
+ struct texture_from_handle;
+
+ struct priv_data *priv_;
+
+ int BeginContext();
+ int EndContext();
+ int GenerateShaders();
+ int DoComposition(GLComposition *composition);
+ int DoFenceWait(int acquireFenceFd);
+ int CreateTextureFromHandle(buffer_handle_t handle,
+ struct texture_from_handle *tex);
+ void DestroyTextureFromHandle(const struct texture_from_handle &tex);
+ void CheckAndDestroyTarget(int target_handle);
+
+ friend GLComposition;
+};
+
+} // namespace android
diff --git a/glworker.cpp b/glworker.cpp
index df6a8f2..e0d337b 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -23,6 +23,9 @@
#include <sys/resource.h>
+#include <sync/sync.h>
+#include <sw_sync.h>
+
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
@@ -707,4 +710,193 @@ int GLWorkerCompositor::CompositeAndFinish(hwc_layer_1 *layers,
return ret;
}
+int GLWorker::DoComposition(GLWorkerCompositor &compositor, Work *work) {
+ int ret =
+ compositor.Composite(work->layers, work->num_layers, work->framebuffer);
+
+ int timeline_fd = work->timeline_fd;
+ work->timeline_fd = -1;
+
+ if (ret) {
+ worker_ret_ = ret;
+ glFinish();
+ sw_sync_timeline_inc(timeline_fd, work->num_layers);
+ close(timeline_fd);
+ return pthread_cond_signal(&work_done_cond_);
+ }
+
+ unsigned timeline_count = work->num_layers + 1;
+ worker_ret_ = sw_sync_fence_create(timeline_fd, "GLComposition done fence",
+ timeline_count);
+ ret = pthread_cond_signal(&work_done_cond_);
+
+ glFinish();
+
+ sw_sync_timeline_inc(timeline_fd, timeline_count);
+ close(timeline_fd);
+
+ return ret;
+}
+
+GLWorker::GLWorker() : initialized_(false) {
+}
+
+GLWorker::~GLWorker() {
+ if (!initialized_)
+ return;
+
+ if (SignalWorker(NULL, true) != 0 || pthread_join(thread_, NULL) != 0)
+ pthread_kill(thread_, SIGTERM);
+
+ pthread_cond_destroy(&work_ready_cond_);
+ pthread_cond_destroy(&work_done_cond_);
+ pthread_mutex_destroy(&lock_);
+}
+
+#define TRY(x, n, g) \
+ ret = x; \
+ if (ret) { \
+ ALOGE("Failed to " n " %d", ret); \
+ g; \
+ }
+
+#define TRY_RETURN(x, n) TRY(x, n, return ret)
+
+int GLWorker::Init() {
+ int ret = 0;
+
+ worker_work_ = NULL;
+ worker_exit_ = false;
+ worker_ret_ = -1;
+
+ ret = pthread_cond_init(&work_ready_cond_, NULL);
+ if (ret) {
+ ALOGE("Failed to int GLThread condition %d", ret);
+ return ret;
+ }
+
+ ret = pthread_cond_init(&work_done_cond_, NULL);
+ if (ret) {
+ ALOGE("Failed to int GLThread condition %d", ret);
+ pthread_cond_destroy(&work_ready_cond_);
+ return ret;
+ }
+
+ ret = pthread_mutex_init(&lock_, NULL);
+ if (ret) {
+ ALOGE("Failed to init GLThread lock %d", ret);
+ pthread_cond_destroy(&work_ready_cond_);
+ pthread_cond_destroy(&work_done_cond_);
+ return ret;
+ }
+
+ ret = pthread_create(&thread_, NULL, StartRoutine, this);
+ if (ret) {
+ ALOGE("Failed to create GLThread %d", ret);
+ pthread_cond_destroy(&work_ready_cond_);
+ pthread_cond_destroy(&work_done_cond_);
+ pthread_mutex_destroy(&lock_);
+ return ret;
+ }
+
+ initialized_ = true;
+
+ TRY_RETURN(pthread_mutex_lock(&lock_), "lock GLThread");
+
+ while (!worker_exit_ && worker_ret_ != 0)
+ TRY(pthread_cond_wait(&work_done_cond_, &lock_), "wait on condition",
+ goto out_unlock);
+
+ ret = worker_ret_;
+
+out_unlock:
+ int unlock_ret = pthread_mutex_unlock(&lock_);
+ if (unlock_ret) {
+ ret = unlock_ret;
+ ALOGE("Failed to unlock GLThread %d", unlock_ret);
+ }
+ return ret;
+}
+
+int GLWorker::SignalWorker(Work *work, bool worker_exit) {
+ int ret = 0;
+ if (worker_exit_)
+ return -EINVAL;
+ TRY_RETURN(pthread_mutex_lock(&lock_), "lock GLThread");
+ worker_work_ = work;
+ worker_exit_ = worker_exit;
+ ret = pthread_cond_signal(&work_ready_cond_);
+ if (ret) {
+ ALOGE("Failed to signal GLThread caller %d", ret);
+ pthread_mutex_unlock(&lock_);
+ return ret;
+ }
+ ret = pthread_cond_wait(&work_done_cond_, &lock_);
+ if (ret) {
+ ALOGE("Failed to wait on GLThread %d", ret);
+ pthread_mutex_unlock(&lock_);
+ return ret;
+ }
+
+ ret = worker_ret_;
+ if (ret) {
+ pthread_mutex_unlock(&lock_);
+ return ret;
+ }
+ TRY_RETURN(pthread_mutex_unlock(&lock_), "unlock GLThread");
+ return ret;
+}
+
+int GLWorker::DoWork(Work *work) {
+ return SignalWorker(work, false);
+}
+
+void GLWorker::WorkerRoutine() {
+ int ret = 0;
+
+ TRY(pthread_mutex_lock(&lock_), "lock GLThread", return );
+
+ GLWorkerCompositor compositor;
+
+ TRY(compositor.Init(), "initialize GL", goto out_signal_done);
+
+ worker_ret_ = 0;
+ TRY(pthread_cond_signal(&work_done_cond_), "signal GLThread caller",
+ goto out_signal_done);
+
+ while (true) {
+ while (worker_work_ == NULL && !worker_exit_)
+ TRY(pthread_cond_wait(&work_ready_cond_, &lock_), "wait on condition",
+ goto out_signal_done);
+
+ if (worker_exit_) {
+ ret = 0;
+ break;
+ }
+
+ ret = DoComposition(compositor, worker_work_);
+
+ worker_work_ = NULL;
+ if (ret) {
+ break;
+ }
+ }
+
+out_signal_done:
+ worker_exit_ = true;
+ worker_ret_ = ret;
+ TRY(pthread_cond_signal(&work_done_cond_), "signal GLThread caller",
+ goto out_unlock);
+out_unlock:
+ TRY(pthread_mutex_unlock(&lock_), "unlock GLThread", return );
+}
+
+/* static */
+void *GLWorker::StartRoutine(void *arg) {
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+ GLWorker *worker = (GLWorker *)arg;
+ worker->WorkerRoutine();
+ return NULL;
+}
+
} // namespace android
diff --git a/glworker.h b/glworker.h
index 8252b62..9550cbe 100644
--- a/glworker.h
+++ b/glworker.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GL_WORKER_H_
#define ANDROID_GL_WORKER_H_
+#include <pthread.h>
+
#include <memory>
#include <vector>
@@ -96,6 +98,44 @@ class GLWorkerCompositor {
std::vector<AutoGLProgram> blend_programs_;
AutoGLBuffer vertex_buffer_;
};
+
+class GLWorker {
+ public:
+ struct Work {
+ hwc_layer_1 *layers;
+ size_t num_layers;
+ int timeline_fd;
+ sp<GraphicBuffer> framebuffer;
+
+ Work() = default;
+ Work(const Work &rhs) = delete;
+ };
+
+ GLWorker();
+ ~GLWorker();
+
+ int Init();
+
+ int DoWork(Work *work);
+
+ private:
+ bool initialized_;
+ pthread_t thread_;
+ pthread_mutex_t lock_;
+ pthread_cond_t work_ready_cond_;
+ pthread_cond_t work_done_cond_;
+ Work *worker_work_;
+ bool work_ready_;
+ bool worker_exit_;
+ int worker_ret_;
+
+ void WorkerRoutine();
+ int DoComposition(GLWorkerCompositor &compositor, Work *work);
+
+ int SignalWorker(Work *work, bool worker_exit);
+
+ static void *StartRoutine(void *arg);
+};
}
#endif
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index b4b1a50..18f6921 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -19,6 +19,7 @@
#include "drm_hwcomposer.h"
#include "drmresources.h"
+#include "gl_compositor.h"
#include "importer.h"
#include "vsyncworker.h"
@@ -37,6 +38,10 @@
#include <cutils/properties.h>
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
+#include <sw_sync.h>
+#include <sync/sync.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
#include <utils/Trace.h>
#define UM_PER_INCH 25400
@@ -44,6 +49,80 @@
namespace android {
+struct hwc_drm_display_framebuffer {
+ hwc_drm_display_framebuffer() : release_fence_fd_(-1) {
+ }
+
+ ~hwc_drm_display_framebuffer() {
+ if (release_fence_fd() >= 0)
+ close(release_fence_fd());
+ }
+
+ bool is_valid() {
+ return buffer_ != NULL;
+ }
+
+ sp<GraphicBuffer> buffer() {
+ return buffer_;
+ }
+
+ int release_fence_fd() {
+ return release_fence_fd_;
+ }
+
+ void set_release_fence_fd(int fd) {
+ if (release_fence_fd_ >= 0)
+ close(release_fence_fd_);
+ release_fence_fd_ = fd;
+ }
+
+ bool Allocate(uint32_t w, uint32_t h) {
+ if (is_valid()) {
+ if (buffer_->getWidth() == w && buffer_->getHeight() == h)
+ return true;
+
+ if (release_fence_fd_ >= 0) {
+ if (sync_wait(release_fence_fd_, -1) != 0) {
+ return false;
+ }
+ }
+ Clear();
+ }
+ buffer_ = new GraphicBuffer(w, h, android::PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_COMPOSER);
+ release_fence_fd_ = -1;
+ return is_valid();
+ }
+
+ void Clear() {
+ if (!is_valid())
+ return;
+
+ if (release_fence_fd_ >= 0) {
+ close(release_fence_fd_);
+ release_fence_fd_ = -1;
+ }
+
+ buffer_.clear();
+ }
+
+ int WaitReleased(int timeout_milliseconds) {
+ if (!is_valid())
+ return 0;
+ if (release_fence_fd_ < 0)
+ return 0;
+
+ int ret = sync_wait(release_fence_fd_, timeout_milliseconds);
+ return ret;
+ }
+
+ private:
+ sp<GraphicBuffer> buffer_;
+ int release_fence_fd_;
+};
+
+
typedef struct hwc_drm_display {
struct hwc_context_t *ctx;
int display;
@@ -51,6 +130,9 @@ typedef struct hwc_drm_display {
std::vector<uint32_t> config_ids;
VSyncWorker vsync_worker;
+
+ hwc_drm_display_framebuffer fb_chain[HWC_FB_BUFFERS];
+ int fb_idx;
} hwc_drm_display_t;
struct hwc_context_t {
@@ -71,6 +153,7 @@ struct hwc_context_t {
DisplayMap displays;
DrmResources drm;
Importer *importer;
+ GLCompositor pre_compositor;
};
static void hwc_dump(struct hwc_composer_device_1* dev, char *buff,
@@ -197,9 +280,12 @@ static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
}
unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
+ bool use_pre_compositor = false;
if (num_layers > num_planes) {
- ALOGE("Can not composite %u with only %u planes", num_layers, num_planes);
+ use_pre_compositor = true;
+ // Reserve one of the planes for the result of the pre compositor.
+ num_planes--;
}
for (j = 0; num_planes && j < (int)num_dc_layers; ++j) {
@@ -219,6 +305,123 @@ static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
--num_planes;
}
+
+ int last_comp_layer = j;
+
+ if (use_pre_compositor) {
+ hwc_drm_display_t *hd = &ctx->displays[i];
+ struct hwc_drm_display_framebuffer *fb = &hd->fb_chain[hd->fb_idx];
+ ret = fb->WaitReleased(-1);
+ if (ret) {
+ ALOGE("Failed to wait for framebuffer %d", ret);
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return ret;
+ }
+
+ DrmConnector *connector = ctx->drm.GetConnectorForDisplay(i);
+ if (!connector) {
+ ALOGE("No connector for display %d", i);
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return -ENODEV;
+ }
+
+ const DrmMode &mode = connector->active_mode();
+ if (!fb->Allocate(mode.h_display(), mode.v_display())) {
+ ALOGE("Failed to allocate framebuffer with size %dx%d",
+ mode.h_display(), mode.v_display());
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return -EINVAL;
+ }
+
+ sp<GraphicBuffer> fb_buffer = fb->buffer();
+ if (fb_buffer == NULL) {
+ ALOGE("Framebuffer is NULL");
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return -EINVAL;
+ }
+
+ Targeting *targeting = ctx->pre_compositor.targeting();
+ if (targeting == NULL) {
+ ALOGE("Pre-compositor does not support targeting");
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return -EINVAL;
+ }
+
+ int target = targeting->CreateTarget(fb_buffer);
+ targeting->SetTarget(target);
+
+ Composition *pre_composition = ctx->pre_compositor.CreateComposition(ctx->importer);
+ if (pre_composition == NULL) {
+ ALOGE("Failed to create pre-composition");
+ targeting->ForgetTarget(target);
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return -EINVAL;
+ }
+
+ for (j = last_comp_layer; j < (int)num_dc_layers; ++j) {
+ hwc_layer_1_t *layer = &dc->hwLayers[j];
+ if (layer->flags & HWC_SKIP_LAYER)
+ continue;
+ if (layer->compositionType != HWC_OVERLAY)
+ continue;
+ ret = hwc_add_layer(i, ctx, layer, pre_composition);
+ if (ret) {
+ ALOGE("Add layer failed %d", ret);
+ delete pre_composition;
+ targeting->ForgetTarget(target);
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return ret;
+ }
+ }
+
+ ret = ctx->pre_compositor.QueueComposition(pre_composition);
+ pre_composition = NULL;
+
+ targeting->ForgetTarget(target);
+ if (ret < 0 && ret != -EALREADY) {
+ ALOGE("Pre-composition failed %d", ret);
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return ret;
+ }
+
+ for (j = last_comp_layer; j < (int)num_dc_layers; ++j) {
+ hwc_layer_1_t *layer = &dc->hwLayers[j];
+ if (layer->flags & HWC_SKIP_LAYER)
+ continue;
+ if (layer->compositionType != HWC_OVERLAY)
+ continue;
+ layer->acquireFenceFd = -1;
+ }
+
+ hwc_layer_1_t composite_layer;
+ hwc_rect_t visible_rect;
+ memset(&composite_layer, 0, sizeof(composite_layer));
+ memset(&visible_rect, 0, sizeof(visible_rect));
+
+ composite_layer.compositionType = HWC_OVERLAY;
+ composite_layer.handle = fb_buffer->getNativeBuffer()->handle;
+ composite_layer.sourceCropf.right = composite_layer.displayFrame.right =
+ visible_rect.right = fb_buffer->getWidth();
+ composite_layer.sourceCropf.bottom = composite_layer.displayFrame.bottom =
+ visible_rect.bottom = fb_buffer->getHeight();
+ composite_layer.visibleRegionScreen.numRects = 1;
+ composite_layer.visibleRegionScreen.rects = &visible_rect;
+ composite_layer.acquireFenceFd = ret == -EALREADY ? -1 : ret;
+ // A known invalid fd in case AddLayer does not modify this field.
+ composite_layer.releaseFenceFd = -1;
+ composite_layer.planeAlpha = 0xff;
+
+ ret = hwc_add_layer(i, ctx, &composite_layer, composition);
+ if (ret) {
+ ALOGE("Add layer failed %d", ret);
+ hwc_set_cleanup(num_displays, display_contents, composition);
+ return ret;
+ }
+ hwc_add_layer_to_retire_fence(&composite_layer, dc);
+
+ fb->set_release_fence_fd(composite_layer.releaseFenceFd);
+ hd->fb_idx = (hd->fb_idx + 1) % HWC_FB_BUFFERS;
+ }
}
ret = ctx->drm.compositor()->QueueComposition(composition);
@@ -459,6 +662,7 @@ static int hwc_initialize_display(struct hwc_context_t *ctx, int display) {
hwc_drm_display_t *hd = &ctx->displays[display];
hd->ctx = ctx;
hd->display = display;
+ hd->fb_idx = 0;
int ret = hwc_set_initial_config(hd);
if (ret) {
@@ -509,6 +713,13 @@ static int hwc_device_open(const struct hw_module_t *module, const char *name,
return ret;
}
+ ret = ctx->pre_compositor.Init();
+ if (ret) {
+ ALOGE("Can't initialize OpenGL Compositor object %d", ret);
+ delete ctx;
+ return ret;
+ }
+
ctx->importer = Importer::CreateInstance(&ctx->drm);
if (!ctx->importer) {
ALOGE("Failed to create importer instance");