Revert "Revert "drm_hwcomposer: have DrmDisplayCompositor do its own OpenGL composition""
This reverts commit cbe9c01336e23a63259db65d22d63d6a697b8813.
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 805fd26..f4e8d9d 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -63,26 +63,9 @@
return 0;
}
-unsigned DrmComposition::GetRemainingLayers(int display,
+unsigned DrmComposition::GetRemainingLayers(int /*display*/,
unsigned num_needed) const {
- DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
- if (!crtc) {
- ALOGE("Failed to find crtc for display %d", display);
- return 0;
- }
-
- unsigned num_planes = 0;
- for (std::vector<DrmPlane *>::const_iterator iter = primary_planes_.begin();
- iter != primary_planes_.end(); ++iter) {
- if ((*iter)->GetCrtcSupported(*crtc))
- ++num_planes;
- }
- for (std::vector<DrmPlane *>::const_iterator iter = overlay_planes_.begin();
- iter != overlay_planes_.end(); ++iter) {
- if ((*iter)->GetCrtcSupported(*crtc))
- ++num_planes;
- }
- return std::min(num_planes, num_needed);
+ return num_needed;
}
int DrmComposition::AddLayer(int display, hwc_layer_1_t *layer,
@@ -111,10 +94,6 @@
break;
}
}
- if (!plane) {
- ALOGE("Failed to find plane for display %d", display);
- return -ENOENT;
- }
return composition_map_[display]->AddLayer(layer, bo, crtc, plane);
}
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index cce1d56..21a9c2a 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -112,6 +112,28 @@
return 0;
}
+int DrmDisplayComposition::AddLayer(hwc_layer_1_t *layer, DrmCrtc *crtc,
+ DrmPlane *plane) {
+ if (layer->transform != 0)
+ return -EINVAL;
+
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
+ return -EINVAL;
+
+ hwc_drm_bo_t bo;
+ int ret = importer_->ImportBuffer(layer->handle, &bo);
+ if (ret) {
+ ALOGE("Failed to import handle of layer %d", ret);
+ return ret;
+ }
+
+ ret = AddLayer(layer, &bo, crtc, plane);
+ if (ret)
+ importer_->ReleaseBuffer(&bo);
+
+ return ret;
+}
+
int DrmDisplayComposition::AddDpmsMode(uint32_t dpms_mode) {
if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
return -EINVAL;
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index 1df8dee..9c51078 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -56,6 +56,9 @@
int AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo, DrmCrtc *crtc,
DrmPlane *plane);
+ // Like the AddLayer that accepts a hwc_drm_bo_t, but uses Importer to import
+ // the layer->handle itself.
+ int AddLayer(hwc_layer_1_t *layer, DrmCrtc *crtc, DrmPlane *plane);
int AddPlaneDisable(DrmPlane *plane);
int AddDpmsMode(uint32_t dpms_mode);
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index e0d808f..7f43503 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -21,7 +21,9 @@
#include "drmcrtc.h"
#include "drmplane.h"
#include "drmresources.h"
+#include "glworker.h"
+#include <algorithm>
#include <pthread.h>
#include <sstream>
#include <stdlib.h>
@@ -42,6 +44,7 @@
frame_no_(0),
initialized_(false),
active_(false),
+ framebuffer_index_(0),
dump_frames_composited_(0),
dump_last_timestamp_ns_(0) {
struct timespec ts;
@@ -132,16 +135,132 @@
return 0;
}
+static bool drm_composition_layer_has_plane(
+ const DrmCompositionLayer_t &comp_layer) {
+ if (comp_layer.plane != NULL)
+ if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
+ comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
+ return true;
+ return false;
+}
+
+static bool drm_composition_layer_has_no_plane(
+ const DrmCompositionLayer_t &comp_layer) {
+ return comp_layer.plane == NULL;
+}
+
+int DrmDisplayCompositor::ApplyPreComposite(
+ DrmDisplayComposition *display_comp) {
+ int ret = 0;
+ DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
+
+ auto last_layer = find_if(layers->rbegin(), layers->rend(),
+ drm_composition_layer_has_plane);
+ if (last_layer == layers->rend()) {
+ ALOGE("Frame has no overlays");
+ return -EINVAL;
+ }
+
+ DrmCompositionLayer_t &comp_layer = *last_layer;
+ DrmPlane *stolen_plane = NULL;
+ std::swap(stolen_plane, comp_layer.plane);
+
+ DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
+ if (connector == NULL) {
+ ALOGE("Failed to determine display mode: no connector for display %d",
+ display_);
+ return -ENODEV;
+ }
+
+ const DrmMode &mode = connector->active_mode();
+ DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
+ ret = fb.WaitReleased(-1);
+ if (ret) {
+ ALOGE("Failed to wait for framebuffer release %d", ret);
+ return ret;
+ }
+ fb.set_release_fence_fd(-1);
+ if (!fb.Allocate(mode.h_display(), mode.v_display())) {
+ ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
+ mode.v_display());
+ return -ENOMEM;
+ }
+
+ std::vector<hwc_layer_1_t> pre_comp_layers;
+ for (const auto &comp_layer : *layers)
+ if (comp_layer.plane == NULL)
+ pre_comp_layers.push_back(comp_layer.layer);
+
+ if (!pre_compositor_) {
+ pre_compositor_.reset(new GLWorkerCompositor());
+ ret = pre_compositor_->Init();
+ if (ret) {
+ ALOGE("Failed to initialize OpenGL compositor %d", ret);
+ return ret;
+ }
+ }
+ ret = pre_compositor_->CompositeAndFinish(
+ pre_comp_layers.data(), pre_comp_layers.size(), fb.buffer());
+ if (ret) {
+ ALOGE("Failed to composite layers");
+ return ret;
+ }
+
+ layers->erase(std::remove_if(layers->begin(), layers->end(),
+ drm_composition_layer_has_no_plane),
+ layers->end());
+
+ hwc_layer_1_t pre_comp_output_layer;
+ memset(&pre_comp_output_layer, 0, sizeof(pre_comp_output_layer));
+ pre_comp_output_layer.compositionType = HWC_OVERLAY;
+ pre_comp_output_layer.handle = fb.buffer()->handle;
+ pre_comp_output_layer.acquireFenceFd = -1;
+ pre_comp_output_layer.releaseFenceFd = -1;
+ pre_comp_output_layer.planeAlpha = 0xff;
+ pre_comp_output_layer.visibleRegionScreen.numRects = 1;
+ pre_comp_output_layer.visibleRegionScreen.rects =
+ &pre_comp_output_layer.displayFrame;
+ pre_comp_output_layer.sourceCropf.top =
+ pre_comp_output_layer.displayFrame.top = 0;
+ pre_comp_output_layer.sourceCropf.left =
+ pre_comp_output_layer.displayFrame.left = 0;
+ pre_comp_output_layer.sourceCropf.right =
+ pre_comp_output_layer.displayFrame.right = fb.buffer()->getWidth();
+ pre_comp_output_layer.sourceCropf.bottom =
+ pre_comp_output_layer.displayFrame.bottom = fb.buffer()->getHeight();
+
+ ret = display_comp->AddLayer(&pre_comp_output_layer,
+ drm_->GetCrtcForDisplay(display_), stolen_plane);
+ if (ret) {
+ ALOGE("Failed to add composited layer %d", ret);
+ return ret;
+ }
+
+ fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
+ framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
+
+ return ret;
+}
+
int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
int ret = 0;
+ DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
+ bool use_pre_comp = std::any_of(layers->begin(), layers->end(),
+ drm_composition_layer_has_no_plane);
+
+ if (use_pre_comp) {
+ ret = ApplyPreComposite(display_comp);
+ if (ret)
+ return ret;
+ }
+
drmModePropertySetPtr pset = drmModePropertySetAlloc();
if (!pset) {
ALOGE("Failed to allocate property set");
return -ENOMEM;
}
- DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
iter != layers->end(); ++iter) {
hwc_layer_1_t *layer = &iter->layer;
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 9f50664..46d71ae 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -20,6 +20,7 @@
#include "drm_hwcomposer.h"
#include "drmcomposition.h"
#include "drmcompositorworker.h"
+#include "drmframebuffer.h"
#include <pthread.h>
#include <queue>
@@ -28,8 +29,12 @@
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
+#define DRM_DISPLAY_BUFFERS 2
+
namespace android {
+class GLWorkerCompositor;
+
class DrmDisplayCompositor {
public:
DrmDisplayCompositor();
@@ -46,6 +51,7 @@
private:
DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
+ int ApplyPreComposite(DrmDisplayComposition *display_comp);
int ApplyFrame(DrmDisplayComposition *display_comp);
int ApplyDpms(DrmDisplayComposition *display_comp);
@@ -62,6 +68,10 @@
bool initialized_;
bool active_;
+ int framebuffer_index_;
+ DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS];
+ std::unique_ptr<GLWorkerCompositor> pre_compositor_;
+
// mutable since we need to acquire in HaveQueuedComposites
mutable pthread_mutex_t lock_;
diff --git a/drmframebuffer.h b/drmframebuffer.h
new file mode 100644
index 0000000..6f078d9
--- /dev/null
+++ b/drmframebuffer.h
@@ -0,0 +1,102 @@
+/*
+ * 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_DRM_FRAMEBUFFER_
+#define ANDROID_DRM_FRAMEBUFFER_
+
+#include <stdint.h>
+
+#include <sync/sync.h>
+
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+
+struct DrmFramebuffer {
+ DrmFramebuffer() : release_fence_fd_(-1) {
+ }
+
+ ~DrmFramebuffer() {
+ 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, 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_;
+};
+}
+
+#endif // ANDROID_DRM_FRAMEBUFFER_
diff --git a/glworker.cpp b/glworker.cpp
index c737c45..e0d337b 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -702,6 +702,14 @@
return ret;
}
+int GLWorkerCompositor::CompositeAndFinish(hwc_layer_1 *layers,
+ size_t num_layers,
+ sp<GraphicBuffer> framebuffer) {
+ int ret = Composite(layers, num_layers, framebuffer);
+ glFinish();
+ return ret;
+}
+
int GLWorker::DoComposition(GLWorkerCompositor &compositor, Work *work) {
int ret =
compositor.Composite(work->layers, work->num_layers, work->framebuffer);
diff --git a/glworker.h b/glworker.h
index e9febec..9550cbe 100644
--- a/glworker.h
+++ b/glworker.h
@@ -88,6 +88,8 @@
int Composite(hwc_layer_1 *layers, size_t num_layers,
sp<GraphicBuffer> framebuffer);
+ int CompositeAndFinish(hwc_layer_1 *layers, size_t num_layers,
+ sp<GraphicBuffer> framebuffer);
private:
EGLDisplay egl_display_;