Merge "drm_hwcomposer: integrate GLCompositor with hwcomposer" into mnc-dev
diff --git a/Android.mk b/Android.mk
index 9fc17fa..5eef35f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -20,10 +20,14 @@
LOCAL_SHARED_LIBRARIES := \
libcutils \
libdrm \
+ libEGL \
+ libGLESv2 \
libhardware \
liblog \
libsync \
- libutils \
+ libui \
+ libutils
+
LOCAL_C_INCLUDES := \
external/libdrm \
@@ -44,7 +48,9 @@
drmmode.cpp \
drmplane.cpp \
drmproperty.cpp \
+ gl_compositor.cpp \
hwcomposer.cpp \
+ seperate_rects.cpp \
vsyncworker.cpp \
worker.cpp
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index 2f9640e..6a30fbe 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -18,6 +18,7 @@
#include "drm_hwcomposer.h"
#include "drmresources.h"
+#include "gl_compositor.h"
#include "importer.h"
#include "vsyncworker.h"
@@ -38,11 +39,88 @@
#include <hardware/hwcomposer.h>
#include <sw_sync.h>
#include <sync/sync.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
#define UM_PER_INCH 25400
+#define HWC_FB_BUFFERS 2
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;
@@ -50,6 +128,9 @@
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 {
@@ -70,6 +151,7 @@
DisplayMap displays;
DrmResources drm;
Importer *importer;
+ GLCompositor pre_compositor;
};
static void hwc_dump(struct hwc_composer_device_1* dev, char *buff,
@@ -84,43 +166,31 @@
static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
hwc_display_contents_1_t **display_contents) {
- // XXX: Once we have a GL compositor, just make everything HWC_OVERLAY
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
- Composition *composition =
- ctx->drm.compositor()->CreateComposition(ctx->importer);
- if (!composition) {
- ALOGE("Drm composition init failed");
- return -EINVAL;
- }
-
for (int i = 0; i < (int)num_displays; ++i) {
if (!display_contents[i])
continue;
- int num_layers = display_contents[i]->numHwLayers;
- int num_planes = composition->GetRemainingLayers(i, num_layers);
-
- // XXX: Should go away with atomic modeset
DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
if (!crtc) {
ALOGE("No crtc for display %d", i);
- delete composition;
return -ENODEV;
}
- if (crtc->requires_modeset())
- num_planes = 0;
- for (int j = std::max(0, num_layers - num_planes); j < num_layers; j++) {
- if (j >= num_planes)
- break;
-
+ 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 (layer->compositionType == HWC_FRAMEBUFFER)
- layer->compositionType = HWC_OVERLAY;
+
+ if (crtc->requires_modeset()) {
+ if (layer->compositionType == HWC_OVERLAY)
+ layer->compositionType = HWC_FRAMEBUFFER;
+ } else {
+ if (layer->compositionType == HWC_FRAMEBUFFER)
+ layer->compositionType = HWC_OVERLAY;
+ }
}
}
- delete composition;
return 0;
}
@@ -190,35 +260,45 @@
hwc_set_cleanup(num_displays, display_contents, composition);
return -ENODEV;
}
-
- hwc_display_contents_1_t *dc = display_contents[i];
- unsigned num_layers = dc->numHwLayers;
- unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
bool use_target = false;
- // XXX: We don't need to check for modeset required with atomic modeset
- if (crtc->requires_modeset() || num_layers > num_planes)
+ if (crtc->requires_modeset()) {
use_target = true;
-
- // XXX: Won't need to worry about FB_TARGET with GL Compositor
- for (int j = 0; use_target && j < (int)num_layers; ++j) {
- hwc_layer_1_t *layer = &dc->hwLayers[j];
- if (layer->compositionType != HWC_FRAMEBUFFER_TARGET)
- continue;
-
- ret = hwc_add_layer(i, ctx, layer, composition);
- if (ret) {
- ALOGE("Add layer failed %d", ret);
- hwc_set_cleanup(num_displays, display_contents, composition);
- return ret;
- }
- --num_planes;
- break;
}
- for (int j = 0; num_planes && j < (int)num_layers; ++j) {
+ hwc_display_contents_1_t *dc = display_contents[i];
+ int j;
+ unsigned num_layers = 0;
+ unsigned num_dc_layers = dc->numHwLayers;
+ for (j = 0; j < (int)num_dc_layers; ++j) {
hwc_layer_1_t *layer = &dc->hwLayers[j];
- if (layer->compositionType != HWC_OVERLAY)
+ if (layer->flags & HWC_SKIP_LAYER)
continue;
+ if ((use_target && layer->compositionType == HWC_FRAMEBUFFER_TARGET) ||
+ layer->compositionType == HWC_OVERLAY) {
+ num_layers++;
+ }
+ }
+
+ unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
+ bool use_pre_compositor = false;
+
+ if (!use_target && 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) {
+ hwc_layer_1_t *layer = &dc->hwLayers[j];
+ if (layer->flags & HWC_SKIP_LAYER)
+ continue;
+ if (use_target) {
+ if (layer->compositionType != HWC_FRAMEBUFFER_TARGET)
+ continue;
+ } else {
+ if (layer->compositionType != HWC_OVERLAY)
+ continue;
+ }
ret = hwc_add_layer(i, ctx, layer, composition);
if (ret) {
@@ -228,6 +308,122 @@
}
--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;
+ }
+
+ fb->set_release_fence_fd(composite_layer.releaseFenceFd);
+ hd->fb_idx = (hd->fb_idx + 1) % HWC_FB_BUFFERS;
+ }
}
ret = ctx->drm.compositor()->QueueComposition(composition);
@@ -410,8 +606,7 @@
return -EINVAL;
}
- int ret =
- ctx->drm.SetDisplayActiveMode(display, hd->config_ids[index]);
+ int ret = ctx->drm.SetDisplayActiveMode(display, hd->config_ids[index]);
if (ret) {
ALOGE("Failed to set config for display %d", display);
return ret;
@@ -452,6 +647,7 @@
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) {
@@ -502,6 +698,13 @@
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");