Merge "drm_hwcomposer: limit maximum depth of display composition queue" into mnc-dr-dev
diff --git a/autogl.h b/autogl.h
new file mode 100644
index 0000000..5d25e44
--- /dev/null
+++ b/autogl.h
@@ -0,0 +1,110 @@
+/*
+ * 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_AUTO_GL_H_
+#define ANDROID_AUTO_GL_H_
+
+#include <memory>
+#define EGL_EGLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+// TODO(zachr): use hwc_drm_bo to turn buffer handles into textures
+#ifndef EGL_NATIVE_HANDLE_ANDROID_NVX
+#define EGL_NATIVE_HANDLE_ANDROID_NVX 0x322A
+#endif
+
+namespace android {
+
+#define AUTO_GL_TYPE(name, type, zero, deleter) \
+ struct name##Deleter { \
+ typedef type pointer; \
+ \
+ void operator()(pointer p) const { \
+ if (p != zero) { \
+ deleter; \
+ } \
+ } \
+ }; \
+ typedef std::unique_ptr<type, name##Deleter> name;
+
+AUTO_GL_TYPE(AutoGLFramebuffer, GLuint, 0, glDeleteFramebuffers(1, &p))
+AUTO_GL_TYPE(AutoGLBuffer, GLuint, 0, glDeleteBuffers(1, &p))
+AUTO_GL_TYPE(AutoGLTexture, GLuint, 0, glDeleteTextures(1, &p))
+AUTO_GL_TYPE(AutoGLShader, GLint, 0, glDeleteShader(p))
+AUTO_GL_TYPE(AutoGLProgram, GLint, 0, glDeleteProgram(p))
+
+struct AutoEGLDisplayImage {
+ AutoEGLDisplayImage() : display_(EGL_NO_DISPLAY), image_(EGL_NO_IMAGE_KHR) {
+ }
+
+ AutoEGLDisplayImage(EGLDisplay display, EGLImageKHR image)
+ : display_(display), image_(image) {
+ }
+
+ AutoEGLDisplayImage(const AutoEGLDisplayImage& rhs) = delete;
+ AutoEGLDisplayImage(AutoEGLDisplayImage&& rhs) {
+ clear();
+ std::swap(display_, rhs.display_);
+ std::swap(image_, rhs.image_);
+ }
+
+ ~AutoEGLDisplayImage() {
+ clear();
+ }
+
+ AutoEGLDisplayImage& operator=(const AutoEGLDisplayImage& rhs) = delete;
+ AutoEGLDisplayImage& operator=(AutoEGLDisplayImage&& rhs) {
+ clear();
+ std::swap(display_, rhs.display_);
+ std::swap(image_, rhs.image_);
+ return *this;
+ }
+
+ void reset(EGLDisplay display, EGLImageKHR image) {
+ clear();
+ display_ = display;
+ image_ = image;
+ }
+
+ void clear() {
+ if (image_ != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(display_, image_);
+ display_ = EGL_NO_DISPLAY;
+ image_ = EGL_NO_IMAGE_KHR;
+ }
+ }
+
+ EGLImageKHR image() const {
+ return image_;
+ }
+
+ private:
+ EGLDisplay display_;
+ EGLImageKHR image_;
+};
+
+struct AutoEGLImageAndGLTexture {
+ AutoEGLDisplayImage image;
+ AutoGLTexture texture;
+};
+}
+
+#endif
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index f4e8d9d..864c5e5 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -24,28 +24,28 @@
#include <stdlib.h>
#include <cutils/log.h>
+#include <cutils/properties.h>
#include <sw_sync.h>
#include <sync/sync.h>
namespace android {
-static const bool kUseOverlayPlanes = true;
-
DrmComposition::DrmComposition(DrmResources *drm, Importer *importer)
: drm_(drm), importer_(importer) {
+ char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
+ property_get("hwc.drm.use_overlay_planes", use_overlay_planes_prop, "1");
+ bool use_overlay_planes = atoi(use_overlay_planes_prop);
+
for (DrmResources::PlaneIter iter = drm_->begin_planes();
iter != drm_->end_planes(); ++iter) {
if ((*iter)->type() == DRM_PLANE_TYPE_PRIMARY)
primary_planes_.push_back(*iter);
- else if (kUseOverlayPlanes && (*iter)->type() == DRM_PLANE_TYPE_OVERLAY)
+ else if (use_overlay_planes && (*iter)->type() == DRM_PLANE_TYPE_OVERLAY)
overlay_planes_.push_back(*iter);
}
}
-DrmComposition::~DrmComposition() {
-}
-
-int DrmComposition::Init() {
+int DrmComposition::Init(uint64_t frame_no) {
for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
iter != drm_->end_connectors(); ++iter) {
int display = (*iter)->display();
@@ -54,7 +54,12 @@
ALOGE("Failed to allocate new display composition\n");
return -ENOMEM;
}
- int ret = composition_map_[(*iter)->display()]->Init(drm_, importer_);
+
+ // If the display hasn't been modeset yet, this will be NULL
+ DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
+
+ int ret = composition_map_[(*iter)->display()]->Init(drm_, crtc, importer_,
+ frame_no);
if (ret) {
ALOGE("Failed to init display composition for %d", (*iter)->display());
return ret;
@@ -63,42 +68,26 @@
return 0;
}
-unsigned DrmComposition::GetRemainingLayers(int /*display*/,
- unsigned num_needed) const {
- return num_needed;
+int DrmComposition::SetLayers(size_t num_displays,
+ const DrmCompositionDisplayLayersMap *maps) {
+ int ret = 0;
+ for (size_t display_index = 0; display_index < num_displays;
+ display_index++) {
+ const DrmCompositionDisplayLayersMap &map = maps[display_index];
+ int display = map.display;
+
+ ret = composition_map_[display]->SetLayers(
+ map.layers, map.num_layers, map.layer_indices, &primary_planes_,
+ &overlay_planes_);
+ if (ret)
+ return ret;
+ }
+
+ return DisableUnusedPlanes();
}
-int DrmComposition::AddLayer(int display, hwc_layer_1_t *layer,
- hwc_drm_bo *bo) {
- DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
- if (!crtc) {
- ALOGE("Failed to find crtc for display %d", display);
- return -ENODEV;
- }
-
- // Find a plane for the layer
- DrmPlane *plane = NULL;
- for (std::vector<DrmPlane *>::iterator iter = primary_planes_.begin();
- iter != primary_planes_.end(); ++iter) {
- if ((*iter)->GetCrtcSupported(*crtc)) {
- plane = *iter;
- primary_planes_.erase(iter);
- break;
- }
- }
- for (std::vector<DrmPlane *>::iterator iter = overlay_planes_.begin();
- !plane && iter != overlay_planes_.end(); ++iter) {
- if ((*iter)->GetCrtcSupported(*crtc)) {
- plane = *iter;
- overlay_planes_.erase(iter);
- break;
- }
- }
- return composition_map_[display]->AddLayer(layer, bo, crtc, plane);
-}
-
-int DrmComposition::AddDpmsMode(int display, uint32_t dpms_mode) {
- return composition_map_[display]->AddDpmsMode(dpms_mode);
+int DrmComposition::SetDpmsMode(int display, uint32_t dpms_mode) {
+ return composition_map_[display]->SetDpmsMode(dpms_mode);
}
std::unique_ptr<DrmDisplayComposition> DrmComposition::TakeDisplayComposition(
diff --git a/drmcomposition.h b/drmcomposition.h
index 69bf6d9..426ced0 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -31,21 +31,26 @@
namespace android {
+struct DrmCompositionDisplayLayersMap {
+ int display;
+ size_t num_layers;
+ hwc_layer_1_t *layers;
+ size_t *layer_indices;
+};
+
class DrmComposition {
public:
DrmComposition(DrmResources *drm, Importer *importer);
- ~DrmComposition();
- int Init();
+ int Init(uint64_t frame_no);
- unsigned GetRemainingLayers(int display, unsigned num_needed) const;
- int AddLayer(int display, hwc_layer_1_t *layer, hwc_drm_bo_t *bo);
- int AddDpmsMode(int display, uint32_t dpms_mode);
-
- int DisableUnusedPlanes();
+ int SetLayers(size_t num_displays,
+ const DrmCompositionDisplayLayersMap *maps);
+ int SetDpmsMode(int display, uint32_t dpms_mode);
std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
DrmDisplayComposition *GetDisplayComposition(int display);
+ int DisableUnusedPlanes();
private:
DrmComposition(const DrmComposition &) = delete;
@@ -62,7 +67,6 @@
*/
std::map<int, std::unique_ptr<DrmDisplayComposition>> composition_map_;
};
-
}
#endif // ANDROID_DRM_COMPOSITION_H_
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index 082e75d..ad4cf88 100644
--- a/drmcompositor.cpp
+++ b/drmcompositor.cpp
@@ -27,7 +27,7 @@
namespace android {
-DrmCompositor::DrmCompositor(DrmResources *drm) : drm_(drm) {
+DrmCompositor::DrmCompositor(DrmResources *drm) : drm_(drm), frame_no_(0) {
}
DrmCompositor::~DrmCompositor() {
@@ -53,7 +53,7 @@
ALOGE("Failed to allocate drm composition");
return NULL;
}
- int ret = composition->Init();
+ int ret = composition->Init(++frame_no_);
if (ret) {
ALOGE("Failed to initialize drm composition %d", ret);
delete composition;
@@ -62,7 +62,8 @@
return composition;
}
-int DrmCompositor::QueueComposition(DrmComposition *composition) {
+int DrmCompositor::QueueComposition(
+ std::unique_ptr<DrmComposition> composition) {
int ret = composition->DisableUnusedPlanes();
if (ret) {
ALOGE("Failed to disable unused planes %d", ret);
@@ -76,7 +77,6 @@
composition->TakeDisplayComposition(display));
if (ret) {
ALOGE("Failed to queue composition for display %d", display);
- delete composition;
return ret;
}
}
diff --git a/drmcompositor.h b/drmcompositor.h
index aa4a876..0741932 100644
--- a/drmcompositor.h
+++ b/drmcompositor.h
@@ -22,6 +22,7 @@
#include "importer.h"
#include <map>
+#include <memory>
#include <sstream>
namespace android {
@@ -35,7 +36,7 @@
DrmComposition *CreateComposition(Importer *importer);
- int QueueComposition(DrmComposition *composition);
+ int QueueComposition(std::unique_ptr<DrmComposition> composition);
int Composite();
void Dump(std::ostringstream *out) const;
@@ -44,6 +45,8 @@
DrmResources *drm_;
+ uint64_t frame_no_;
+
// mutable for Dump() propagation
mutable std::map<int, DrmDisplayCompositor> compositor_map_;
};
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index 21a9c2a..c1848e0 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -30,13 +30,39 @@
namespace android {
-DrmCompositionLayer::DrmCompositionLayer() : crtc(NULL), plane(NULL) {
- memset(&layer, 0, sizeof(layer));
- layer.acquireFenceFd = -1;
- memset(&bo, 0, sizeof(bo));
+static native_handle_t *dup_buffer_handle(buffer_handle_t handle) {
+ native_handle_t *new_handle =
+ native_handle_create(handle->numFds, handle->numInts);
+ if (new_handle == NULL)
+ return NULL;
+
+ const int *old_data = handle->data;
+ int *new_data = new_handle->data;
+ for (int i = 0; i < handle->numFds; i++) {
+ *new_data = dup(*old_data);
+ old_data++;
+ new_data++;
+ }
+ memcpy(new_data, old_data, sizeof(int) * handle->numInts);
+
+ return new_handle;
}
-DrmCompositionLayer::~DrmCompositionLayer() {
+static void free_buffer_handle(native_handle_t *handle) {
+ int ret = native_handle_close(handle);
+ if (ret)
+ ALOGE("Failed to close native handle %d", ret);
+ ret = native_handle_delete(handle);
+ if (ret)
+ ALOGE("Failed to delete native handle %d", ret);
+}
+
+DrmCompositionLayer::DrmCompositionLayer()
+ : crtc(NULL), plane(NULL), handle(NULL) {
+ memset(&layer, 0, sizeof(layer));
+ layer.releaseFenceFd = -1;
+ layer.acquireFenceFd = -1;
+ memset(&bo, 0, sizeof(bo));
}
DrmDisplayComposition::DrmDisplayComposition()
@@ -46,7 +72,10 @@
timeline_fd_(-1),
timeline_(0),
timeline_current_(0),
- dpms_mode_(DRM_MODE_DPMS_ON) {
+ timeline_pre_comp_done_(0),
+ pre_composition_layer_index_(-1),
+ dpms_mode_(DRM_MODE_DPMS_ON),
+ frame_no_(0) {
}
DrmDisplayComposition::~DrmDisplayComposition() {
@@ -55,6 +84,11 @@
if (importer_ && iter->bo.fb_id)
importer_->ReleaseBuffer(&iter->bo);
+ if (iter->handle) {
+ gralloc_->unregisterBuffer(gralloc_, iter->handle);
+ free_buffer_handle(iter->handle);
+ }
+
if (iter->layer.acquireFenceFd >= 0)
close(iter->layer.acquireFenceFd);
}
@@ -66,11 +100,21 @@
}
}
-int DrmDisplayComposition::Init(DrmResources *drm, Importer *importer) {
+int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc,
+ Importer *importer, uint64_t frame_no) {
drm_ = drm;
+ crtc_ = crtc; // Can be NULL if we haven't modeset yet
importer_ = importer;
+ frame_no_ = frame_no;
- int ret = sw_sync_timeline_create();
+ int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+ (const hw_module_t **)&gralloc_);
+ if (ret) {
+ ALOGE("Failed to open gralloc module %d", ret);
+ return ret;
+ }
+
+ ret = sw_sync_timeline_create();
if (ret < 0) {
ALOGE("Failed to create sw sync timeline %d", ret);
return ret;
@@ -87,54 +131,188 @@
return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des;
}
-int DrmDisplayComposition::AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo,
- DrmCrtc *crtc, DrmPlane *plane) {
- if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
- return -EINVAL;
-
- ++timeline_;
- layer->releaseFenceFd =
- sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
- if (layer->releaseFenceFd < 0) {
- ALOGE("Could not create release fence %d", layer->releaseFenceFd);
- return layer->releaseFenceFd;
+static DrmPlane *TakePlane(DrmCrtc *crtc, std::vector<DrmPlane *> *planes) {
+ for (auto iter = planes->begin(); iter != planes->end(); ++iter) {
+ if ((*iter)->GetCrtcSupported(*crtc)) {
+ DrmPlane *plane = *iter;
+ planes->erase(iter);
+ return plane;
+ }
}
-
- DrmCompositionLayer_t c_layer;
- c_layer.layer = *layer;
- c_layer.bo = *bo;
- c_layer.crtc = crtc;
- c_layer.plane = plane;
-
- layer->acquireFenceFd = -1; // We own this now
- layers_.push_back(c_layer);
- type_ = DRM_COMPOSITION_TYPE_FRAME;
- return 0;
+ return NULL;
}
-int DrmDisplayComposition::AddLayer(hwc_layer_1_t *layer, DrmCrtc *crtc,
- DrmPlane *plane) {
- if (layer->transform != 0)
- return -EINVAL;
+static DrmPlane *TakePlane(DrmCrtc *crtc,
+ std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes) {
+ DrmPlane *plane = TakePlane(crtc, primary_planes);
+ if (plane)
+ return plane;
+ return TakePlane(crtc, overlay_planes);
+}
- if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
- return -EINVAL;
+int DrmDisplayComposition::CreateNextTimelineFence() {
+ ++timeline_;
+ return sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
+}
- 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;
- }
+int DrmDisplayComposition::IncreaseTimelineToPoint(int point) {
+ int timeline_increase = point - timeline_current_;
+ if (timeline_increase <= 0)
+ return 0;
- ret = AddLayer(layer, &bo, crtc, plane);
+ int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
if (ret)
- importer_->ReleaseBuffer(&bo);
+ ALOGE("Failed to increment sync timeline %d", ret);
+ else
+ timeline_current_ = point;
return ret;
}
-int DrmDisplayComposition::AddDpmsMode(uint32_t dpms_mode) {
+int DrmDisplayComposition::SetLayers(hwc_layer_1_t *layers, size_t num_layers,
+ size_t *layer_indices,
+ std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes) {
+ int ret = 0;
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
+ return -EINVAL;
+
+ for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
+ hwc_layer_1_t *layer = &layers[layer_indices[layer_index]];
+
+ native_handle_t *handle_copy = dup_buffer_handle(layer->handle);
+ if (handle_copy == NULL) {
+ ALOGE("Failed to duplicate handle");
+ return -ENOMEM;
+ }
+
+ int ret = gralloc_->registerBuffer(gralloc_, handle_copy);
+ if (ret) {
+ ALOGE("Failed to register buffer handle %d", ret);
+ free_buffer_handle(handle_copy);
+ return ret;
+ }
+
+ layers_.emplace_back();
+ DrmCompositionLayer_t *c_layer = &layers_.back();
+ c_layer->layer = *layer;
+ c_layer->handle = handle_copy;
+ c_layer->crtc = crtc_;
+
+ ret = importer_->ImportBuffer(layer->handle, &c_layer->bo);
+ if (ret) {
+ ALOGE("Failed to import handle of layer %d", ret);
+ goto fail;
+ }
+
+ if (pre_composition_layer_index_ == -1) {
+ c_layer->plane = TakePlane(crtc_, primary_planes, overlay_planes);
+ if (c_layer->plane == NULL) {
+ if (layers_.size() <= 1) {
+ ALOGE("Failed to match any planes to the crtc of this display");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ layers_.emplace_back();
+ // c_layer's address might have changed when we resized the vector
+ c_layer = &layers_[layers_.size() - 2];
+ DrmCompositionLayer_t &pre_comp_layer = layers_.back();
+ pre_comp_layer.crtc = crtc_;
+ hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer;
+ memset(&pre_comp_output_layer, 0, sizeof(pre_comp_output_layer));
+ pre_comp_output_layer.compositionType = HWC_OVERLAY;
+ 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_composition_layer_index_ = layers_.size() - 1;
+
+ // This is all to fix up the previous layer, which has now become part
+ // of the set of pre-composition layers because we are stealing its
+ // plane.
+ DrmCompositionLayer_t &last_c_layer = layers_[layers_.size() - 3];
+ std::swap(pre_comp_layer.plane, last_c_layer.plane);
+ hwc_layer_1_t *last_layer = &layers[layer_indices[layer_index - 1]];
+ ret = last_layer->releaseFenceFd = CreateNextTimelineFence();
+ if (ret < 0) {
+ ALOGE("Could not create release fence %d", ret);
+ goto fail;
+ }
+ }
+ }
+
+ if (c_layer->plane == NULL) {
+ // Layers to be pre composited all get the earliest release fences as they
+ // will get released soonest.
+ ret = layer->releaseFenceFd = CreateNextTimelineFence();
+ if (ret < 0) {
+ ALOGE("Could not create release fence %d", ret);
+ goto fail;
+ }
+ }
+ }
+
+ timeline_pre_comp_done_ = timeline_;
+
+ for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
+ hwc_layer_1_t *layer = &layers[layer_indices[layer_index]];
+ if (layer->releaseFenceFd >= 0)
+ continue;
+
+ ret = layer->releaseFenceFd = CreateNextTimelineFence();
+ if (ret < 0) {
+ ALOGE("Could not create release fence %d", ret);
+ goto fail;
+ }
+ }
+
+ for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
+ hwc_layer_1_t *layer = &layers[layer_indices[layer_index]];
+ layer->acquireFenceFd = -1; // We own this now
+ }
+
+ type_ = DRM_COMPOSITION_TYPE_FRAME;
+ return 0;
+
+fail:
+
+ for (size_t c_layer_index = 0; c_layer_index < layers_.size();
+ c_layer_index++) {
+ DrmCompositionLayer_t &c_layer = layers_[c_layer_index];
+ if (c_layer.handle) {
+ gralloc_->unregisterBuffer(gralloc_, c_layer.handle);
+ free_buffer_handle(c_layer.handle);
+ }
+ if (c_layer.bo.fb_id)
+ importer_->ReleaseBuffer(&c_layer.bo);
+ if (c_layer.plane != NULL) {
+ std::vector<DrmPlane *> *return_to =
+ (c_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY) ? primary_planes
+ : overlay_planes;
+ return_to->insert(return_to->begin() + c_layer_index, c_layer.plane);
+ }
+ }
+ layers_.clear();
+
+ for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
+ hwc_layer_1_t *layer = &layers[layer_indices[layer_index]];
+ if (layer->releaseFenceFd >= 0) {
+ close(layer->releaseFenceFd);
+ layer->releaseFenceFd = -1;
+ }
+ }
+ sw_sync_timeline_inc(timeline_fd_, timeline_ - timeline_current_);
+
+ timeline_ = timeline_current_;
+ return ret;
+}
+
+int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) {
if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
return -EINVAL;
dpms_mode_ = dpms_mode;
@@ -143,32 +321,64 @@
}
int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
- DrmCompositionLayer_t c_layer;
+ layers_.emplace_back();
+ DrmCompositionLayer_t &c_layer = layers_.back();
c_layer.crtc = NULL;
c_layer.plane = plane;
- layers_.push_back(c_layer);
return 0;
}
+void DrmDisplayComposition::RemoveNoPlaneLayers() {
+ for (auto &comp_layer : layers_) {
+ if (comp_layer.plane != NULL)
+ continue;
+
+ if (importer_ && comp_layer.bo.fb_id) {
+ importer_->ReleaseBuffer(&comp_layer.bo);
+ }
+
+ if (comp_layer.handle) {
+ gralloc_->unregisterBuffer(gralloc_, comp_layer.handle);
+ free_buffer_handle(comp_layer.handle);
+ }
+
+ if (comp_layer.layer.acquireFenceFd >= 0) {
+ close(comp_layer.layer.acquireFenceFd);
+ comp_layer.layer.acquireFenceFd = -1;
+ }
+ }
+
+ layers_.erase(
+ std::remove_if(layers_.begin(), layers_.end(),
+ [](DrmCompositionLayer_t &l) { return l.plane == NULL; }),
+ layers_.end());
+}
+
+int DrmDisplayComposition::SignalPreCompositionDone() {
+ return IncreaseTimelineToPoint(timeline_pre_comp_done_);
+}
+
int DrmDisplayComposition::FinishComposition() {
- int timeline_increase = timeline_ - 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_ = timeline_;
-
- return ret;
+ return IncreaseTimelineToPoint(timeline_);
}
DrmCompositionLayerVector_t *DrmDisplayComposition::GetCompositionLayers() {
return &layers_;
}
+int DrmDisplayComposition::pre_composition_layer_index() const {
+ return pre_composition_layer_index_;
+}
+
uint32_t DrmDisplayComposition::dpms_mode() const {
return dpms_mode_;
}
+
+uint64_t DrmDisplayComposition::frame_no() const {
+ return frame_no_;
+}
+
+Importer *DrmDisplayComposition::importer() const {
+ return importer_;
+}
}
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index 9c51078..be4ecef 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -18,11 +18,14 @@
#define ANDROID_DRM_DISPLAY_COMPOSITION_H_
#include "drm_hwcomposer.h"
+#include "drmcrtc.h"
#include "drmplane.h"
+#include "glworker.h"
#include "importer.h"
#include <vector>
+#include <hardware/gralloc.h>
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
@@ -36,12 +39,12 @@
typedef struct DrmCompositionLayer {
DrmCompositionLayer();
- ~DrmCompositionLayer();
hwc_layer_1_t layer;
hwc_drm_bo_t bo;
DrmCrtc *crtc;
DrmPlane *plane;
+ native_handle_t *handle;
} DrmCompositionLayer_t;
typedef std::vector<DrmCompositionLayer_t> DrmCompositionLayerVector_t;
@@ -50,39 +53,55 @@
DrmDisplayComposition();
~DrmDisplayComposition();
- int Init(DrmResources *drm, Importer *importer);
+ int Init(DrmResources *drm, DrmCrtc *crtc, Importer *importer,
+ uint64_t frame_no);
DrmCompositionType type() const;
- 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 SetLayers(hwc_layer_1_t *layers, size_t num_layers, size_t *layer_indices,
+ std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes);
int AddPlaneDisable(DrmPlane *plane);
- int AddDpmsMode(uint32_t dpms_mode);
+ int SetDpmsMode(uint32_t dpms_mode);
+ void RemoveNoPlaneLayers();
+ int SignalPreCompositionDone();
int FinishComposition();
DrmCompositionLayerVector_t *GetCompositionLayers();
+ int pre_composition_layer_index() const;
uint32_t dpms_mode() const;
+ uint64_t frame_no() const;
+
+ Importer *importer() const;
+
private:
DrmDisplayComposition(const DrmDisplayComposition &) = delete;
bool validate_composition_type(DrmCompositionType desired);
+ int CreateNextTimelineFence();
+ int IncreaseTimelineToPoint(int point);
+
DrmResources *drm_;
+ DrmCrtc *crtc_;
Importer *importer_;
+ const gralloc_module_t *gralloc_;
+ EGLDisplay egl_display_;
DrmCompositionType type_;
int timeline_fd_;
int timeline_;
int timeline_current_;
+ int timeline_pre_comp_done_;
DrmCompositionLayerVector_t layers_;
+ int pre_composition_layer_index_;
uint32_t dpms_mode_;
+
+ uint64_t frame_no_;
};
}
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index 2021923..b293681 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -44,7 +44,6 @@
: drm_(NULL),
display_(-1),
worker_(this),
- frame_no_(0),
initialized_(false),
active_(false),
framebuffer_index_(0),
@@ -165,17 +164,6 @@
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",
@@ -198,69 +186,59 @@
}
std::vector<hwc_layer_1_t> pre_comp_layers;
- for (const auto &comp_layer : *layers)
- if (comp_layer.plane == NULL)
+ for (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;
+ pre_comp_layers.back().handle = comp_layer.handle;
+ comp_layer.layer.acquireFenceFd = -1;
}
}
- ret = pre_compositor_->CompositeAndFinish(
- pre_comp_layers.data(), pre_comp_layers.size(), fb.buffer());
+
+ ret = pre_compositor_->Composite(pre_comp_layers.data(),
+ pre_comp_layers.size(), fb.buffer());
+ pre_compositor_->Finish();
+
+ for (auto &pre_comp_layer : pre_comp_layers) {
+ if (pre_comp_layer.acquireFenceFd >= 0) {
+ close(pre_comp_layer.acquireFenceFd);
+ pre_comp_layer.acquireFenceFd = -1;
+ }
+ }
+
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;
+ DrmCompositionLayer_t &pre_comp_layer =
+ layers->at(display_comp->pre_composition_layer_index());
+ ret = display_comp->importer()->ImportBuffer(fb.buffer()->handle,
+ &pre_comp_layer.bo);
+ if (ret) {
+ ALOGE("Failed to import handle of layer %d", ret);
+ return ret;
+ }
+ hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer;
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;
+ display_comp->RemoveNoPlaneLayers();
+ display_comp->SignalPreCompositionDone();
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) {
+ if (display_comp->pre_composition_layer_index() >= 0) {
ret = ApplyPreComposite(display_comp);
if (ret)
return ret;
@@ -272,6 +250,7 @@
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;
@@ -409,6 +388,16 @@
int DrmDisplayCompositor::Composite() {
ATRACE_CALL();
+
+ if (!pre_compositor_) {
+ pre_compositor_.reset(new GLWorkerCompositor());
+ int ret = pre_compositor_->Init();
+ if (ret) {
+ ALOGE("Failed to initialize OpenGL compositor %d", ret);
+ return ret;
+ }
+ }
+
int ret = pthread_mutex_lock(&lock_);
if (ret) {
ALOGE("Failed to acquire compositor lock %d", ret);
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 46d71ae..50109b3 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -63,8 +63,6 @@
std::queue<std::unique_ptr<DrmDisplayComposition>> composite_queue_;
std::unique_ptr<DrmDisplayComposition> active_composition_;
- uint64_t frame_no_;
-
bool initialized_;
bool active_;
diff --git a/drmmode.cpp b/drmmode.cpp
index abd3b32..7f8c04d 100644
--- a/drmmode.cpp
+++ b/drmmode.cpp
@@ -68,8 +68,7 @@
h_total_ == m.htotal && h_skew_ == m.hskew &&
v_display_ == m.vdisplay && v_sync_start_ == m.vsync_start &&
v_sync_end_ == m.vsync_end && v_total_ == m.vtotal &&
- v_scan_ == m.vscan && flags_ == m.flags &&
- type_ == m.type;
+ v_scan_ == m.vscan && flags_ == m.flags && type_ == m.type;
}
void DrmMode::ToDrmModeModeInfo(drm_mode_modeinfo *m) const {
diff --git a/drmproperty.cpp b/drmproperty.cpp
index 378e3a2..7b4a4f9 100644
--- a/drmproperty.cpp
+++ b/drmproperty.cpp
@@ -71,7 +71,6 @@
type_ = DRM_PROPERTY_TYPE_OBJECT;
else if (flags_ & DRM_MODE_PROP_BLOB)
type_ = DRM_PROPERTY_TYPE_BLOB;
-
}
uint32_t DrmProperty::id() const {
diff --git a/drmresources.cpp b/drmresources.cpp
index feb5187..32fe5cc 100644
--- a/drmresources.cpp
+++ b/drmresources.cpp
@@ -467,18 +467,17 @@
return -EINVAL;
}
- DrmComposition *comp = compositor_.CreateComposition(NULL);
+ std::unique_ptr<DrmComposition> comp(compositor_.CreateComposition(NULL));
if (!comp) {
ALOGE("Failed to create composition for dpms on %d", display);
return -ENOMEM;
}
- int ret = comp->AddDpmsMode(display, mode);
+ int ret = comp->SetDpmsMode(display, mode);
if (ret) {
ALOGE("Failed to add dpms %ld to composition on %d %d", mode, display, ret);
- delete comp;
return ret;
}
- ret = compositor_.QueueComposition(comp);
+ ret = compositor_.QueueComposition(std::move(comp));
if (ret) {
ALOGE("Failed to queue dpms composition on %d %d", display, ret);
return ret;
diff --git a/glworker.cpp b/glworker.cpp
index df6a8f2..f18ace9 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -15,7 +15,7 @@
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "GLWorker"
+#define LOG_TAG "hwc-gl-worker"
#include <algorithm>
#include <string>
@@ -23,6 +23,8 @@
#include <sys/resource.h>
+#include <cutils/properties.h>
+
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
@@ -54,11 +56,7 @@
// [ 2 4 ]
float kTextureTransformMatrices[] = {
1.0f, 0.0f, 0.0f, 1.0f, // identity matrix
- -1.0f, 0.0f, 0.0f, 1.0f, // HWC_TRANSFORM_FLIP_H;
- 1.0f, 0.0f, 0.0f, -1.0f, // HWC_TRANSFORM_FLIP_V;
- 0.0f, 1.0f, -1.0f, 0.0f, // HWC_TRANSFORM_ROT_90;
- -1.0f, 0.0f, 0.0f, -1.0f, // HWC_TRANSFORM_ROT_180;
- 0.0f, -1.0f, 1.0f, 0.0f, // HWC_TRANSFORM_ROT_270;
+ 0.0f, 1.0f, 1.0f, 0.0f, // swap x and y
};
// clang-format on
@@ -194,9 +192,9 @@
"out vec2 fTexCoords[LAYER_COUNT]; \n"
"void main() { \n"
" for (int i = 0; i < LAYER_COUNT; i++) { \n"
-" fTexCoords[i] = (uLayerCrop[i].xy + vTexCoords * uLayerCrop[i].zw) / \n"
+" vec2 tempCoords = vTexCoords * uTexMatrix[i]; \n"
+" fTexCoords[i] = (uLayerCrop[i].xy + tempCoords * uLayerCrop[i].zw) / \n"
" vec2(textureSize(uLayerTextures[i], 0)); \n"
-" fTexCoords[i] *= uTexMatrix[i]; \n"
" } \n"
" vec2 scaledPosition = uViewport.xy + vPosition * uViewport.zw; \n"
" gl_Position = vec4(scaledPosition * vec2(2.0) - vec2(1.0), 0.0, 1.0); \n"
@@ -352,39 +350,49 @@
cmd.texture_count++;
src.texture_index = i;
- for (int b = 0; b < 4; b++) {
- float bound_percent = (cmd.bounds[b] - display_rect.bounds[b % 2]) /
- display_size[b % 2];
- src.crop_bounds[b] =
- crop_rect.bounds[b % 2] + bound_percent * crop_size[b % 2];
- }
-
- float *src_tex_mat;
+ bool swap_xy, flip_xy[2];
switch (layer.transform) {
case HWC_TRANSFORM_FLIP_H:
- src_tex_mat = &kTextureTransformMatrices[4];
+ swap_xy = false; flip_xy[0] = true; flip_xy[1] = false;
break;
case HWC_TRANSFORM_FLIP_V:
- src_tex_mat = &kTextureTransformMatrices[8];
+ swap_xy = false; flip_xy[0] = false; flip_xy[1] = true;
break;
case HWC_TRANSFORM_ROT_90:
- src_tex_mat = &kTextureTransformMatrices[12];
+ swap_xy = true; flip_xy[0] = false; flip_xy[1] = true;
break;
case HWC_TRANSFORM_ROT_180:
- src_tex_mat = &kTextureTransformMatrices[16];
+ swap_xy = false; flip_xy[0] = true; flip_xy[1] = true;
break;
case HWC_TRANSFORM_ROT_270:
- src_tex_mat = &kTextureTransformMatrices[20];
+ swap_xy = true; flip_xy[0] = true; flip_xy[1] = false;
break;
default:
ALOGE(
"Unknown transform for layer: defaulting to identity "
"transform");
case 0:
- src_tex_mat = &kTextureTransformMatrices[0];
+ swap_xy = false; flip_xy[0] = false; flip_xy[1] = false;
break;
}
- std::copy_n(src_tex_mat, 4, src.texture_matrix);
+
+ if (swap_xy)
+ std::copy_n(&kTextureTransformMatrices[4], 4, src.texture_matrix);
+ else
+ std::copy_n(&kTextureTransformMatrices[0], 4, src.texture_matrix);
+
+ for (int j = 0; j < 4; j++) {
+ int b = j ^ (swap_xy ? 1 : 0);
+ float bound_percent = (cmd.bounds[b] - display_rect.bounds[b % 2]) /
+ display_size[b % 2];
+ if (flip_xy[j % 2]) {
+ src.crop_bounds[j] =
+ crop_rect.bounds[j % 2 + 2] - bound_percent * crop_size[j % 2];
+ } else {
+ src.crop_bounds[j] =
+ crop_rect.bounds[j % 2] + bound_percent * crop_size[j % 2];
+ }
+ }
if (layer.blending == HWC_BLENDING_NONE) {
src.alpha = 1.0f;
@@ -444,7 +452,7 @@
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindTexture(GL_TEXTURE_2D, 0);
- out->image.reset(image);
+ out->image.reset(egl_display, image);
out->texture.reset(texture);
return 0;
@@ -552,7 +560,7 @@
}
int GLWorkerCompositor::Composite(hwc_layer_1 *layers, size_t num_layers,
- sp<GraphicBuffer> framebuffer) {
+ const sp<GraphicBuffer> &framebuffer) {
ATRACE_CALL();
int ret = 0;
size_t i;
@@ -565,54 +573,31 @@
GLint frame_width = framebuffer->getWidth();
GLint frame_height = framebuffer->getHeight();
- EGLSyncKHR finished_sync;
-
- AutoEGLImageKHR egl_fb_image(
- eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- (EGLClientBuffer)framebuffer->getNativeBuffer(),
- NULL /* no attribs */),
- EGLImageDeleter(egl_display_));
-
- if (egl_fb_image.get() == EGL_NO_IMAGE_KHR) {
- ALOGE("Failed to make image from target buffer: %s", GetEGLError());
- return -EINVAL;
- }
-
- GLuint gl_fb_tex;
- glGenTextures(1, &gl_fb_tex);
- AutoGLTexture gl_fb_tex_auto(gl_fb_tex);
- glBindTexture(GL_TEXTURE_2D, gl_fb_tex);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
- (GLeglImageOES)egl_fb_image.get());
- glBindTexture(GL_TEXTURE_2D, 0);
-
- GLuint gl_fb;
- glGenFramebuffers(1, &gl_fb);
- AutoGLFramebuffer gl_fb_auto(gl_fb);
- glBindFramebuffer(GL_FRAMEBUFFER, gl_fb);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- gl_fb_tex, 0);
-
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- ALOGE("Failed framebuffer check for created target buffer: %s",
- GetGLFramebufferError());
+ CachedFramebuffer *cached_framebuffer =
+ PrepareAndCacheFramebuffer(framebuffer);
+ if (cached_framebuffer == NULL) {
+ ALOGE("Composite failed because of failed framebuffer");
return -EINVAL;
}
for (i = 0; i < num_layers; i++) {
- const struct hwc_layer_1 *layer = &layers[i];
+ struct hwc_layer_1 *layer = &layers[i];
if (ret) {
- if (layer->acquireFenceFd >= 0)
+ if (layer->acquireFenceFd >= 0) {
close(layer->acquireFenceFd);
+ layer->acquireFenceFd = -1;
+ }
continue;
}
- layer_textures.emplace_back(egl_display_);
+ layer_textures.emplace_back();
ret = CreateTextureFromHandle(egl_display_, layer->handle,
&layer_textures.back());
+
if (!ret) {
ret = EGLFenceWait(egl_display_, layer->acquireFenceFd);
+ layer->acquireFenceFd = -1;
}
if (ret) {
layer_textures.pop_back();
@@ -699,12 +684,103 @@
return ret;
}
-int GLWorkerCompositor::CompositeAndFinish(hwc_layer_1 *layers,
- size_t num_layers,
- sp<GraphicBuffer> framebuffer) {
- int ret = Composite(layers, num_layers, framebuffer);
+void GLWorkerCompositor::Finish() {
+ ATRACE_CALL();
glFinish();
- return ret;
+
+ char use_framebuffer_cache_opt[PROPERTY_VALUE_MAX];
+ property_get("hwc.drm.use_framebuffer_cache", use_framebuffer_cache_opt, "1");
+ bool use_framebuffer_cache = atoi(use_framebuffer_cache_opt);
+
+ if (use_framebuffer_cache) {
+ for (auto &fb : cached_framebuffers_)
+ fb.strong_framebuffer.clear();
+ } else {
+ cached_framebuffers_.clear();
+ }
+}
+
+GLWorkerCompositor::CachedFramebuffer::CachedFramebuffer(
+ const sp<GraphicBuffer> &gb, AutoEGLDisplayImage &&image,
+ AutoGLTexture &&tex, AutoGLFramebuffer &&fb)
+ : strong_framebuffer(gb),
+ weak_framebuffer(gb),
+ egl_fb_image(std::move(image)),
+ gl_fb_tex(std::move(tex)),
+ gl_fb(std::move(fb)) {
+}
+
+bool GLWorkerCompositor::CachedFramebuffer::Promote() {
+ if (strong_framebuffer.get() != NULL)
+ return true;
+ strong_framebuffer = weak_framebuffer.promote();
+ return strong_framebuffer.get() != NULL;
+}
+
+GLWorkerCompositor::CachedFramebuffer *
+GLWorkerCompositor::FindCachedFramebuffer(
+ const sp<GraphicBuffer> &framebuffer) {
+ for (auto &fb : cached_framebuffers_)
+ if (fb.weak_framebuffer == framebuffer)
+ return &fb;
+ return NULL;
+}
+
+GLWorkerCompositor::CachedFramebuffer *
+GLWorkerCompositor::PrepareAndCacheFramebuffer(
+ const sp<GraphicBuffer> &framebuffer) {
+ CachedFramebuffer *cached_framebuffer = FindCachedFramebuffer(framebuffer);
+ if (cached_framebuffer != NULL) {
+ if (cached_framebuffer->Promote()) {
+ glBindFramebuffer(GL_FRAMEBUFFER, cached_framebuffer->gl_fb.get());
+ return cached_framebuffer;
+ }
+
+ for (auto it = cached_framebuffers_.begin();
+ it != cached_framebuffers_.end(); ++it) {
+ if (it->weak_framebuffer == framebuffer) {
+ cached_framebuffers_.erase(it);
+ break;
+ }
+ }
+ }
+
+ AutoEGLDisplayImage egl_fb_image(
+ egl_display_,
+ eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)framebuffer->getNativeBuffer(),
+ NULL /* no attribs */));
+
+ if (egl_fb_image.image() == EGL_NO_IMAGE_KHR) {
+ ALOGE("Failed to make image from target buffer: %s", GetEGLError());
+ return NULL;
+ }
+
+ GLuint gl_fb_tex;
+ glGenTextures(1, &gl_fb_tex);
+ AutoGLTexture gl_fb_tex_auto(gl_fb_tex);
+ glBindTexture(GL_TEXTURE_2D, gl_fb_tex);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+ (GLeglImageOES)egl_fb_image.image());
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ GLuint gl_fb;
+ glGenFramebuffers(1, &gl_fb);
+ AutoGLFramebuffer gl_fb_auto(gl_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, gl_fb);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ gl_fb_tex, 0);
+
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGE("Failed framebuffer check for created target buffer: %s",
+ GetGLFramebufferError());
+ return NULL;
+ }
+
+ cached_framebuffers_.emplace_back(framebuffer, std::move(egl_fb_image),
+ std::move(gl_fb_tex_auto),
+ std::move(gl_fb_auto));
+ return &cached_framebuffers_.back();
}
} // namespace android
diff --git a/glworker.h b/glworker.h
index 8252b62..ce41444 100644
--- a/glworker.h
+++ b/glworker.h
@@ -17,7 +17,6 @@
#ifndef ANDROID_GL_WORKER_H_
#define ANDROID_GL_WORKER_H_
-#include <memory>
#include <vector>
#define EGL_EGLEXT_PROTOTYPES
@@ -30,71 +29,49 @@
#include <ui/GraphicBuffer.h>
-struct hwc_layer_1;
+#include "autogl.h"
namespace android {
-#define AUTO_GL_TYPE(name, type, zero, deleter) \
- struct name##Deleter { \
- typedef type pointer; \
- \
- void operator()(pointer p) const { \
- if (p != zero) { \
- deleter; \
- } \
- } \
- }; \
- typedef std::unique_ptr<type, name##Deleter> name;
-
-AUTO_GL_TYPE(AutoGLFramebuffer, GLuint, 0, glDeleteFramebuffers(1, &p))
-AUTO_GL_TYPE(AutoGLBuffer, GLuint, 0, glDeleteBuffers(1, &p))
-AUTO_GL_TYPE(AutoGLTexture, GLuint, 0, glDeleteTextures(1, &p))
-AUTO_GL_TYPE(AutoGLShader, GLint, 0, glDeleteShader(p))
-AUTO_GL_TYPE(AutoGLProgram, GLint, 0, glDeleteProgram(p))
-
-struct EGLImageDeleter {
- typedef EGLImageKHR pointer;
-
- EGLDisplay egl_display_;
-
- EGLImageDeleter(EGLDisplay egl_display) : egl_display_(egl_display) {
- }
-
- void operator()(EGLImageKHR p) const {
- if (p != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(egl_display_, p);
- }
- }
-};
-typedef std::unique_ptr<EGLImageKHR, EGLImageDeleter> AutoEGLImageKHR;
-
-struct AutoEGLImageAndGLTexture {
- AutoEGLImageKHR image;
- AutoGLTexture texture;
-
- AutoEGLImageAndGLTexture(EGLDisplay egl_display)
- : image(EGL_NO_IMAGE_KHR, EGLImageDeleter(egl_display)) {
- }
-};
-
class GLWorkerCompositor {
public:
GLWorkerCompositor();
~GLWorkerCompositor();
int Init();
-
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);
+ const sp<GraphicBuffer> &framebuffer);
+ void Finish();
private:
+ struct CachedFramebuffer {
+ // If the strong_framebuffer is non-NULL, we are holding a strong reference
+ // until we are sure rendering is done. The weak reference will be equal in
+ // that case.
+ sp<GraphicBuffer> strong_framebuffer;
+ wp<GraphicBuffer> weak_framebuffer;
+ AutoEGLDisplayImage egl_fb_image;
+ AutoGLTexture gl_fb_tex;
+ AutoGLFramebuffer gl_fb;
+
+ CachedFramebuffer(const sp<GraphicBuffer> &gb, AutoEGLDisplayImage &&image,
+ AutoGLTexture &&tex, AutoGLFramebuffer &&fb);
+
+ bool Promote();
+ };
+
+ CachedFramebuffer *FindCachedFramebuffer(
+ const sp<GraphicBuffer> &framebuffer);
+ CachedFramebuffer *PrepareAndCacheFramebuffer(
+ const sp<GraphicBuffer> &framebuffer);
+
EGLDisplay egl_display_;
EGLContext egl_ctx_;
std::vector<AutoGLProgram> blend_programs_;
AutoGLBuffer vertex_buffer_;
+
+ std::vector<CachedFramebuffer> cached_framebuffers_;
};
}
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index a83c247..060a955 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -22,12 +22,14 @@
#include "importer.h"
#include "vsyncworker.h"
+#include <stdlib.h>
+
+#include <map>
+#include <vector>
+
#include <errno.h>
#include <fcntl.h>
-#include <list>
-#include <map>
#include <pthread.h>
-#include <stdlib.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <xf86drm.h>
@@ -58,7 +60,7 @@
typedef std::map<int, hwc_drm_display_t> DisplayMap;
typedef DisplayMap::iterator DisplayMapIter;
- hwc_context_t() : procs(NULL), importer(NULL) {
+ hwc_context_t() : procs(NULL), importer(NULL), use_framebuffer_target(false) {
}
~hwc_context_t() {
@@ -71,9 +73,10 @@
DisplayMap displays;
DrmResources drm;
Importer *importer;
+ bool use_framebuffer_target;
};
-static void hwc_dump(struct hwc_composer_device_1* dev, char *buff,
+static void hwc_dump(struct hwc_composer_device_1 *dev, char *buff,
int buff_len) {
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
std::ostringstream out;
@@ -86,6 +89,15 @@
static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
hwc_display_contents_1_t **display_contents) {
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
+
+ char use_framebuffer_target[PROPERTY_VALUE_MAX];
+ property_get("hwc.drm.use_framebuffer_target", use_framebuffer_target, "0");
+ bool new_use_framebuffer_target = atoi(use_framebuffer_target);
+ if (ctx->use_framebuffer_target != new_use_framebuffer_target)
+ ALOGW("Starting to %s HWC_FRAMEBUFFER_TARGET",
+ new_use_framebuffer_target ? "use" : "not use");
+ ctx->use_framebuffer_target = new_use_framebuffer_target;
+
for (int i = 0; i < (int)num_displays; ++i) {
if (!display_contents[i])
continue;
@@ -100,8 +112,19 @@
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 (!ctx->use_framebuffer_target) {
+ if (layer->compositionType == HWC_FRAMEBUFFER)
+ layer->compositionType = HWC_OVERLAY;
+ } else {
+ switch (layer->compositionType) {
+ case HWC_OVERLAY:
+ case HWC_BACKGROUND:
+ case HWC_SIDEBAND:
+ case HWC_CURSOR_OVERLAY:
+ layer->compositionType = HWC_FRAMEBUFFER;
+ break;
+ }
+ }
}
}
@@ -109,8 +132,7 @@
}
static void hwc_set_cleanup(size_t num_displays,
- hwc_display_contents_1_t **display_contents,
- DrmComposition *composition) {
+ hwc_display_contents_1_t **display_contents) {
for (int i = 0; i < (int)num_displays; ++i) {
if (!display_contents[i])
continue;
@@ -128,39 +150,17 @@
dc->outbufAcquireFenceFd = -1;
}
}
-
- delete composition;
}
-static int hwc_add_layer(int display, hwc_context_t *ctx, hwc_layer_1_t *layer,
- DrmComposition *composition) {
- hwc_drm_bo_t bo;
- int ret = ctx->importer->ImportBuffer(layer->handle, &bo);
- if (ret) {
- ALOGE("Failed to import handle to bo %d", ret);
- return ret;
- }
-
- ret = composition->AddLayer(display, layer, &bo);
- if (!ret)
- return 0;
-
- int destroy_ret = ctx->importer->ReleaseBuffer(&bo);
- if (destroy_ret)
- ALOGE("Failed to destroy buffer %d", destroy_ret);
-
- return ret;
-}
-
-static void hwc_add_layer_to_retire_fence(hwc_layer_1_t *layer,
- hwc_display_contents_1_t *display_contents) {
+static void hwc_add_layer_to_retire_fence(
+ hwc_layer_1_t *layer, hwc_display_contents_1_t *display_contents) {
if (layer->releaseFenceFd < 0)
return;
if (display_contents->retireFenceFd >= 0) {
int old_retire_fence = display_contents->retireFenceFd;
- display_contents->retireFenceFd = sync_merge("dc_retire", old_retire_fence,
- layer->releaseFenceFd);
+ display_contents->retireFenceFd =
+ sync_merge("dc_retire", old_retire_fence, layer->releaseFenceFd);
close(old_retire_fence);
} else {
display_contents->retireFenceFd = dup(layer->releaseFenceFd);
@@ -171,64 +171,106 @@
hwc_display_contents_1_t **display_contents) {
ATRACE_CALL();
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
- DrmComposition *composition =
- ctx->drm.compositor()->CreateComposition(ctx->importer);
+ int ret;
+ std::unique_ptr<DrmComposition> composition(
+ ctx->drm.compositor()->CreateComposition(ctx->importer));
if (!composition) {
ALOGE("Drm composition init failed");
- hwc_set_cleanup(num_displays, display_contents, NULL);
+ hwc_set_cleanup(num_displays, display_contents);
return -EINVAL;
}
- int ret;
+ std::vector<DrmCompositionDisplayLayersMap> layers_map;
+ std::vector<std::vector<size_t>> layers_indices;
+ layers_map.reserve(num_displays);
+ layers_indices.reserve(num_displays);
+
for (int i = 0; i < (int)num_displays; ++i) {
if (!display_contents[i])
continue;
-
hwc_display_contents_1_t *dc = display_contents[i];
- int j;
- unsigned num_layers = 0;
+
+ layers_map.emplace_back();
+ DrmCompositionDisplayLayersMap &map = layers_map[i];
+ map.display = i;
+ map.layers = dc->hwLayers;
+
+ std::vector<size_t> indices_to_composite;
unsigned num_dc_layers = dc->numHwLayers;
- for (j = 0; j < (int)num_dc_layers; ++j) {
+ int framebuffer_target_index = -1;
+ for (int j = 0; j < (int)num_dc_layers; ++j) {
+ hwc_layer_1_t *layer = &dc->hwLayers[j];
+ if (layer->flags & HWC_SKIP_LAYER)
+ continue;
+ if (!ctx->use_framebuffer_target) {
+ if (layer->compositionType == HWC_OVERLAY)
+ indices_to_composite.push_back(j);
+ if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
+ framebuffer_target_index = j;
+ } else {
+ if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
+ indices_to_composite.push_back(j);
+ }
+ }
+ if (ctx->use_framebuffer_target) {
+ if (indices_to_composite.size() != 1) {
+ ALOGE("Expected 1 (got %d) layer with HWC_FRAMEBUFFER_TARGET",
+ indices_to_composite.size());
+ hwc_set_cleanup(num_displays, display_contents);
+ return -EINVAL;
+ }
+ } else {
+ if (indices_to_composite.empty() && framebuffer_target_index >= 0) {
+ // Fall back to use HWC_FRAMEBUFFER_TARGET if all HWC_OVERLAY layers
+ // are skipped.
+ hwc_layer_1_t *layer = &dc->hwLayers[framebuffer_target_index];
+ if (!layer->handle || (layer->flags & HWC_SKIP_LAYER)) {
+ ALOGE("Expected valid layer with HWC_FRAMEBUFFER_TARGET when all "
+ "HWC_OVERLAY layers are skipped.");
+ hwc_set_cleanup(num_displays, display_contents);
+ return -EINVAL;
+ }
+ indices_to_composite.push_back(framebuffer_target_index);
+ }
+ }
+
+ map.num_layers = indices_to_composite.size();
+ layers_indices.emplace_back(std::move(indices_to_composite));
+ map.layer_indices = layers_indices.back().data();
+ }
+
+ ret = composition->SetLayers(layers_map.size(), layers_map.data());
+ if (ret) {
+ hwc_set_cleanup(num_displays, display_contents);
+ return -EINVAL;
+ }
+
+ ret = ctx->drm.compositor()->QueueComposition(std::move(composition));
+ if (ret) {
+ hwc_set_cleanup(num_displays, display_contents);
+ return -EINVAL;
+ }
+
+ composition.reset(NULL);
+
+ for (int i = 0; i < (int)num_displays; ++i) {
+ if (!display_contents[i])
+ continue;
+ hwc_display_contents_1_t *dc = display_contents[i];
+ unsigned num_dc_layers = dc->numHwLayers;
+ for (int j = 0; 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)
- num_layers++;
- }
-
- unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
-
- if (num_layers > num_planes) {
- ALOGE("Can not composite %u with only %u planes", num_layers, 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 (layer->compositionType != HWC_OVERLAY)
- 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;
- }
- hwc_add_layer_to_retire_fence(layer, dc);
-
- --num_planes;
+ hwc_add_layer_to_retire_fence(layer, dc);
}
}
- ret = ctx->drm.compositor()->QueueComposition(composition);
- composition = NULL;
if (ret) {
ALOGE("Failed to queue the composition");
- hwc_set_cleanup(num_displays, display_contents, NULL);
- return ret;
}
- hwc_set_cleanup(num_displays, display_contents, NULL);
+ hwc_set_cleanup(num_displays, display_contents);
return ret;
}
diff --git a/nvimporter.cpp b/nvimporter.cpp
index 93b9129..de3ed55 100644
--- a/nvimporter.cpp
+++ b/nvimporter.cpp
@@ -121,7 +121,7 @@
return 0;
}
-int NvImporter::ReleaseBuffer(hwc_drm_bo_t * bo) {
+int NvImporter::ReleaseBuffer(hwc_drm_bo_t *bo) {
NvBuffer_t *buf = (NvBuffer_t *)bo->priv;
if (!buf) {
ALOGE("Freeing bo %ld, buf is NULL!", bo->fb_id);