Merge tag 'android-6.0.1_r3' into 601r3
Android 6.0.1 release 3
* tag 'android-6.0.1_r3': (29 commits)
drm_hwcomposer: Use mode vrefresh if provided
drm_hwcomposer: C++ coding style cleanup, no functional changes.
drm_hwcomposer: move atomic modeset calls into a separate worker
drm_hwcomposer: get gralloc buffer usage during hwc_set
drm_hwcomposer: remove unused and confusing HWC_FB_BUFFERS definition.
drm_hwcomposer: implement squashing
drm_hwcomposer: lazily generate shaders for GLWorkerCompositor
drm_hwcomposer: use latest patchset of "separate C compliant header file."
drm_hwcomposer: Remove hwc.drm.use_framebuffer_target property
drm_hwcomposer: separate C compliant header file.
drm_hwcomposer: Add sanity check on display in SetLayers
drm_hwcomposer: fix missing assignment of premult flag
drm_hwcomposer: do not queue layers map for virtual display
drm_hwcomposer: add missing break statement
drm_hwcomposer: Use layer alpha to blend planes
drm_hwcomposer: reimplement Dump for DrmDisplayCompositor
drm_hwcomposer: Do not close duplicate gem handles in nvimporter
drm_hwcomposer: ground work for squashing
drm_hwcomposer: name the texture samplers individually and unroll loop
drm_hwcomposer: fix logic error in premult blending
...
Change-Id: I099a48bb319d3c59336b3bc2f7ec054685c37c3e
diff --git a/autogl.h b/autogl.h
index 5d25e44..fc77fb0 100644
--- a/autogl.h
+++ b/autogl.h
@@ -52,8 +52,7 @@
AUTO_GL_TYPE(AutoGLProgram, GLint, 0, glDeleteProgram(p))
struct AutoEGLDisplayImage {
- AutoEGLDisplayImage() : display_(EGL_NO_DISPLAY), image_(EGL_NO_IMAGE_KHR) {
- }
+ AutoEGLDisplayImage() = default;
AutoEGLDisplayImage(EGLDisplay display, EGLImageKHR image)
: display_(display), image_(image) {
@@ -61,9 +60,10 @@
AutoEGLDisplayImage(const AutoEGLDisplayImage& rhs) = delete;
AutoEGLDisplayImage(AutoEGLDisplayImage&& rhs) {
- clear();
- std::swap(display_, rhs.display_);
- std::swap(image_, rhs.image_);
+ display_ = rhs.display_;
+ image_ = rhs.image_;
+ rhs.display_ = EGL_NO_DISPLAY;
+ rhs.image_ = EGL_NO_IMAGE_KHR;
}
~AutoEGLDisplayImage() {
@@ -97,8 +97,8 @@
}
private:
- EGLDisplay display_;
- EGLImageKHR image_;
+ EGLDisplay display_ = EGL_NO_DISPLAY;
+ EGLImageKHR image_ = EGL_NO_IMAGE_KHR;
};
struct AutoEGLImageAndGLTexture {
diff --git a/drm_hwcomposer.h b/drm_hwcomposer.h
index fdf389b..4a8b4a3 100644
--- a/drm_hwcomposer.h
+++ b/drm_hwcomposer.h
@@ -23,47 +23,10 @@
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
#include "seperate_rects.h"
+#include "drmhwcgralloc.h"
struct hwc_import_context;
-enum {
- /* perform(const struct gralloc_module_t *mod,
- * int op,
- * int drm_fd,
- * buffer_handle_t buffer,
- * struct hwc_drm_bo *bo);
- */
- GRALLOC_MODULE_PERFORM_DRM_IMPORT = 0xffeeff00,
-
- /* perform(const struct gralloc_module_t *mod,
- * int op,
- * buffer_handle_t buffer,
- * void (*free_callback)(void *),
- * void *priv);
- */
- GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE = 0xffeeff01,
-
- /* perform(const struct gralloc_module_t *mod,
- * int op,
- * buffer_handle_t buffer,
- * void (*free_callback)(void *),
- * void **priv);
- */
- GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE = 0xffeeff02,
-};
-
-typedef struct hwc_drm_bo {
- uint32_t width;
- uint32_t height;
- uint32_t format; /* DRM_FORMAT_* from drm_fourcc.h */
- uint32_t pitches[4];
- uint32_t offsets[4];
- uint32_t gem_handles[4];
- uint32_t fb_id;
- int acquire_fence_fd;
- void *priv;
-} hwc_drm_bo_t;
-
int hwc_import_init(struct hwc_import_context **ctx);
int hwc_import_destroy(struct hwc_import_context *ctx);
@@ -171,11 +134,11 @@
return *this;
}
- operator bool() {
+ operator bool() const {
return importer_ != NULL;
}
- hwc_drm_bo *operator->();
+ const hwc_drm_bo *operator->() const;
void Clear();
@@ -245,6 +208,7 @@
struct DrmHwcLayer {
buffer_handle_t sf_handle = NULL;
+ int gralloc_buffer_usage = 0;
DrmHwcBuffer buffer;
DrmHwcNativeHandle handle;
DrmHwcTransform transform = DrmHwcTransform::kIdentity;
@@ -257,11 +221,12 @@
UniqueFd acquire_fence;
OutputFd release_fence;
- DrmHwcLayer() = default;
- DrmHwcLayer(DrmHwcLayer &&rhs) = default;
-
int InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer,
const gralloc_module_t *gralloc);
+
+ buffer_handle_t get_usable_handle() const {
+ return handle.get() != NULL ? handle.get() : sf_handle;
+ }
};
struct DrmHwcDisplayContents {
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 55fa00c..e7b02b6 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -58,10 +58,9 @@
// 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);
+ int ret = composition_map_[display]->Init(drm_, crtc, importer_, frame_no);
if (ret) {
- ALOGE("Failed to init display composition for %d", (*iter)->display());
+ ALOGE("Failed to init display composition for %d", display);
return ret;
}
}
@@ -76,14 +75,18 @@
DrmCompositionDisplayLayersMap &map = maps[display_index];
int display = map.display;
+ if (!drm_->GetConnectorForDisplay(display)) {
+ ALOGE("Invalid display given to SetLayers %d", display);
+ continue;
+ }
+
ret = composition_map_[display]->SetLayers(
- map.layers.data(), map.layers.size(), &primary_planes_,
- &overlay_planes_);
+ map.layers.data(), map.layers.size(), map.geometry_changed);
if (ret)
return ret;
}
- return DisableUnusedPlanes();
+ return 0;
}
int DrmComposition::SetDpmsMode(int display, uint32_t dpms_mode) {
@@ -99,6 +102,23 @@
return std::move(composition_map_[display]);
}
+int DrmComposition::Plan(std::map<int, DrmDisplayCompositor> &compositor_map) {
+ int ret = 0;
+ for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+ iter != drm_->end_connectors(); ++iter) {
+ int display = (*iter)->display();
+ DrmDisplayComposition *comp = GetDisplayComposition(display);
+ ret = comp->Plan(compositor_map[display].squash_state(), &primary_planes_,
+ &overlay_planes_);
+ if (ret) {
+ ALOGE("Failed to plan composition for dislay %d", display);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int DrmComposition::DisableUnusedPlanes() {
for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
iter != drm_->end_connectors(); ++iter) {
diff --git a/drmcomposition.h b/drmcomposition.h
index ad7a5df..80a7eea 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -30,8 +30,11 @@
namespace android {
+class DrmDisplayCompositor;
+
struct DrmCompositionDisplayLayersMap {
int display;
+ bool geometry_changed = true;
std::vector<DrmHwcLayer> layers;
DrmCompositionDisplayLayersMap() = default;
@@ -51,6 +54,8 @@
std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
DrmDisplayComposition *GetDisplayComposition(int display);
+
+ int Plan(std::map<int, DrmDisplayCompositor> &compositor_map);
int DisableUnusedPlanes();
private:
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index ad4cf88..6b3c294 100644
--- a/drmcompositor.cpp
+++ b/drmcompositor.cpp
@@ -64,11 +64,15 @@
int DrmCompositor::QueueComposition(
std::unique_ptr<DrmComposition> composition) {
- int ret = composition->DisableUnusedPlanes();
- if (ret) {
- ALOGE("Failed to disable unused planes %d", ret);
+ int ret;
+
+ ret = composition->Plan(compositor_map_);
+ if (ret)
return ret;
- }
+
+ ret = composition->DisableUnusedPlanes();
+ if (ret)
+ return ret;
for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
iter != drm_->end_connectors(); ++iter) {
@@ -76,7 +80,7 @@
int ret = compositor_map_[display].QueueComposition(
composition->TakeDisplayComposition(display));
if (ret) {
- ALOGE("Failed to queue composition for display %d", display);
+ ALOGE("Failed to queue composition for display %d (%d)", display, ret);
return ret;
}
}
diff --git a/drmcompositorworker.h b/drmcompositorworker.h
index 9f74fb6..00e14ee 100644
--- a/drmcompositorworker.h
+++ b/drmcompositorworker.h
@@ -26,12 +26,12 @@
class DrmCompositorWorker : public Worker {
public:
DrmCompositorWorker(DrmDisplayCompositor *compositor);
- ~DrmCompositorWorker();
+ ~DrmCompositorWorker() override;
int Init();
protected:
- virtual void Routine();
+ void Routine() override;
DrmDisplayCompositor *compositor_;
};
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index d47b5dc..34d879e 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -23,6 +23,9 @@
#include <stdlib.h>
+#include <algorithm>
+#include <unordered_set>
+
#include <cutils/log.h>
#include <sw_sync.h>
#include <sync/sync.h>
@@ -30,38 +33,15 @@
namespace android {
-DrmCompositionLayer::DrmCompositionLayer(DrmCrtc *crtc, DrmHwcLayer &&l)
- : crtc(crtc),
- sf_handle(l.sf_handle),
- buffer(std::move(l.buffer)),
- handle(std::move(l.handle)),
- transform(l.transform),
- blending(l.blending),
- alpha(l.alpha),
- source_crop(l.source_crop),
- display_frame(l.display_frame),
- source_damage(l.source_damage),
- acquire_fence(std::move(l.acquire_fence)) {
-}
-
-DrmDisplayComposition::DrmDisplayComposition()
- : drm_(NULL),
- importer_(NULL),
- type_(DRM_COMPOSITION_TYPE_EMPTY),
- timeline_fd_(-1),
- timeline_(0),
- timeline_current_(0),
- timeline_pre_comp_done_(0),
- pre_composition_layer_index_(-1),
- dpms_mode_(DRM_MODE_DPMS_ON),
- frame_no_(0) {
-}
+const size_t DrmCompositionPlane::kSourceNone;
+const size_t DrmCompositionPlane::kSourcePreComp;
+const size_t DrmCompositionPlane::kSourceSquash;
+const size_t DrmCompositionPlane::kSourceLayerMax;
DrmDisplayComposition::~DrmDisplayComposition() {
if (timeline_fd_ >= 0) {
- FinishComposition();
+ SignalCompositionDone();
close(timeline_fd_);
- timeline_fd_ = -1;
}
}
@@ -81,14 +61,79 @@
return 0;
}
-DrmCompositionType DrmDisplayComposition::type() const {
- return type_;
-}
-
bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) {
return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des;
}
+int DrmDisplayComposition::CreateNextTimelineFence() {
+ ++timeline_;
+ return sw_sync_fence_create(timeline_fd_, "hwc drm display composition fence",
+ timeline_);
+}
+
+int DrmDisplayComposition::IncreaseTimelineToPoint(int point) {
+ int timeline_increase = point - timeline_current_;
+ if (timeline_increase <= 0)
+ return 0;
+
+ int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
+ if (ret)
+ ALOGE("Failed to increment sync timeline %d", ret);
+ else
+ timeline_current_ = point;
+
+ return ret;
+}
+
+int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers,
+ bool geometry_changed) {
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
+ return -EINVAL;
+
+ geometry_changed_ = geometry_changed;
+
+ for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
+ layers_.emplace_back(std::move(layers[layer_index]));
+ }
+
+ type_ = DRM_COMPOSITION_TYPE_FRAME;
+ return 0;
+}
+
+int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) {
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
+ return -EINVAL;
+ dpms_mode_ = dpms_mode;
+ type_ = DRM_COMPOSITION_TYPE_DPMS;
+ return 0;
+}
+
+int DrmDisplayComposition::SetDisplayMode(const DrmMode &display_mode) {
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET))
+ return -EINVAL;
+ display_mode_ = display_mode;
+ dpms_mode_ = DRM_MODE_DPMS_ON;
+ type_ = DRM_COMPOSITION_TYPE_MODESET;
+ return 0;
+}
+
+int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
+ composition_planes_.emplace_back(
+ DrmCompositionPlane{plane, crtc_, DrmCompositionPlane::kSourceNone});
+ return 0;
+}
+
+static size_t CountUsablePlanes(DrmCrtc *crtc,
+ std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes) {
+ return std::count_if(
+ primary_planes->begin(), primary_planes->end(),
+ [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); }) +
+ std::count_if(
+ overlay_planes->begin(), overlay_planes->end(),
+ [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); });
+}
+
static DrmPlane *TakePlane(DrmCrtc *crtc, std::vector<DrmPlane *> *planes) {
for (auto iter = planes->begin(); iter != planes->end(); ++iter) {
if ((*iter)->GetCrtcSupported(*crtc)) {
@@ -109,182 +154,387 @@
return TakePlane(crtc, overlay_planes);
}
-int DrmDisplayComposition::CreateNextTimelineFence() {
- ++timeline_;
- return sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
+static std::vector<size_t> SetBitsToVector(uint64_t in, size_t *index_map) {
+ std::vector<size_t> out;
+ size_t msb = sizeof(in) * 8 - 1;
+ uint64_t mask = (uint64_t)1 << msb;
+ for (size_t i = msb; mask != (uint64_t)0; i--, mask >>= 1)
+ if (in & mask)
+ out.push_back(index_map[i]);
+ return out;
}
-int DrmDisplayComposition::IncreaseTimelineToPoint(int point) {
- int timeline_increase = point - timeline_current_;
- if (timeline_increase <= 0)
- return 0;
+static void SeparateLayers(DrmHwcLayer *layers, size_t *used_layers,
+ size_t num_used_layers,
+ DrmHwcRect<int> *exclude_rects,
+ size_t num_exclude_rects,
+ std::vector<DrmCompositionRegion> ®ions) {
+ if (num_used_layers > 64) {
+ ALOGE("Failed to separate layers because there are more than 64");
+ return;
+ }
- int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
- if (ret)
- ALOGE("Failed to increment sync timeline %d", ret);
- else
- timeline_current_ = point;
+ if (num_used_layers + num_exclude_rects > 64) {
+ ALOGW(
+ "Exclusion rectangles are being truncated to make the rectangle count "
+ "fit into 64");
+ num_exclude_rects = 64 - num_used_layers;
+ }
- return ret;
+ // We inject all the exclude rects into the rects list. Any resulting rect
+ // that includes ANY of the first num_exclude_rects is rejected.
+ std::vector<DrmHwcRect<int>> layer_rects(num_used_layers + num_exclude_rects);
+ std::copy(exclude_rects, exclude_rects + num_exclude_rects,
+ layer_rects.begin());
+ std::transform(
+ used_layers, used_layers + num_used_layers,
+ layer_rects.begin() + num_exclude_rects,
+ [=](size_t layer_index) { return layers[layer_index].display_frame; });
+
+ std::vector<seperate_rects::RectSet<uint64_t, int>> seperate_regions;
+ seperate_rects::seperate_rects_64(layer_rects, &seperate_regions);
+ uint64_t exclude_mask = ((uint64_t)1 << num_exclude_rects) - 1;
+
+ for (seperate_rects::RectSet<uint64_t, int> ®ion : seperate_regions) {
+ if (region.id_set.getBits() & exclude_mask)
+ continue;
+ regions.emplace_back(DrmCompositionRegion{
+ region.rect,
+ SetBitsToVector(region.id_set.getBits() >> num_exclude_rects,
+ used_layers)});
+ }
}
-int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers,
- std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes) {
- int ret = 0;
- if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
- return -EINVAL;
+int DrmDisplayComposition::CreateAndAssignReleaseFences() {
+ std::unordered_set<DrmHwcLayer *> squash_layers;
+ std::unordered_set<DrmHwcLayer *> pre_comp_layers;
+ std::unordered_set<DrmHwcLayer *> comp_layers;
- for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
- DrmHwcLayer *layer = &layers[layer_index];
-
- layers_.emplace_back(crtc_, std::move(*layer));
- DrmCompositionLayer *c_layer = &layers_.back();
-
- 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 &pre_comp_layer = layers_.back();
- pre_comp_layer.crtc = crtc_;
-
- 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 &last_c_layer = layers_[layers_.size() - 3];
- std::swap(pre_comp_layer.plane, last_c_layer.plane);
- OutputFd &last_release_fence = layers[layer_index - 1].release_fence;
- last_release_fence.Set(CreateNextTimelineFence());
- ret = last_release_fence.get();
- 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.
- layer->release_fence.Set(CreateNextTimelineFence());
- ret = layer->release_fence.get();
- if (ret < 0) {
- ALOGE("Could not create release fence %d", ret);
- goto fail;
- }
+ for (const DrmCompositionRegion ®ion : squash_regions_) {
+ for (size_t source_layer_index : region.source_layers) {
+ DrmHwcLayer *source_layer = &layers_[source_layer_index];
+ squash_layers.emplace(source_layer);
}
}
+ for (const DrmCompositionRegion ®ion : pre_comp_regions_) {
+ for (size_t source_layer_index : region.source_layers) {
+ DrmHwcLayer *source_layer = &layers_[source_layer_index];
+ pre_comp_layers.emplace(source_layer);
+ squash_layers.erase(source_layer);
+ }
+ }
+
+ for (const DrmCompositionPlane &plane : composition_planes_) {
+ if (plane.source_layer <= DrmCompositionPlane::kSourceLayerMax) {
+ DrmHwcLayer *source_layer = &layers_[plane.source_layer];
+ comp_layers.emplace(source_layer);
+ pre_comp_layers.erase(source_layer);
+ }
+ }
+
+ for (DrmHwcLayer *layer : squash_layers) {
+ int ret = layer->release_fence.Set(CreateNextTimelineFence());
+ if (ret < 0)
+ return ret;
+ }
+ timeline_squash_done_ = timeline_;
+
+ for (DrmHwcLayer *layer : pre_comp_layers) {
+ int ret = layer->release_fence.Set(CreateNextTimelineFence());
+ if (ret < 0)
+ return ret;
+ }
timeline_pre_comp_done_ = timeline_;
- for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
- DrmHwcLayer *layer = &layers[layer_index];
- if (layer->release_fence.get() >= 0)
+ for (DrmHwcLayer *layer : comp_layers) {
+ int ret = layer->release_fence.Set(CreateNextTimelineFence());
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+int DrmDisplayComposition::Plan(SquashState *squash,
+ std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes) {
+ if (type_ != DRM_COMPOSITION_TYPE_FRAME)
+ return 0;
+
+ size_t planes_can_use =
+ CountUsablePlanes(crtc_, primary_planes, overlay_planes);
+ if (planes_can_use == 0) {
+ ALOGE("Display %d has no usable planes", crtc_->display());
+ return -ENODEV;
+ }
+
+ bool use_squash_framebuffer = false;
+ // Used to determine which layers were entirely squashed
+ std::vector<int> layer_squash_area(layers_.size(), 0);
+ // Used to avoid rerendering regions that were squashed
+ std::vector<DrmHwcRect<int>> exclude_rects;
+ if (squash != NULL && planes_can_use >= 3) {
+ if (geometry_changed_) {
+ squash->Init(layers_.data(), layers_.size());
+ } else {
+ std::vector<bool> changed_regions;
+ squash->GenerateHistory(layers_.data(), layers_.size(), changed_regions);
+
+ std::vector<bool> stable_regions;
+ squash->StableRegionsWithMarginalHistory(changed_regions, stable_regions);
+
+ // Only if SOME region is stable
+ use_squash_framebuffer =
+ std::find(stable_regions.begin(), stable_regions.end(), true) !=
+ stable_regions.end();
+
+ squash->RecordHistory(layers_.data(), layers_.size(), changed_regions);
+
+ // Changes in which regions are squashed triggers a rerender via
+ // squash_regions.
+ bool render_squash = squash->RecordAndCompareSquashed(stable_regions);
+
+ for (size_t region_index = 0; region_index < stable_regions.size();
+ region_index++) {
+ const SquashState::Region ®ion = squash->regions()[region_index];
+ if (!stable_regions[region_index])
+ continue;
+
+ exclude_rects.emplace_back(region.rect);
+
+ if (render_squash) {
+ squash_regions_.emplace_back();
+ squash_regions_.back().frame = region.rect;
+ }
+
+ int frame_area = region.rect.area();
+ // Source layers are sorted front to back i.e. top layer has lowest
+ // index.
+ for (size_t layer_index = layers_.size();
+ layer_index-- > 0; // Yes, I double checked this
+ /* See condition */) {
+ if (!region.layer_refs[layer_index])
+ continue;
+ layer_squash_area[layer_index] += frame_area;
+ if (render_squash)
+ squash_regions_.back().source_layers.push_back(layer_index);
+ }
+ }
+ }
+ }
+
+ std::vector<size_t> layers_remaining;
+ for (size_t layer_index = 0; layer_index < layers_.size(); layer_index++) {
+ // Skip layers that were completely squashed
+ if (layer_squash_area[layer_index] >=
+ layers_[layer_index].display_frame.area()) {
continue;
+ }
- ret = layer->release_fence.Set(CreateNextTimelineFence());
- if (ret < 0) {
- ALOGE("Could not create release fence %d", ret);
- goto fail;
+ layers_remaining.push_back(layer_index);
+ }
+
+ if (use_squash_framebuffer)
+ planes_can_use--;
+
+ if (layers_remaining.size() > planes_can_use)
+ planes_can_use--;
+
+ size_t last_composition_layer = 0;
+ for (last_composition_layer = 0;
+ last_composition_layer < layers_remaining.size() && planes_can_use > 0;
+ last_composition_layer++, planes_can_use--) {
+ composition_planes_.emplace_back(
+ DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
+ crtc_, layers_remaining[last_composition_layer]});
+ }
+
+ layers_remaining.erase(layers_remaining.begin(),
+ layers_remaining.begin() + last_composition_layer);
+
+ if (layers_remaining.size() > 0) {
+ composition_planes_.emplace_back(
+ DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
+ crtc_, DrmCompositionPlane::kSourcePreComp});
+
+ SeparateLayers(layers_.data(), layers_remaining.data(),
+ layers_remaining.size(), exclude_rects.data(),
+ exclude_rects.size(), pre_comp_regions_);
+ }
+
+ if (use_squash_framebuffer) {
+ composition_planes_.emplace_back(
+ DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
+ crtc_, DrmCompositionPlane::kSourceSquash});
+ }
+
+ return CreateAndAssignReleaseFences();
+}
+
+static const char *DrmCompositionTypeToString(DrmCompositionType type) {
+ switch (type) {
+ case DRM_COMPOSITION_TYPE_EMPTY:
+ return "EMPTY";
+ case DRM_COMPOSITION_TYPE_FRAME:
+ return "FRAME";
+ case DRM_COMPOSITION_TYPE_DPMS:
+ return "DPMS";
+ case DRM_COMPOSITION_TYPE_MODESET:
+ return "MODESET";
+ default:
+ return "<invalid>";
+ }
+}
+
+static const char *DPMSModeToString(int dpms_mode) {
+ switch (dpms_mode) {
+ case DRM_MODE_DPMS_ON:
+ return "ON";
+ case DRM_MODE_DPMS_OFF:
+ return "OFF";
+ default:
+ return "<invalid>";
+ }
+}
+
+static void DumpBuffer(const DrmHwcBuffer &buffer, std::ostringstream *out) {
+ if (!buffer) {
+ *out << "buffer=<invalid>";
+ return;
+ }
+
+ *out << "buffer[w/h/format]=";
+ *out << buffer->width << "/" << buffer->height << "/" << buffer->format;
+}
+
+static const char *TransformToString(DrmHwcTransform transform) {
+ switch (transform) {
+ case DrmHwcTransform::kIdentity:
+ return "IDENTITY";
+ case DrmHwcTransform::kFlipH:
+ return "FLIPH";
+ case DrmHwcTransform::kFlipV:
+ return "FLIPV";
+ case DrmHwcTransform::kRotate90:
+ return "ROTATE90";
+ case DrmHwcTransform::kRotate180:
+ return "ROTATE180";
+ case DrmHwcTransform::kRotate270:
+ return "ROTATE270";
+ default:
+ return "<invalid>";
+ }
+}
+
+static const char *BlendingToString(DrmHwcBlending blending) {
+ switch (blending) {
+ case DrmHwcBlending::kNone:
+ return "NONE";
+ case DrmHwcBlending::kPreMult:
+ return "PREMULT";
+ case DrmHwcBlending::kCoverage:
+ return "COVERAGE";
+ default:
+ return "<invalid>";
+ }
+}
+
+static void DumpRegion(const DrmCompositionRegion ®ion,
+ std::ostringstream *out) {
+ *out << "frame";
+ region.frame.Dump(out);
+ *out << " source_layers=(";
+
+ const std::vector<size_t> &source_layers = region.source_layers;
+ for (size_t i = 0; i < source_layers.size(); i++) {
+ *out << source_layers[i];
+ if (i < source_layers.size() - 1) {
+ *out << " ";
}
}
- type_ = DRM_COMPOSITION_TYPE_FRAME;
- return 0;
+ *out << ")";
+}
-fail:
+void DrmDisplayComposition::Dump(std::ostringstream *out) const {
+ *out << "----DrmDisplayComposition"
+ << " crtc=" << (crtc_ ? crtc_->id() : -1)
+ << " type=" << DrmCompositionTypeToString(type_);
- for (size_t c_layer_index = 0; c_layer_index < layers_.size();
- c_layer_index++) {
- DrmCompositionLayer &c_layer = layers_[c_layer_index];
- 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);
- }
+ switch (type_) {
+ case DRM_COMPOSITION_TYPE_DPMS:
+ *out << " dpms_mode=" << DPMSModeToString(dpms_mode_);
+ break;
+ case DRM_COMPOSITION_TYPE_MODESET:
+ *out << " display_mode=" << display_mode_.h_display() << "x"
+ << display_mode_.v_display();
+ break;
+ default:
+ break;
}
- layers_.clear();
+ *out << " timeline[current/squash/pre-comp/done]=" << timeline_current_ << "/"
+ << timeline_squash_done_ << "/" << timeline_pre_comp_done_ << "/"
+ << timeline_ << "\n";
- sw_sync_timeline_inc(timeline_fd_, timeline_ - timeline_current_);
+ *out << " Layers: count=" << layers_.size() << "\n";
+ for (size_t i = 0; i < layers_.size(); i++) {
+ const DrmHwcLayer &layer = layers_[i];
+ *out << " [" << i << "] ";
- timeline_ = timeline_current_;
- return ret;
-}
+ DumpBuffer(layer.buffer, out);
-int DrmDisplayComposition::SetDpmsMode(uint32_t dpms_mode) {
- if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
- return -EINVAL;
- dpms_mode_ = dpms_mode;
- type_ = DRM_COMPOSITION_TYPE_DPMS;
- return 0;
-}
+ *out << " transform=" << TransformToString(layer.transform)
+ << " blending[a=" << (int)layer.alpha
+ << "]=" << BlendingToString(layer.blending) << " source_crop";
+ layer.source_crop.Dump(out);
+ *out << " display_frame";
+ layer.display_frame.Dump(out);
-int DrmDisplayComposition::SetDisplayMode(const DrmMode &display_mode) {
- if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET))
- return -EINVAL;
- display_mode_ = display_mode;
- dpms_mode_ = DRM_MODE_DPMS_ON;
- type_ = DRM_COMPOSITION_TYPE_MODESET;
- return 0;
-}
+ *out << "\n";
+ }
-int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
- layers_.emplace_back();
- DrmCompositionLayer &c_layer = layers_.back();
- c_layer.crtc = NULL;
- c_layer.plane = plane;
- return 0;
-}
+ *out << " Planes: count=" << composition_planes_.size() << "\n";
+ for (size_t i = 0; i < composition_planes_.size(); i++) {
+ const DrmCompositionPlane &comp_plane = composition_planes_[i];
+ *out << " [" << i << "]"
+ << " plane=" << (comp_plane.plane ? comp_plane.plane->id() : -1)
+ << " source_layer=";
+ if (comp_plane.source_layer <= DrmCompositionPlane::kSourceLayerMax) {
+ *out << comp_plane.source_layer;
+ } else {
+ switch (comp_plane.source_layer) {
+ case DrmCompositionPlane::kSourceNone:
+ *out << "NONE";
+ break;
+ case DrmCompositionPlane::kSourcePreComp:
+ *out << "PRECOMP";
+ break;
+ case DrmCompositionPlane::kSourceSquash:
+ *out << "SQUASH";
+ break;
+ default:
+ *out << "<invalid>";
+ break;
+ }
+ }
-void DrmDisplayComposition::RemoveNoPlaneLayers() {
- layers_.erase(
- std::remove_if(layers_.begin(), layers_.end(),
- [](DrmCompositionLayer &l) { return l.plane == NULL; }),
- layers_.end());
-}
+ *out << "\n";
+ }
-int DrmDisplayComposition::SignalPreCompositionDone() {
- return IncreaseTimelineToPoint(timeline_pre_comp_done_);
-}
+ *out << " Squash Regions: count=" << squash_regions_.size() << "\n";
+ for (size_t i = 0; i < squash_regions_.size(); i++) {
+ *out << " [" << i << "] ";
+ DumpRegion(squash_regions_[i], out);
+ *out << "\n";
+ }
-int DrmDisplayComposition::FinishComposition() {
- return IncreaseTimelineToPoint(timeline_);
-}
-
-std::vector<DrmCompositionLayer>
- *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_;
-}
-
-const DrmMode &DrmDisplayComposition::display_mode() const {
- return display_mode_;
-}
-
-Importer *DrmDisplayComposition::importer() const {
- return importer_;
+ *out << " Pre-Comp Regions: count=" << pre_comp_regions_.size() << "\n";
+ for (size_t i = 0; i < pre_comp_regions_.size(); i++) {
+ *out << " [" << i << "] ";
+ DumpRegion(pre_comp_regions_[i], out);
+ *out << "\n";
+ }
}
}
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index 57e8521..69324fd 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -23,6 +23,7 @@
#include "glworker.h"
#include "importer.h"
+#include <sstream>
#include <vector>
#include <hardware/gralloc.h>
@@ -31,6 +32,8 @@
namespace android {
+struct SquashState;
+
enum DrmCompositionType {
DRM_COMPOSITION_TYPE_EMPTY,
DRM_COMPOSITION_TYPE_FRAME,
@@ -38,90 +41,119 @@
DRM_COMPOSITION_TYPE_MODESET,
};
-struct DrmCompositionLayer {
- DrmCrtc *crtc = NULL;
- DrmPlane *plane = NULL;
+struct DrmCompositionRegion {
+ DrmHwcRect<int> frame;
+ std::vector<size_t> source_layers;
+};
- buffer_handle_t sf_handle = NULL;
- DrmHwcBuffer buffer;
- DrmHwcNativeHandle handle;
- DrmHwcTransform transform = DrmHwcTransform::kIdentity;
- DrmHwcBlending blending = DrmHwcBlending::kNone;
- uint8_t alpha = 0xff;
- DrmHwcRect<float> source_crop;
- DrmHwcRect<int> display_frame;
- std::vector<DrmHwcRect<int>> source_damage;
-
- UniqueFd acquire_fence;
-
- DrmCompositionLayer() = default;
- DrmCompositionLayer(DrmCrtc *crtc, DrmHwcLayer &&l);
- DrmCompositionLayer(DrmCompositionLayer &&l) = default;
-
- DrmCompositionLayer &operator=(DrmCompositionLayer &&l) = default;
-
- buffer_handle_t get_usable_handle() const {
- return handle.get() != NULL ? handle.get() : sf_handle;
- }
+struct DrmCompositionPlane {
+ const static size_t kSourceNone = SIZE_MAX;
+ const static size_t kSourcePreComp = kSourceNone - 1;
+ const static size_t kSourceSquash = kSourcePreComp - 1;
+ const static size_t kSourceLayerMax = kSourceSquash - 1;
+ DrmPlane *plane;
+ DrmCrtc *crtc;
+ size_t source_layer;
};
class DrmDisplayComposition {
public:
- DrmDisplayComposition();
+ DrmDisplayComposition() = default;
+ DrmDisplayComposition(const DrmDisplayComposition &) = delete;
~DrmDisplayComposition();
int Init(DrmResources *drm, DrmCrtc *crtc, Importer *importer,
uint64_t frame_no);
- DrmCompositionType type() const;
-
- int SetLayers(DrmHwcLayer *layers, size_t num_layers,
- std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes);
+ int SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed);
int AddPlaneDisable(DrmPlane *plane);
int SetDpmsMode(uint32_t dpms_mode);
int SetDisplayMode(const DrmMode &display_mode);
- void RemoveNoPlaneLayers();
- int SignalPreCompositionDone();
- int FinishComposition();
-
- std::vector<DrmCompositionLayer> *GetCompositionLayers();
- int pre_composition_layer_index() const;
- uint32_t dpms_mode() const;
- const DrmMode &display_mode() const;
-
- uint64_t frame_no() const;
-
- Importer *importer() const;
-
- private:
- DrmDisplayComposition(const DrmDisplayComposition &) = delete;
-
- bool validate_composition_type(DrmCompositionType desired);
+ int Plan(SquashState *squash, std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes);
int CreateNextTimelineFence();
+ int SignalSquashDone() {
+ return IncreaseTimelineToPoint(timeline_squash_done_);
+ }
+ int SignalPreCompDone() {
+ return IncreaseTimelineToPoint(timeline_pre_comp_done_);
+ }
+ int SignalCompositionDone() {
+ return IncreaseTimelineToPoint(timeline_);
+ }
+
+ std::vector<DrmHwcLayer> &layers() {
+ return layers_;
+ }
+
+ std::vector<DrmCompositionRegion> &squash_regions() {
+ return squash_regions_;
+ }
+
+ std::vector<DrmCompositionRegion> &pre_comp_regions() {
+ return pre_comp_regions_;
+ }
+
+ std::vector<DrmCompositionPlane> &composition_planes() {
+ return composition_planes_;
+ }
+
+ uint64_t frame_no() const {
+ return frame_no_;
+ }
+
+ DrmCompositionType type() const {
+ return type_;
+ }
+
+ uint32_t dpms_mode() const {
+ return dpms_mode_;
+ }
+
+ const DrmMode &display_mode() const {
+ return display_mode_;
+ }
+
+ DrmCrtc *crtc() const {
+ return crtc_;
+ }
+
+ Importer *importer() const {
+ return importer_;
+ }
+
+ void Dump(std::ostringstream *out) const;
+
+ private:
+ bool validate_composition_type(DrmCompositionType desired);
+
int IncreaseTimelineToPoint(int point);
- DrmResources *drm_;
- DrmCrtc *crtc_;
- Importer *importer_;
- const gralloc_module_t *gralloc_;
- EGLDisplay egl_display_;
+ int CreateAndAssignReleaseFences();
- DrmCompositionType type_;
+ DrmResources *drm_ = NULL;
+ DrmCrtc *crtc_ = NULL;
+ Importer *importer_ = NULL;
- int timeline_fd_;
- int timeline_;
- int timeline_current_;
- int timeline_pre_comp_done_;
-
- std::vector<DrmCompositionLayer> layers_;
- int pre_composition_layer_index_;
- uint32_t dpms_mode_;
+ DrmCompositionType type_ = DRM_COMPOSITION_TYPE_EMPTY;
+ uint32_t dpms_mode_ = DRM_MODE_DPMS_ON;
DrmMode display_mode_;
- uint64_t frame_no_;
+ int timeline_fd_ = -1;
+ int timeline_ = 0;
+ int timeline_current_ = 0;
+ int timeline_squash_done_ = 0;
+ int timeline_pre_comp_done_ = 0;
+
+ bool geometry_changed_;
+ std::vector<DrmHwcLayer> layers_;
+ std::vector<DrmCompositionRegion> squash_regions_;
+ std::vector<DrmCompositionRegion> pre_comp_regions_;
+ std::vector<DrmCompositionPlane> composition_planes_;
+
+ uint64_t frame_no_ = 0;
};
}
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index 5676f1d..3f41fca 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -23,7 +23,6 @@
#include "drmresources.h"
#include "glworker.h"
-#include <algorithm>
#include <pthread.h>
#include <sched.h>
#include <sstream>
@@ -36,18 +35,212 @@
#include <sync/sync.h>
#include <utils/Trace.h>
-#define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 3
+#define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 2
namespace android {
+void SquashState::Init(DrmHwcLayer *layers, size_t num_layers) {
+ generation_number_++;
+ valid_history_ = 0;
+ regions_.clear();
+ last_handles_.clear();
+
+ std::vector<DrmHwcRect<int>> in_rects;
+ for (size_t i = 0; i < num_layers; i++) {
+ DrmHwcLayer *layer = &layers[i];
+ in_rects.emplace_back(layer->display_frame);
+ last_handles_.push_back(layer->sf_handle);
+ }
+
+ std::vector<seperate_rects::RectSet<uint64_t, int>> out_regions;
+ seperate_rects::seperate_rects_64(in_rects, &out_regions);
+
+ for (const seperate_rects::RectSet<uint64_t, int> &out_region : out_regions) {
+ regions_.emplace_back();
+ Region ®ion = regions_.back();
+ region.rect = out_region.rect;
+ region.layer_refs = out_region.id_set.getBits();
+ }
+}
+
+void SquashState::GenerateHistory(DrmHwcLayer *layers, size_t num_layers,
+ std::vector<bool> &changed_regions) const {
+ changed_regions.resize(regions_.size());
+ if (num_layers != last_handles_.size()) {
+ ALOGE("SquashState::GenerateHistory expected %zu layers but got %zu layers",
+ last_handles_.size(), num_layers);
+ return;
+ }
+ std::bitset<kMaxLayers> changed_layers;
+ for (size_t i = 0; i < last_handles_.size(); i++) {
+ DrmHwcLayer *layer = &layers[i];
+ if (last_handles_[i] != layer->sf_handle) {
+ changed_layers.set(i);
+ }
+ }
+
+ for (size_t i = 0; i < regions_.size(); i++) {
+ changed_regions[i] = (regions_[i].layer_refs & changed_layers).any();
+ }
+}
+
+void SquashState::StableRegionsWithMarginalHistory(
+ const std::vector<bool> &changed_regions,
+ std::vector<bool> &stable_regions) const {
+ stable_regions.resize(regions_.size());
+ for (size_t i = 0; i < regions_.size(); i++) {
+ stable_regions[i] = !changed_regions[i] && is_stable(i);
+ }
+}
+
+void SquashState::RecordHistory(DrmHwcLayer *layers, size_t num_layers,
+ const std::vector<bool> &changed_regions) {
+ if (num_layers != last_handles_.size()) {
+ ALOGE("SquashState::RecordHistory expected %zu layers but got %zu layers",
+ last_handles_.size(), num_layers);
+ return;
+ }
+ if (changed_regions.size() != regions_.size()) {
+ ALOGE("SquashState::RecordHistory expected %zu regions but got %zu regions",
+ regions_.size(), changed_regions.size());
+ return;
+ }
+
+ for (size_t i = 0; i < last_handles_.size(); i++) {
+ DrmHwcLayer *layer = &layers[i];
+ last_handles_[i] = layer->sf_handle;
+ }
+
+ for (size_t i = 0; i < regions_.size(); i++) {
+ regions_[i].change_history <<= 1;
+ regions_[i].change_history.set(/* LSB */ 0, changed_regions[i]);
+ }
+
+ valid_history_++;
+}
+
+bool SquashState::RecordAndCompareSquashed(
+ const std::vector<bool> &squashed_regions) {
+ if (squashed_regions.size() != regions_.size()) {
+ ALOGE(
+ "SquashState::RecordAndCompareSquashed expected %zu regions but got "
+ "%zu regions",
+ regions_.size(), squashed_regions.size());
+ return false;
+ }
+ bool changed = false;
+ for (size_t i = 0; i < regions_.size(); i++) {
+ if (regions_[i].squashed != squashed_regions[i]) {
+ regions_[i].squashed = squashed_regions[i];
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+void SquashState::Dump(std::ostringstream *out) const {
+ *out << "----SquashState generation=" << generation_number_
+ << " history=" << valid_history_ << "\n"
+ << " Regions: count=" << regions_.size() << "\n";
+ for (size_t i = 0; i < regions_.size(); i++) {
+ const Region ®ion = regions_[i];
+ *out << " [" << i << "]"
+ << " history=" << region.change_history << " rect";
+ region.rect.Dump(out);
+ *out << " layers=(";
+ bool first = true;
+ for (size_t layer_index = 0; layer_index < kMaxLayers; layer_index++) {
+ if ((region.layer_refs &
+ std::bitset<kMaxLayers>((size_t)1 << layer_index))
+ .any()) {
+ if (!first)
+ *out << " ";
+ first = false;
+ *out << layer_index;
+ }
+ }
+ *out << ")";
+ if (region.squashed)
+ *out << " squashed";
+ *out << "\n";
+ }
+}
+
+static bool UsesSquash(const std::vector<DrmCompositionPlane> &comp_planes) {
+ return std::any_of(comp_planes.begin(), comp_planes.end(),
+ [](const DrmCompositionPlane &plane) {
+ return plane.source_layer ==
+ DrmCompositionPlane::kSourceSquash;
+ });
+}
+
+DrmDisplayCompositor::FrameWorker::FrameWorker(DrmDisplayCompositor *compositor)
+ : Worker("frame-worker", HAL_PRIORITY_URGENT_DISPLAY),
+ compositor_(compositor) {
+}
+
+DrmDisplayCompositor::FrameWorker::~FrameWorker() {
+}
+
+int DrmDisplayCompositor::FrameWorker::Init() {
+ return InitWorker();
+}
+
+void DrmDisplayCompositor::FrameWorker::QueueFrame(
+ std::unique_ptr<DrmDisplayComposition> composition, int status) {
+ Lock();
+ FrameState frame;
+ frame.composition = std::move(composition);
+ frame.status = status;
+ frame_queue_.push(std::move(frame));
+ SignalLocked();
+ Unlock();
+}
+
+void DrmDisplayCompositor::FrameWorker::Routine() {
+ int ret = Lock();
+ if (ret) {
+ ALOGE("Failed to lock worker, %d", ret);
+ return;
+ }
+
+ int wait_ret = 0;
+ if (frame_queue_.empty()) {
+ wait_ret = WaitForSignalOrExitLocked();
+ }
+
+ FrameState frame;
+ if (!frame_queue_.empty()) {
+ frame = std::move(frame_queue_.front());
+ frame_queue_.pop();
+ }
+
+ ret = Unlock();
+ if (ret) {
+ ALOGE("Failed to unlock worker, %d", ret);
+ return;
+ }
+
+ if (wait_ret == -EINTR) {
+ return;
+ } else if (wait_ret) {
+ ALOGE("Failed to wait for signal, %d", wait_ret);
+ return;
+ }
+
+ compositor_->ApplyFrame(std::move(frame.composition), frame.status);
+}
+
DrmDisplayCompositor::DrmDisplayCompositor()
: drm_(NULL),
display_(-1),
worker_(this),
+ frame_worker_(this),
initialized_(false),
active_(false),
needs_modeset_(false),
framebuffer_index_(0),
+ squash_framebuffer_index_(0),
dump_frames_composited_(0),
dump_last_timestamp_ns_(0) {
struct timespec ts;
@@ -61,6 +254,7 @@
return;
worker_.Exit();
+ frame_worker_.Exit();
int ret = pthread_mutex_lock(&lock_);
if (ret)
@@ -94,11 +288,22 @@
ALOGE("Failed to initialize compositor worker %d\n", ret);
return ret;
}
+ ret = frame_worker_.Init();
+ if (ret) {
+ pthread_mutex_destroy(&lock_);
+ ALOGE("Failed to initialize frame worker %d\n", ret);
+ return ret;
+ }
initialized_ = true;
return 0;
}
+std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition()
+ const {
+ return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition());
+}
+
int DrmDisplayCompositor::QueueComposition(
std::unique_ptr<DrmDisplayComposition> composition) {
switch (composition->type()) {
@@ -148,94 +353,248 @@
return 0;
}
-static bool drm_composition_layer_has_plane(
- const DrmCompositionLayer &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;
+std::tuple<uint32_t, uint32_t, int>
+DrmDisplayCompositor::GetActiveModeResolution() {
+ DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
+ if (connector == NULL) {
+ ALOGE("Failed to determine display mode: no connector for display %d",
+ display_);
+ return std::make_tuple(0, 0, -ENODEV);
+ }
+
+ const DrmMode &mode = connector->active_mode();
+ return std::make_tuple(mode.h_display(), mode.v_display(), 0);
}
-static bool drm_composition_layer_has_no_plane(
- const DrmCompositionLayer &comp_layer) {
- return comp_layer.plane == NULL;
+int DrmDisplayCompositor::PrepareFramebuffer(
+ DrmFramebuffer &fb, DrmDisplayComposition *display_comp) {
+ int ret = fb.WaitReleased(-1);
+ if (ret) {
+ ALOGE("Failed to wait for framebuffer release %d", ret);
+ return ret;
+ }
+ uint32_t width, height;
+ std::tie(width, height, ret) = GetActiveModeResolution();
+ if (ret) {
+ ALOGE(
+ "Failed to allocate framebuffer because the display resolution could "
+ "not be determined %d",
+ ret);
+ return ret;
+ }
+
+ fb.set_release_fence_fd(-1);
+ if (!fb.Allocate(width, height)) {
+ ALOGE("Failed to allocate framebuffer with size %dx%d", width, height);
+ return -ENOMEM;
+ }
+
+ display_comp->layers().emplace_back();
+ DrmHwcLayer &pre_comp_layer = display_comp->layers().back();
+ pre_comp_layer.sf_handle = fb.buffer()->handle;
+ pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, width, height);
+ pre_comp_layer.display_frame = DrmHwcRect<int>(0, 0, width, height);
+ ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
+ display_comp->importer());
+ if (ret) {
+ ALOGE("Failed to import framebuffer for display %d", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+int DrmDisplayCompositor::ApplySquash(DrmDisplayComposition *display_comp) {
+ int ret = 0;
+
+ DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_];
+ ret = PrepareFramebuffer(fb, display_comp);
+ if (ret) {
+ ALOGE("Failed to prepare framebuffer for squash %d", ret);
+ return ret;
+ }
+
+ std::vector<DrmCompositionRegion> ®ions = display_comp->squash_regions();
+ ret = pre_compositor_->Composite(display_comp->layers().data(),
+ regions.data(), regions.size(), fb.buffer());
+ pre_compositor_->Finish();
+
+ if (ret) {
+ ALOGE("Failed to squash layers");
+ return ret;
+ }
+
+ ret = display_comp->CreateNextTimelineFence();
+ if (ret <= 0) {
+ ALOGE("Failed to create squash framebuffer release fence %d", ret);
+ return ret;
+ }
+
+ fb.set_release_fence_fd(ret);
+ display_comp->SignalSquashDone();
+
+ return 0;
}
int DrmDisplayCompositor::ApplyPreComposite(
DrmDisplayComposition *display_comp) {
int ret = 0;
- std::vector<DrmCompositionLayer> *layers =
- display_comp->GetCompositionLayers();
- 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(fb.kReleaseWaitTimeoutMs);
+ ret = PrepareFramebuffer(fb, display_comp);
if (ret) {
- ALOGE("Failed to wait for framebuffer release %d", ret);
+ ALOGE("Failed to prepare framebuffer for pre-composite %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<DrmCompositionLayer> pre_comp_layers;
- for (auto &comp_layer : *layers) {
- if (comp_layer.plane == NULL) {
- pre_comp_layers.emplace_back(std::move(comp_layer));
- }
- }
-
- ret = pre_compositor_->Composite(pre_comp_layers.data(),
- pre_comp_layers.size(), fb.buffer());
+ std::vector<DrmCompositionRegion> ®ions = display_comp->pre_comp_regions();
+ ret = pre_compositor_->Composite(display_comp->layers().data(),
+ regions.data(), regions.size(), fb.buffer());
pre_compositor_->Finish();
if (ret) {
- ALOGE("Failed to composite layers");
+ ALOGE("Failed to pre-composite layers");
return ret;
}
- DrmCompositionLayer &pre_comp_layer =
- layers->at(display_comp->pre_composition_layer_index());
- ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
- display_comp->importer());
- if (ret) {
- ALOGE("Failed to import handle of layer %d", ret);
+ ret = display_comp->CreateNextTimelineFence();
+ if (ret <= 0) {
+ ALOGE("Failed to create pre-composite framebuffer release fence %d", ret);
return ret;
}
- pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, fb.buffer()->getWidth(),
- fb.buffer()->getHeight());
- pre_comp_layer.display_frame =
- DrmHwcRect<int>(0, 0, fb.buffer()->getWidth(), fb.buffer()->getHeight());
- // TODO(zachr) get a release fence
- // fb.set_release_fence_fd(pre_comp_layer.release_fence.Release());
- framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
+ fb.set_release_fence_fd(ret);
+ display_comp->SignalPreCompDone();
- display_comp->RemoveNoPlaneLayers();
- display_comp->SignalPreCompositionDone();
- return ret;
+ return 0;
}
-int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
+int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
+ drmModePropertySetPtr pset = drmModePropertySetAlloc();
+ if (!pset) {
+ ALOGE("Failed to allocate property set");
+ return -ENOMEM;
+ }
+
+ int ret;
+ std::vector<DrmCompositionPlane> &comp_planes =
+ display_comp->composition_planes();
+ for (DrmCompositionPlane &comp_plane : comp_planes) {
+ DrmPlane *plane = comp_plane.plane;
+ ret =
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
+ 0) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(), 0);
+ if (ret) {
+ ALOGE("Failed to add plane %d disable to pset", plane->id());
+ drmModePropertySetFree(pset);
+ return ret;
+ }
+ }
+
+ ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
+ if (ret) {
+ ALOGE("Failed to commit pset ret=%d\n", ret);
+ drmModePropertySetFree(pset);
+ return ret;
+ }
+
+ drmModePropertySetFree(pset);
+ return 0;
+}
+
+int DrmDisplayCompositor::PrepareFrame(DrmDisplayComposition *display_comp) {
int ret = 0;
- if (display_comp->pre_composition_layer_index() >= 0) {
+ std::vector<DrmHwcLayer> &layers = display_comp->layers();
+ std::vector<DrmCompositionPlane> &comp_planes =
+ display_comp->composition_planes();
+ std::vector<DrmCompositionRegion> &squash_regions =
+ display_comp->squash_regions();
+ std::vector<DrmCompositionRegion> &pre_comp_regions =
+ display_comp->pre_comp_regions();
+
+ int squash_layer_index = -1;
+ if (squash_regions.size() > 0) {
+ squash_framebuffer_index_ = (squash_framebuffer_index_ + 1) % 2;
+ ret = ApplySquash(display_comp);
+ if (ret)
+ return ret;
+
+ squash_layer_index = layers.size() - 1;
+ } else {
+ if (UsesSquash(comp_planes)) {
+ DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_];
+ layers.emplace_back();
+ squash_layer_index = layers.size() - 1;
+ DrmHwcLayer &squash_layer = layers.back();
+ ret = squash_layer.buffer.ImportBuffer(fb.buffer()->handle,
+ display_comp->importer());
+ if (ret) {
+ ALOGE("Failed to import old squashed framebuffer %d", ret);
+ return ret;
+ }
+ squash_layer.sf_handle = fb.buffer()->handle;
+ squash_layer.source_crop = DrmHwcRect<float>(
+ 0, 0, squash_layer.buffer->width, squash_layer.buffer->height);
+ squash_layer.display_frame = DrmHwcRect<int>(
+ 0, 0, squash_layer.buffer->width, squash_layer.buffer->height);
+ ret = display_comp->CreateNextTimelineFence();
+
+ if (ret <= 0) {
+ ALOGE("Failed to create squash framebuffer release fence %d", ret);
+ return ret;
+ }
+
+ fb.set_release_fence_fd(ret);
+ ret = 0;
+ }
+ }
+
+ bool do_pre_comp = pre_comp_regions.size() > 0;
+ int pre_comp_layer_index = -1;
+ if (do_pre_comp) {
ret = ApplyPreComposite(display_comp);
if (ret)
return ret;
+
+ pre_comp_layer_index = layers.size() - 1;
+ framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
}
+ for (DrmCompositionPlane &comp_plane : comp_planes) {
+ switch (comp_plane.source_layer) {
+ case DrmCompositionPlane::kSourceSquash:
+ comp_plane.source_layer = squash_layer_index;
+ break;
+ case DrmCompositionPlane::kSourcePreComp:
+ if (!do_pre_comp) {
+ ALOGE(
+ "Can not use pre composite framebuffer with no pre composite "
+ "regions");
+ return -EINVAL;
+ }
+ comp_plane.source_layer = pre_comp_layer_index;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp) {
+ int ret = 0;
+
+ std::vector<DrmHwcLayer> &layers = display_comp->layers();
+ std::vector<DrmCompositionPlane> &comp_planes =
+ display_comp->composition_planes();
+ std::vector<DrmCompositionRegion> &pre_comp_regions =
+ display_comp->pre_comp_regions();
+
+ DrmFramebuffer *pre_comp_fb;
+
DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
if (!connector) {
ALOGE("Could not locate connector for display %d", display_);
@@ -295,25 +654,83 @@
}
}
- std::vector<DrmCompositionLayer> *layers =
- display_comp->GetCompositionLayers();
- for (DrmCompositionLayer &layer : *layers) {
- int acquire_fence = layer.acquire_fence.get();
- if (acquire_fence >= 0) {
- ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
- if (ret) {
- ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
- drmModePropertySetFree(pset);
- drm_->DestroyPropertyBlob(blob_id);
- return ret;
+ for (DrmCompositionPlane &comp_plane : comp_planes) {
+ DrmPlane *plane = comp_plane.plane;
+ DrmCrtc *crtc = comp_plane.crtc;
+
+ int fb_id = -1;
+ DrmHwcRect<int> display_frame;
+ DrmHwcRect<float> source_crop;
+ uint64_t rotation = 0;
+ uint64_t alpha = 0xFF;
+ switch (comp_plane.source_layer) {
+ case DrmCompositionPlane::kSourceNone:
+ break;
+ case DrmCompositionPlane::kSourceSquash:
+ ALOGE("Actual source layer index expected for squash layer");
+ break;
+ case DrmCompositionPlane::kSourcePreComp:
+ ALOGE("Actual source layer index expected for pre-comp layer");
+ break;
+ default: {
+ if (comp_plane.source_layer >= layers.size()) {
+ ALOGE("Source layer index %zu out of bounds %zu",
+ comp_plane.source_layer, layers.size());
+ break;
+ }
+ DrmHwcLayer &layer = layers[comp_plane.source_layer];
+ if (layer.acquire_fence.get() >= 0) {
+ int acquire_fence = layer.acquire_fence.get();
+ for (int i = 0; i < kAcquireWaitTries; ++i) {
+ ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
+ if (ret)
+ ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
+ acquire_fence, i, ret, (i + 1) * kAcquireWaitTimeoutMs);
+ }
+ if (ret) {
+ ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
+ break;
+ }
+ layer.acquire_fence.Close();
+ }
+ if (!layer.buffer) {
+ ALOGE("Expected a valid framebuffer for pset");
+ break;
+ }
+ fb_id = layer.buffer->fb_id;
+ display_frame = layer.display_frame;
+ source_crop = layer.source_crop;
+ if (layer.blending == DrmHwcBlending::kPreMult)
+ alpha = layer.alpha;
+ switch (layer.transform) {
+ case DrmHwcTransform::kFlipH:
+ rotation = 1 << DRM_REFLECT_X;
+ break;
+ case DrmHwcTransform::kFlipV:
+ rotation = 1 << DRM_REFLECT_Y;
+ break;
+ case DrmHwcTransform::kRotate90:
+ rotation = 1 << DRM_ROTATE_90;
+ break;
+ case DrmHwcTransform::kRotate180:
+ rotation = 1 << DRM_ROTATE_180;
+ break;
+ case DrmHwcTransform::kRotate270:
+ rotation = 1 << DRM_ROTATE_270;
+ break;
+ case DrmHwcTransform::kIdentity:
+ rotation = 0;
+ break;
+ default:
+ ALOGE("Invalid transform value 0x%x given", layer.transform);
+ break;
+ }
+ break;
}
- layer.acquire_fence.Close();
}
- DrmPlane *plane = layer.plane;
-
- // Disable the plane if there's no crtc
- if (!layer.crtc) {
+ // Disable the plane if there's no framebuffer
+ if (fb_id < 0) {
ret = drmModePropertySetAdd(pset, plane->id(),
plane->crtc_property().id(), 0) ||
drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
@@ -325,40 +742,6 @@
continue;
}
- if (!layer.buffer) {
- ALOGE("Expected a valid framebuffer for pset");
- ret = -EINVAL;
- break;
- }
-
- uint64_t rotation;
- switch (layer.transform) {
- case DrmHwcTransform::kFlipH:
- rotation = 1 << DRM_REFLECT_X;
- break;
- case DrmHwcTransform::kFlipV:
- rotation = 1 << DRM_REFLECT_Y;
- break;
- case DrmHwcTransform::kRotate90:
- rotation = 1 << DRM_ROTATE_90;
- break;
- case DrmHwcTransform::kRotate180:
- rotation = 1 << DRM_ROTATE_180;
- break;
- case DrmHwcTransform::kRotate270:
- rotation = 1 << DRM_ROTATE_270;
- break;
- case DrmHwcTransform::kIdentity:
- rotation = 0;
- break;
- default:
- ALOGE("Invalid transform value 0x%x given", layer.transform);
- ret = -EINVAL;
- break;
- }
- if (ret)
- break;
-
// TODO: Once we have atomic test, this should fall back to GL
if (rotation && plane->rotation_property().id() == 0) {
ALOGE("Rotation is not supported on plane %d", plane->id());
@@ -366,31 +749,36 @@
break;
}
+ // TODO: Once we have atomic test, this should fall back to GL
+ if (alpha != 0xFF && plane->alpha_property().id() == 0) {
+ ALOGE("Alpha is not supported on plane %d", plane->id());
+ ret = -EINVAL;
+ break;
+ }
+
ret =
drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
- layer.crtc->id()) ||
+ crtc->id()) ||
drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
- layer.buffer->fb_id) ||
+ fb_id) ||
drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
- layer.display_frame.left) ||
+ display_frame.left) ||
drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
- layer.display_frame.top) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->crtc_w_property().id(),
- layer.display_frame.right - layer.display_frame.left) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->crtc_h_property().id(),
- layer.display_frame.bottom - layer.display_frame.top) ||
+ display_frame.top) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_w_property().id(),
+ display_frame.right - display_frame.left) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_h_property().id(),
+ display_frame.bottom - display_frame.top) ||
drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
- (int)(layer.source_crop.left) << 16) ||
+ (int)(source_crop.left) << 16) ||
drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
- (int)(layer.source_crop.top) << 16) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->src_w_property().id(),
- (int)(layer.source_crop.right - layer.source_crop.left) << 16) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->src_h_property().id(),
- (int)(layer.source_crop.bottom - layer.source_crop.top) << 16);
+ (int)(source_crop.top) << 16) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->src_w_property().id(),
+ (int)(source_crop.right - source_crop.left)
+ << 16) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->src_h_property().id(),
+ (int)(source_crop.bottom - source_crop.top)
+ << 16);
if (ret) {
ALOGE("Failed to add plane %d to set", plane->id());
break;
@@ -405,8 +793,19 @@
break;
}
}
+
+ if (plane->alpha_property().id()) {
+ ret = drmModePropertySetAdd(pset, plane->id(),
+ plane->alpha_property().id(), alpha);
+ if (ret) {
+ ALOGE("Failed to add alpha property %d to plane %d",
+ plane->alpha_property().id(), plane->id());
+ break;
+ }
+ }
}
+out:
if (!ret) {
ret = drmModePropertySetCommit(drm_->fd(), DRM_MODE_ATOMIC_ALLOW_MODESET,
drm_, pset);
@@ -460,6 +859,38 @@
return 0;
}
+void DrmDisplayCompositor::ApplyFrame(
+ std::unique_ptr<DrmDisplayComposition> composition, int status) {
+ int ret = status;
+
+ if (!ret)
+ ret = CommitFrame(composition.get());
+
+ if (ret) {
+ ALOGE("Composite failed for display %d", display_);
+
+ // Disable the hw used by the last active composition. This allows us to
+ // signal the release fences from that composition to avoid hanging.
+ if (DisablePlanes(active_composition_.get()))
+ return;
+ }
+ ++dump_frames_composited_;
+
+ if (active_composition_)
+ active_composition_->SignalCompositionDone();
+
+ ret = pthread_mutex_lock(&lock_);
+ if (ret)
+ ALOGE("Failed to acquire lock for active_composition swap");
+
+ active_composition_.swap(composition);
+
+ if (!ret)
+ ret = pthread_mutex_unlock(&lock_);
+ if (ret)
+ ALOGE("Failed to release lock for active_composition swap");
+}
+
int DrmDisplayCompositor::Composite() {
ATRACE_CALL();
@@ -497,12 +928,8 @@
switch (composition->type()) {
case DRM_COMPOSITION_TYPE_FRAME:
- ret = ApplyFrame(composition.get());
- if (ret) {
- ALOGE("Composite failed for display %d", display_);
- return ret;
- }
- ++dump_frames_composited_;
+ ret = PrepareFrame(composition.get());
+ frame_worker_.QueueFrame(std::move(composition), ret);
break;
case DRM_COMPOSITION_TYPE_DPMS:
ret = ApplyDpms(composition.get());
@@ -518,20 +945,6 @@
return -EINVAL;
}
- if (active_composition_)
- active_composition_->FinishComposition();
-
- ret = pthread_mutex_lock(&lock_);
- if (ret)
- ALOGE("Failed to acquire lock for active_composition swap");
-
- active_composition_.swap(composition);
-
- if (!ret)
- ret = pthread_mutex_unlock(&lock_);
- if (ret)
- ALOGE("Failed to release lock for active_composition swap");
-
return ret;
}
@@ -553,25 +966,7 @@
return empty_ret;
}
-struct DrmDumpLayer {
- int plane_id;
- int crtc_id;
- DrmHwcTransform transform;
- DrmHwcRect<float> source_crop;
- DrmHwcRect<int> display_frame;
-
- DrmDumpLayer(DrmCompositionLayer &rhs)
- : plane_id(rhs.plane->id()),
- crtc_id(rhs.crtc ? rhs.crtc->id() : -1),
- transform(rhs.transform),
- source_crop(rhs.source_crop),
- display_frame(rhs.display_frame) {
- }
-};
-
void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
- uint64_t cur_ts;
-
int ret = pthread_mutex_lock(&lock_);
if (ret)
return;
@@ -581,20 +976,12 @@
struct timespec ts;
ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-
- std::vector<DrmCompositionLayer> *input_layers =
- active_composition_->GetCompositionLayers();
- std::vector<DrmDumpLayer> layers;
- if (active_composition_)
- layers.insert(layers.begin(), input_layers->begin(), input_layers->end());
- else
- ret = -EAGAIN;
-
- ret |= pthread_mutex_unlock(&lock_);
- if (ret)
+ if (ret) {
+ pthread_mutex_unlock(&lock_);
return;
+ }
- cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+ uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
@@ -604,27 +991,11 @@
dump_last_timestamp_ns_ = cur_ts;
- *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
- for (std::vector<DrmDumpLayer>::iterator iter = layers.begin();
- iter != layers.end(); ++iter) {
- *out << "------ DrmDisplayCompositor Layer: plane=" << iter->plane_id
- << " ";
+ if (active_composition_)
+ active_composition_->Dump(out);
- if (iter->crtc_id < 0) {
- *out << "disabled\n";
- continue;
- }
+ squash_state_.Dump(out);
- *out << "crtc=" << iter->crtc_id
- << " crtc[x/y/w/h]=" << iter->display_frame.left << "/"
- << iter->display_frame.top << "/"
- << iter->display_frame.right - iter->display_frame.left << "/"
- << iter->display_frame.bottom - iter->display_frame.top << " "
- << " src[x/y/w/h]=" << iter->source_crop.left << "/"
- << iter->source_crop.top << "/"
- << iter->source_crop.right - iter->source_crop.left << "/"
- << iter->source_crop.bottom - iter->source_crop.top
- << " transform=" << (uint32_t)iter->transform << "\n";
- }
+ pthread_mutex_unlock(&lock_);
}
}
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 0f3a12f..e756fde 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -21,10 +21,13 @@
#include "drmcomposition.h"
#include "drmcompositorworker.h"
#include "drmframebuffer.h"
+#include "seperate_rects.h"
#include <pthread.h>
+#include <memory>
#include <queue>
#include <sstream>
+#include <tuple>
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
@@ -35,6 +38,47 @@
class GLWorkerCompositor;
+class SquashState {
+ public:
+ static const unsigned kHistoryLength = 6; // TODO: make this number not magic
+ static const unsigned kMaxLayers = 64;
+
+ struct Region {
+ DrmHwcRect<int> rect;
+ std::bitset<kMaxLayers> layer_refs;
+ std::bitset<kHistoryLength> change_history;
+ bool squashed = false;
+ };
+
+ bool is_stable(int region_index) const {
+ return valid_history_ >= kHistoryLength &&
+ regions_[region_index].change_history.none();
+ }
+
+ const std::vector<Region> ®ions() const {
+ return regions_;
+ }
+
+ void Init(DrmHwcLayer *layers, size_t num_layers);
+ void GenerateHistory(DrmHwcLayer *layers, size_t num_layers,
+ std::vector<bool> &changed_regions) const;
+ void StableRegionsWithMarginalHistory(
+ const std::vector<bool> &changed_regions,
+ std::vector<bool> &stable_regions) const;
+ void RecordHistory(DrmHwcLayer *layers, size_t num_layers,
+ const std::vector<bool> &changed_regions);
+ bool RecordAndCompareSquashed(const std::vector<bool> &squashed_regions);
+
+ void Dump(std::ostringstream *out) const;
+
+ private:
+ size_t generation_number_ = 0;
+ unsigned valid_history_ = 0;
+ std::vector<buffer_handle_t> last_handles_;
+
+ std::vector<Region> regions_;
+};
+
class DrmDisplayCompositor {
public:
DrmDisplayCompositor();
@@ -42,27 +86,66 @@
int Init(DrmResources *drm, int display);
+ std::unique_ptr<DrmDisplayComposition> CreateComposition() const;
int QueueComposition(std::unique_ptr<DrmDisplayComposition> composition);
int Composite();
void Dump(std::ostringstream *out) const;
+ std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution();
+
bool HaveQueuedComposites() const;
+ SquashState *squash_state() {
+ return &squash_state_;
+ }
+
private:
+ struct FrameState {
+ std::unique_ptr<DrmDisplayComposition> composition;
+ int status = 0;
+ };
+
+ class FrameWorker : public Worker {
+ public:
+ FrameWorker(DrmDisplayCompositor *compositor);
+ ~FrameWorker() override;
+
+ int Init();
+ void QueueFrame(std::unique_ptr<DrmDisplayComposition> composition,
+ int status);
+
+ protected:
+ void Routine() override;
+
+ private:
+ DrmDisplayCompositor *compositor_;
+ std::queue<FrameState> frame_queue_;
+ };
+
DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
- // Set to 83ms (~12fps) which is somewhere between a reasonable amount of
- // time to wait for a long render and a small enough delay to limit jank.
- static const int kAcquireWaitTimeoutMs = 83;
+ // We'll wait for acquire fences to fire for kAcquireWaitTimeoutMs,
+ // kAcquireWaitTries times, logging a warning in between.
+ static const int kAcquireWaitTries = 5;
+ static const int kAcquireWaitTimeoutMs = 100;
+ int PrepareFramebuffer(DrmFramebuffer &fb,
+ DrmDisplayComposition *display_comp);
+ int ApplySquash(DrmDisplayComposition *display_comp);
int ApplyPreComposite(DrmDisplayComposition *display_comp);
- int ApplyFrame(DrmDisplayComposition *display_comp);
+ int PrepareFrame(DrmDisplayComposition *display_comp);
+ int CommitFrame(DrmDisplayComposition *display_comp);
int ApplyDpms(DrmDisplayComposition *display_comp);
+ int DisablePlanes(DrmDisplayComposition *display_comp);
+
+ void ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,
+ int status);
DrmResources *drm_;
int display_;
DrmCompositorWorker worker_;
+ FrameWorker frame_worker_;
std::queue<std::unique_ptr<DrmDisplayComposition>> composite_queue_;
std::unique_ptr<DrmDisplayComposition> active_composition_;
@@ -77,6 +160,10 @@
DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS];
std::unique_ptr<GLWorkerCompositor> pre_compositor_;
+ SquashState squash_state_;
+ int squash_framebuffer_index_;
+ DrmFramebuffer squash_framebuffers_[2];
+
// mutable since we need to acquire in HaveQueuedComposites
mutable pthread_mutex_t lock_;
diff --git a/drmgenericimporter.h b/drmgenericimporter.h
index d509ed8..c362c17 100644
--- a/drmgenericimporter.h
+++ b/drmgenericimporter.h
@@ -27,12 +27,12 @@
class DrmGenericImporter : public Importer {
public:
DrmGenericImporter(DrmResources *drm);
- virtual ~DrmGenericImporter();
+ ~DrmGenericImporter() override;
int Init();
- virtual int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo);
- virtual int ReleaseBuffer(hwc_drm_bo_t *bo);
+ int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+ int ReleaseBuffer(hwc_drm_bo_t *bo) override;
private:
uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
diff --git a/drmhwcgralloc.h b/drmhwcgralloc.h
new file mode 100644
index 0000000..765c897
--- /dev/null
+++ b/drmhwcgralloc.h
@@ -0,0 +1,67 @@
+/*
+ * 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_DRMHWCGRALLOC_H_
+#define ANDROID_DRMHWCGRALLOC_H_
+
+#include <stdint.h>
+
+enum {
+ /* perform(const struct gralloc_module_t *mod,
+ * int op,
+ * int drm_fd,
+ * buffer_handle_t buffer,
+ * struct hwc_drm_bo *bo);
+ */
+ GRALLOC_MODULE_PERFORM_DRM_IMPORT = 0xffeeff00,
+
+ /* perform(const struct gralloc_module_t *mod,
+ * int op,
+ * buffer_handle_t buffer,
+ * void (*free_callback)(void *),
+ * void *priv);
+ */
+ GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE = 0xffeeff01,
+
+ /* perform(const struct gralloc_module_t *mod,
+ * int op,
+ * buffer_handle_t buffer,
+ * void (*free_callback)(void *),
+ * void **priv);
+ */
+ GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE = 0xffeeff02,
+
+ /* perform(const struct gralloc_module_t *mod,
+ * int op,
+ * buffer_handle_t buffer,
+ * int *usage);
+ */
+ GRALLOC_MODULE_PERFORM_GET_USAGE = 0xffeeff03,
+};
+
+typedef struct hwc_drm_bo {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format; /* DRM_FORMAT_* from drm_fourcc.h */
+ uint32_t pitches[4];
+ uint32_t offsets[4];
+ uint32_t gem_handles[4];
+ uint32_t fb_id;
+ int acquire_fence_fd;
+ void *priv;
+} hwc_drm_bo_t;
+
+#endif // ANDROID_DRMHWCGRALLOC_H_
diff --git a/drmmode.cpp b/drmmode.cpp
index 7f8c04d..2b558c9 100644
--- a/drmmode.cpp
+++ b/drmmode.cpp
@@ -36,6 +36,7 @@
v_sync_end_(m->vsync_end),
v_total_(m->vtotal),
v_scan_(m->vscan),
+ v_refresh_(m->vrefresh),
flags_(m->flags),
type_(m->type),
name_(m->name) {
@@ -54,6 +55,7 @@
v_sync_end_(0),
v_total_(0),
v_scan_(0),
+ v_refresh_(0),
flags_(0),
type_(0),
name_("") {
@@ -83,6 +85,7 @@
m->vsync_end = v_sync_end_;
m->vtotal = v_total_;
m->vscan = v_scan_;
+ m->vrefresh = v_refresh_;
m->flags = flags_;
m->type = type_;
strncpy(m->name, name_.c_str(), DRM_DISPLAY_MODE_LEN);
@@ -141,7 +144,8 @@
}
float DrmMode::v_refresh() const {
- return clock_ / (float)(v_total_ * h_total_) * 1000.0f;
+ return v_refresh_ ? v_refresh_ * 1.0f :
+ clock_ / (float)(v_total_ * h_total_) * 1000.0f;
}
uint32_t DrmMode::flags() const {
diff --git a/drmmode.h b/drmmode.h
index 3088b7a..1110ce8 100644
--- a/drmmode.h
+++ b/drmmode.h
@@ -71,6 +71,7 @@
uint32_t v_sync_end_;
uint32_t v_total_;
uint32_t v_scan_;
+ uint32_t v_refresh_;
uint32_t flags_;
uint32_t type_;
diff --git a/drmplane.cpp b/drmplane.cpp
index 3f17d7c..5785d5a 100644
--- a/drmplane.cpp
+++ b/drmplane.cpp
@@ -124,6 +124,10 @@
if (ret)
ALOGE("Could not get rotation property");
+ ret = drm_->GetPlaneProperty(*this, "alpha", &alpha_property_);
+ if (ret)
+ ALOGI("Could not get alpha property");
+
return 0;
}
@@ -182,4 +186,8 @@
const DrmProperty &DrmPlane::rotation_property() const {
return rotation_property_;
}
+
+const DrmProperty &DrmPlane::alpha_property() const {
+ return alpha_property_;
+}
}
diff --git a/drmplane.h b/drmplane.h
index 1969d52..ff3380f 100644
--- a/drmplane.h
+++ b/drmplane.h
@@ -52,6 +52,7 @@
const DrmProperty &src_w_property() const;
const DrmProperty &src_h_property() const;
const DrmProperty &rotation_property() const;
+ const DrmProperty &alpha_property() const;
private:
DrmPlane(const DrmPlane &);
@@ -74,6 +75,7 @@
DrmProperty src_w_property_;
DrmProperty src_h_property_;
DrmProperty rotation_property_;
+ DrmProperty alpha_property_;
};
}
diff --git a/glworker.cpp b/glworker.cpp
index 4cbe142..0b98a51 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
#include <string>
#include <sstream>
+#include <unordered_set>
#include <sys/resource.h>
@@ -37,8 +38,6 @@
#include "glworker.h"
-#include "seperate_rects.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
@@ -48,9 +47,6 @@
namespace android {
-typedef seperate_rects::Rect<float> FRect;
-typedef seperate_rects::RectSet<uint64_t, float> FRectSet;
-
// clang-format off
// Column-major order:
// float mat[4] = { 1, 2, 3, 4 } ===
@@ -153,13 +149,15 @@
static AutoGLShader CompileAndCheckShader(GLenum type, unsigned source_count,
const GLchar **sources,
- std::string *shader_log) {
+ std::ostringstream *shader_log) {
GLint status;
AutoGLShader shader(glCreateShader(type));
if (shader.get() == 0) {
- *shader_log = "glCreateShader failed";
+ if (shader_log)
+ *shader_log << "Failed glCreateShader call";
return 0;
}
+
glShaderSource(shader.get(), source_count, sources, NULL);
glCompileShader(shader.get());
glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status);
@@ -167,8 +165,14 @@
if (shader_log) {
GLint log_length;
glGetShaderiv(shader.get(), GL_INFO_LOG_LENGTH, &log_length);
- shader_log->resize(log_length);
- glGetShaderInfoLog(shader.get(), log_length, NULL, &(*shader_log)[0]);
+ std::string info_log(log_length, ' ');
+ glGetShaderInfoLog(shader.get(), log_length, NULL, &info_log.front());
+ *shader_log << "Failed to compile shader:\n" << info_log.c_str()
+ << "\nShader Source:\n";
+ for (unsigned i = 0; i < source_count; i++) {
+ *shader_log << sources[i];
+ }
+ *shader_log << "\n";
}
return 0;
}
@@ -176,118 +180,116 @@
return shader;
}
-static int GenerateShaders(std::vector<AutoGLProgram> *blend_programs) {
- // Limits: GL_MAX_VARYING_COMPONENTS, GL_MAX_TEXTURE_IMAGE_UNITS,
- // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
- // clang-format off
- const GLchar *shader_preamble = "#version 300 es\n#define LAYER_COUNT ";
+static std::string GenerateVertexShader(int layer_count) {
+ std::ostringstream vertex_shader_stream;
+ vertex_shader_stream
+ << "#version 300 es\n"
+ << "#define LAYER_COUNT " << layer_count << "\n"
+ << "precision mediump int;\n"
+ << "uniform vec4 uViewport;\n"
+ << "uniform vec4 uLayerCrop[LAYER_COUNT];\n"
+ << "uniform mat2 uTexMatrix[LAYER_COUNT];\n"
+ << "in vec2 vPosition;\n"
+ << "in vec2 vTexCoords;\n"
+ << "out vec2 fTexCoords[LAYER_COUNT];\n"
+ << "void main() {\n"
+ << " for (int i = 0; i < LAYER_COUNT; i++) {\n"
+ << " vec2 tempCoords = vTexCoords * uTexMatrix[i];\n"
+ << " fTexCoords[i] =\n"
+ << " uLayerCrop[i].xy + tempCoords * uLayerCrop[i].zw;\n"
+ << " }\n"
+ << " vec2 scaledPosition = uViewport.xy + vPosition * uViewport.zw;\n"
+ << " gl_Position =\n"
+ << " vec4(scaledPosition * vec2(2.0) - vec2(1.0), 0.0, 1.0);\n"
+ << "}\n";
+ return vertex_shader_stream.str();
+}
- const GLchar *vertex_shader_source =
-"\n"
-"precision mediump int; \n"
-"uniform vec4 uViewport; \n"
-"uniform vec4 uLayerCrop[LAYER_COUNT]; \n"
-"uniform mat2 uTexMatrix[LAYER_COUNT]; \n"
-"in vec2 vPosition; \n"
-"in vec2 vTexCoords; \n"
-"out vec2 fTexCoords[LAYER_COUNT]; \n"
-"void main() { \n"
-" for (int i = 0; i < LAYER_COUNT; i++) { \n"
-" vec2 tempCoords = vTexCoords * uTexMatrix[i]; \n"
-" fTexCoords[i] = uLayerCrop[i].xy + tempCoords * uLayerCrop[i].zw; \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"
-"} \n";
+static std::string GenerateFragmentShader(int layer_count) {
+ std::ostringstream fragment_shader_stream;
+ fragment_shader_stream << "#version 300 es\n"
+ << "#define LAYER_COUNT " << layer_count << "\n"
+ << "#extension GL_OES_EGL_image_external : require\n"
+ << "precision mediump float;\n";
+ for (int i = 0; i < layer_count; ++i) {
+ fragment_shader_stream << "uniform samplerExternalOES uLayerTexture" << i
+ << ";\n";
+ }
+ fragment_shader_stream << "uniform float uLayerAlpha[LAYER_COUNT];\n"
+ << "uniform float uLayerPremult[LAYER_COUNT];\n"
+ << "in vec2 fTexCoords[LAYER_COUNT];\n"
+ << "out vec4 oFragColor;\n"
+ << "void main() {\n"
+ << " vec3 color = vec3(0.0, 0.0, 0.0);\n"
+ << " float alphaCover = 1.0;\n"
+ << " vec4 texSample;\n"
+ << " vec3 multRgb;\n";
+ for (int i = 0; i < layer_count; ++i) {
+ if (i > 0)
+ fragment_shader_stream << " if (alphaCover > 0.5/255.0) {\n";
+ // clang-format off
+ fragment_shader_stream
+ << " texSample = texture2D(uLayerTexture" << i << ",\n"
+ << " fTexCoords[" << i << "]);\n"
+ << " multRgb = texSample.rgb *\n"
+ << " max(texSample.a, uLayerPremult[" << i << "]);\n"
+ << " color += multRgb * uLayerAlpha[" << i << "] * alphaCover;\n"
+ << " alphaCover *= 1.0 - texSample.a * uLayerAlpha[" << i << "];\n";
+ // clang-format on
+ }
+ for (int i = 0; i < layer_count - 1; ++i)
+ fragment_shader_stream << " }\n";
+ fragment_shader_stream << " oFragColor = vec4(color, 1.0 - alphaCover);\n"
+ << "}\n";
+ return fragment_shader_stream.str();
+}
- const GLchar *fragment_shader_source =
-"\n"
-"#extension GL_OES_EGL_image_external : require \n"
-"precision mediump float; \n"
-"uniform samplerExternalOES uLayerTextures[LAYER_COUNT]; \n"
-"uniform float uLayerAlpha[LAYER_COUNT]; \n"
-"in vec2 fTexCoords[LAYER_COUNT]; \n"
-"out vec4 oFragColor; \n"
-"void main() { \n"
-" vec3 color = vec3(0.0, 0.0, 0.0); \n"
-" float alphaCover = 1.0; \n"
-" for (int i = 0; i < LAYER_COUNT; i++) { \n"
-" vec4 texSample = texture2D(uLayerTextures[i], fTexCoords[i]); \n"
-" float a = texSample.a * uLayerAlpha[i]; \n"
-" color += a * alphaCover * texSample.rgb; \n"
-" alphaCover *= 1.0 - a; \n"
-" if (alphaCover <= 0.5/255.0) \n"
-" break; \n"
-" } \n"
-" oFragColor = vec4(color, 1.0 - alphaCover); \n"
-"} \n";
- // clang-format on
+static AutoGLProgram GenerateProgram(unsigned num_textures,
+ std::ostringstream *shader_log) {
+ std::string vertex_shader_string = GenerateVertexShader(num_textures);
+ const GLchar *vertex_shader_source = vertex_shader_string.c_str();
+ AutoGLShader vertex_shader = CompileAndCheckShader(
+ GL_VERTEX_SHADER, 1, &vertex_shader_source, shader_log);
+ if (!vertex_shader.get())
+ return 0;
- int i, ret = 1;
- GLint max_texture_images, status;
- AutoGLShader vertex_shader, fragment_shader;
- AutoGLProgram program;
- std::string shader_log;
+ std::string fragment_shader_string = GenerateFragmentShader(num_textures);
+ const GLchar *fragment_shader_source = fragment_shader_string.c_str();
+ AutoGLShader fragment_shader = CompileAndCheckShader(
+ GL_FRAGMENT_SHADER, 1, &fragment_shader_source, shader_log);
+ if (!fragment_shader.get())
+ return 0;
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_images);
-
- for (i = 1; i <= max_texture_images; i++) {
- std::ostringstream layer_count_formatter;
- layer_count_formatter << i;
- std::string layer_count(layer_count_formatter.str());
- const GLchar *shader_sources[3] = {shader_preamble, layer_count.c_str(),
- NULL};
-
- shader_sources[2] = vertex_shader_source;
- vertex_shader = CompileAndCheckShader(GL_VERTEX_SHADER, 3, shader_sources,
- ret ? &shader_log : NULL);
- if (!vertex_shader.get()) {
- if (ret)
- ALOGE("Failed to make vertex shader:\n%s", shader_log.c_str());
- break;
- }
-
- shader_sources[2] = fragment_shader_source;
- fragment_shader = CompileAndCheckShader(
- GL_FRAGMENT_SHADER, 3, shader_sources, ret ? &shader_log : NULL);
- if (!fragment_shader.get()) {
- if (ret)
- ALOGE("Failed to make fragment shader:\n%s", shader_log.c_str());
- break;
- }
-
- program = AutoGLProgram(glCreateProgram());
- if (!program.get()) {
- if (ret)
- ALOGE("Failed to create program %s", GetGLError());
- break;
- }
-
- glAttachShader(program.get(), vertex_shader.get());
- glAttachShader(program.get(), fragment_shader.get());
- glBindAttribLocation(program.get(), 0, "vPosition");
- glBindAttribLocation(program.get(), 1, "vTexCoords");
- glLinkProgram(program.get());
- glDetachShader(program.get(), vertex_shader.get());
- glDetachShader(program.get(), fragment_shader.get());
-
- glGetProgramiv(program.get(), GL_LINK_STATUS, &status);
- if (!status) {
- if (ret) {
- GLint log_length;
- glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &log_length);
- std::string program_log(log_length, ' ');
- glGetProgramInfoLog(program.get(), log_length, NULL, &program_log[0]);
- ALOGE("Failed to link program: \n%s", program_log.c_str());
- }
- break;
- }
-
- ret = 0;
- blend_programs->emplace_back(std::move(program));
+ AutoGLProgram program(glCreateProgram());
+ if (!program.get()) {
+ if (shader_log)
+ *shader_log << "Failed to create program: " << GetGLError() << "\n";
+ return 0;
}
- return ret;
+ glAttachShader(program.get(), vertex_shader.get());
+ glAttachShader(program.get(), fragment_shader.get());
+ glBindAttribLocation(program.get(), 0, "vPosition");
+ glBindAttribLocation(program.get(), 1, "vTexCoords");
+ glLinkProgram(program.get());
+ glDetachShader(program.get(), vertex_shader.get());
+ glDetachShader(program.get(), fragment_shader.get());
+
+ GLint status;
+ glGetProgramiv(program.get(), GL_LINK_STATUS, &status);
+ if (!status) {
+ if (shader_log) {
+ GLint log_length;
+ glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &log_length);
+ std::string program_log(log_length, ' ');
+ glGetProgramInfoLog(program.get(), log_length, NULL,
+ &program_log.front());
+ *shader_log << "Failed to link program:\n" << program_log.c_str() << "\n";
+ }
+ return 0;
+ }
+
+ return program;
}
struct RenderingCommand {
@@ -295,130 +297,103 @@
unsigned texture_index;
float crop_bounds[4];
float alpha;
+ float premult;
float texture_matrix[4];
};
float bounds[4];
- unsigned texture_count;
+ unsigned texture_count = 0;
TextureSource textures[MAX_OVERLAPPING_LAYERS];
-
- RenderingCommand() : texture_count(0) {
- }
};
-static void ConstructCommands(DrmCompositionLayer *layers, size_t num_layers,
- std::vector<RenderingCommand> *commands) {
- std::vector<FRect> in_rects;
- std::vector<FRectSet> out_rects;
- int i;
+static void ConstructCommand(const DrmHwcLayer *layers,
+ const DrmCompositionRegion ®ion,
+ RenderingCommand &cmd) {
+ std::copy_n(region.frame.bounds, 4, cmd.bounds);
- for (unsigned rect_index = 0; rect_index < num_layers; rect_index++) {
- DrmCompositionLayer &layer = layers[rect_index];
- in_rects.emplace_back(layer.display_frame);
- }
+ for (size_t texture_index : region.source_layers) {
+ const DrmHwcLayer &layer = layers[texture_index];
- seperate_frects_64(in_rects, &out_rects);
+ DrmHwcRect<float> display_rect(layer.display_frame);
+ float display_size[2] = {display_rect.bounds[2] - display_rect.bounds[0],
+ display_rect.bounds[3] - display_rect.bounds[1]};
- for (unsigned rect_index = 0; rect_index < out_rects.size(); rect_index++) {
- const FRectSet &out_rect = out_rects[rect_index];
- commands->push_back(RenderingCommand());
- RenderingCommand &cmd = commands->back();
+ float tex_width = layer.buffer->width;
+ float tex_height = layer.buffer->height;
+ DrmHwcRect<float> crop_rect(layer.source_crop.left / tex_width,
+ layer.source_crop.top / tex_height,
+ layer.source_crop.right / tex_width,
+ layer.source_crop.bottom / tex_height);
- for (int i = 0; i < 4; i++)
- cmd.bounds[i] = out_rect.rect.bounds[i];
+ float crop_size[2] = {crop_rect.bounds[2] - crop_rect.bounds[0],
+ crop_rect.bounds[3] - crop_rect.bounds[1]};
- uint64_t tex_set = out_rect.id_set.getBits();
- for (unsigned i = num_layers - 1; tex_set != 0x0; i--) {
- if (tex_set & (0x1 << i)) {
- tex_set &= ~(0x1 << i);
+ RenderingCommand::TextureSource &src = cmd.textures[cmd.texture_count];
+ cmd.texture_count++;
+ src.texture_index = texture_index;
- DrmCompositionLayer &layer = layers[i];
+ bool swap_xy, flip_xy[2];
+ switch (layer.transform) {
+ case DrmHwcTransform::kFlipH:
+ swap_xy = false;
+ flip_xy[0] = true;
+ flip_xy[1] = false;
+ break;
+ case DrmHwcTransform::kFlipV:
+ swap_xy = false;
+ flip_xy[0] = false;
+ flip_xy[1] = true;
+ break;
+ case DrmHwcTransform::kRotate90:
+ swap_xy = true;
+ flip_xy[0] = false;
+ flip_xy[1] = true;
+ break;
+ case DrmHwcTransform::kRotate180:
+ swap_xy = false;
+ flip_xy[0] = true;
+ flip_xy[1] = true;
+ break;
+ case DrmHwcTransform::kRotate270:
+ swap_xy = true;
+ flip_xy[0] = true;
+ flip_xy[1] = false;
+ break;
+ default:
+ ALOGE("Unknown transform for layer: defaulting to identity transform");
+ case DrmHwcTransform::kIdentity:
+ swap_xy = false;
+ flip_xy[0] = false;
+ flip_xy[1] = false;
+ break;
+ }
- FRect display_rect(layer.display_frame);
- float display_size[2] = {
- display_rect.bounds[2] - display_rect.bounds[0],
- display_rect.bounds[3] - display_rect.bounds[1]};
+ if (swap_xy)
+ std::copy_n(&kTextureTransformMatrices[4], 4, src.texture_matrix);
+ else
+ std::copy_n(&kTextureTransformMatrices[0], 4, src.texture_matrix);
- float tex_width = layer.buffer->width;
- float tex_height = layer.buffer->height;
- FRect crop_rect(layer.source_crop.left / tex_width,
- layer.source_crop.top / tex_height,
- layer.source_crop.right / tex_width,
- layer.source_crop.bottom / tex_height);
-
- float crop_size[2] = {crop_rect.bounds[2] - crop_rect.bounds[0],
- crop_rect.bounds[3] - crop_rect.bounds[1]};
-
- RenderingCommand::TextureSource &src = cmd.textures[cmd.texture_count];
- cmd.texture_count++;
- src.texture_index = i;
-
- bool swap_xy, flip_xy[2];
- switch (layer.transform) {
- case DrmHwcTransform::kFlipH:
- swap_xy = false;
- flip_xy[0] = true;
- flip_xy[1] = false;
- break;
- case DrmHwcTransform::kFlipV:
- swap_xy = false;
- flip_xy[0] = false;
- flip_xy[1] = true;
- break;
- case DrmHwcTransform::kRotate90:
- swap_xy = true;
- flip_xy[0] = false;
- flip_xy[1] = true;
- break;
- case DrmHwcTransform::kRotate180:
- swap_xy = false;
- flip_xy[0] = true;
- flip_xy[1] = true;
- break;
- case DrmHwcTransform::kRotate270:
- swap_xy = true;
- flip_xy[0] = true;
- flip_xy[1] = false;
- break;
- default:
- ALOGE(
- "Unknown transform for layer: defaulting to identity "
- "transform");
- case DrmHwcTransform::kIdentity:
- swap_xy = false;
- flip_xy[0] = false;
- flip_xy[1] = false;
- break;
- }
-
- 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 == DrmHwcBlending::kNone) {
- src.alpha = 1.0f;
- // This layer is opaque. There is no point in using layers below this
- // one.
- break;
- }
-
- src.alpha = layer.alpha / 255.0f;
+ 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 == DrmHwcBlending::kNone) {
+ src.alpha = src.premult = 1.0f;
+ // This layer is opaque. There is no point in using layers below this one.
+ break;
+ }
+
+ src.alpha = layer.alpha / 255.0f;
+ src.premult = (layer.blending == DrmHwcBlending::kPreMult) ? 1.0f : 0.0f;
}
}
@@ -564,7 +539,10 @@
glBindBuffer(GL_ARRAY_BUFFER, 0);
vertex_buffer_.reset(vertex_buffer);
- if (GenerateShaders(&blend_programs_)) {
+ std::ostringstream shader_log;
+ blend_programs_.emplace_back(GenerateProgram(1, &shader_log));
+ if (blend_programs_.back().get() == 0) {
+ ALOGE("%s", shader_log.str().c_str());
return 1;
}
@@ -577,16 +555,16 @@
ALOGE("Failed to destroy OpenGL ES Context: %s", GetEGLError());
}
-int GLWorkerCompositor::Composite(DrmCompositionLayer *layers,
- size_t num_layers,
+int GLWorkerCompositor::Composite(DrmHwcLayer *layers,
+ DrmCompositionRegion *regions,
+ size_t num_regions,
const sp<GraphicBuffer> &framebuffer) {
ATRACE_CALL();
int ret = 0;
- size_t i;
std::vector<AutoEGLImageAndGLTexture> layer_textures;
std::vector<RenderingCommand> commands;
- if (num_layers == 0) {
+ if (num_regions == 0) {
return -EALREADY;
}
@@ -599,10 +577,24 @@
return -EINVAL;
}
- for (i = 0; i < num_layers; i++) {
- DrmCompositionLayer *layer = &layers[i];
+ std::unordered_set<size_t> layers_used_indices;
+ for (size_t region_index = 0; region_index < num_regions; region_index++) {
+ DrmCompositionRegion ®ion = regions[region_index];
+ layers_used_indices.insert(region.source_layers.begin(),
+ region.source_layers.end());
+ commands.emplace_back();
+ ConstructCommand(layers, region, commands.back());
+ }
+
+ for (size_t layer_index = 0; layer_index < MAX_OVERLAPPING_LAYERS;
+ layer_index++) {
+ DrmHwcLayer *layer = &layers[layer_index];
layer_textures.emplace_back();
+
+ if (layers_used_indices.count(layer_index) == 0)
+ continue;
+
ret = CreateTextureFromHandle(egl_display_, layer->get_usable_handle(),
&layer_textures.back());
@@ -618,8 +610,6 @@
if (ret)
return ret;
- ConstructCommands(layers, num_layers, &commands);
-
glViewport(0, 0, frame_width, frame_height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -634,24 +624,23 @@
glEnable(GL_SCISSOR_TEST);
for (const RenderingCommand &cmd : commands) {
- if (cmd.texture_count <= 0) {
+ if (cmd.texture_count == 0)
continue;
- }
// TODO(zachr): handle the case of too many overlapping textures for one
// area by falling back to rendering as many layers as possible using
// multiple blending passes.
- if (cmd.texture_count > blend_programs_.size()) {
+ GLint program = PrepareAndCacheProgram(cmd.texture_count);
+ if (program == 0) {
ALOGE("Too many layers to render in one area");
continue;
}
- GLint program = blend_programs_[cmd.texture_count - 1].get();
glUseProgram(program);
GLint gl_viewport_loc = glGetUniformLocation(program, "uViewport");
- GLint gl_tex_loc = glGetUniformLocation(program, "uLayerTextures");
GLint gl_crop_loc = glGetUniformLocation(program, "uLayerCrop");
GLint gl_alpha_loc = glGetUniformLocation(program, "uLayerAlpha");
+ GLint gl_premult_loc = glGetUniformLocation(program, "uLayerPremult");
GLint gl_tex_matrix_loc = glGetUniformLocation(program, "uTexMatrix");
glUniform4f(gl_viewport_loc, cmd.bounds[0] / (float)frame_width,
cmd.bounds[1] / (float)frame_height,
@@ -659,12 +648,18 @@
(cmd.bounds[3] - cmd.bounds[1]) / (float)frame_height);
for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) {
+ std::ostringstream texture_name_formatter;
+ texture_name_formatter << "uLayerTexture" << src_index;
+ GLint gl_tex_loc =
+ glGetUniformLocation(program, texture_name_formatter.str().c_str());
+
const RenderingCommand::TextureSource &src = cmd.textures[src_index];
glUniform1f(gl_alpha_loc + src_index, src.alpha);
+ glUniform1f(gl_premult_loc + src_index, src.premult);
glUniform4f(gl_crop_loc + src_index, src.crop_bounds[0],
src.crop_bounds[1], src.crop_bounds[2] - src.crop_bounds[0],
src.crop_bounds[3] - src.crop_bounds[1]);
- glUniform1i(gl_tex_loc + src_index, src_index);
+ glUniform1i(gl_tex_loc, src_index);
glUniformMatrix2fv(gl_tex_matrix_loc + src_index, 1, GL_FALSE,
src.texture_matrix);
glActiveTexture(GL_TEXTURE0 + src_index);
@@ -793,4 +788,22 @@
return &cached_framebuffers_.back();
}
+GLint GLWorkerCompositor::PrepareAndCacheProgram(unsigned texture_count) {
+ if (blend_programs_.size() >= texture_count) {
+ GLint program = blend_programs_[texture_count - 1].get();
+ if (program != 0)
+ return program;
+ }
+
+ AutoGLProgram program = GenerateProgram(texture_count, NULL);
+ if (program.get() != 0) {
+ if (blend_programs_.size() < texture_count)
+ blend_programs_.resize(texture_count);
+ blend_programs_[texture_count - 1] = std::move(program);
+ return blend_programs_[texture_count - 1].get();
+ }
+
+ return 0;
+}
+
} // namespace android
diff --git a/glworker.h b/glworker.h
index b3163ce..222cf6f 100644
--- a/glworker.h
+++ b/glworker.h
@@ -33,7 +33,8 @@
namespace android {
-struct DrmCompositionLayer;
+struct DrmHwcLayer;
+struct DrmCompositionRegion;
class GLWorkerCompositor {
public:
@@ -41,8 +42,8 @@
~GLWorkerCompositor();
int Init();
- int Composite(DrmCompositionLayer *layers, size_t num_layers,
- const sp<GraphicBuffer> &framebuffer);
+ int Composite(DrmHwcLayer *layers, DrmCompositionRegion *regions,
+ size_t num_regions, const sp<GraphicBuffer> &framebuffer);
void Finish();
private:
@@ -67,6 +68,8 @@
CachedFramebuffer *PrepareAndCacheFramebuffer(
const sp<GraphicBuffer> &framebuffer);
+ GLint PrepareAndCacheProgram(unsigned texture_count);
+
EGLDisplay egl_display_;
EGLContext egl_ctx_;
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index a7c9e43..de5c66f 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -46,7 +46,6 @@
#include <utils/Trace.h>
#define UM_PER_INCH 25400
-#define HWC_FB_BUFFERS 3
namespace android {
@@ -130,7 +129,7 @@
typedef std::map<int, hwc_drm_display_t> DisplayMap;
typedef DisplayMap::iterator DisplayMapIter;
- hwc_context_t() : procs(NULL), importer(NULL), use_framebuffer_target(false) {
+ hwc_context_t() : procs(NULL), importer(NULL) {
}
~hwc_context_t() {
@@ -146,7 +145,6 @@
Importer *importer;
const gralloc_module_t *gralloc;
DummySwSyncTimeline dummy_timeline;
- bool use_framebuffer_target;
VirtualCompositorWorker virtual_compositor_worker;
};
@@ -191,9 +189,9 @@
return *this;
}
-hwc_drm_bo *DrmHwcBuffer::operator->() {
+const hwc_drm_bo *DrmHwcBuffer::operator->() const {
if (importer_ == NULL) {
- ALOGE("Access of none existent BO");
+ ALOGE("Access of non-existent BO");
exit(1);
return NULL;
}
@@ -264,16 +262,15 @@
int DrmHwcLayer::InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer,
const gralloc_module_t *gralloc) {
sf_handle = sf_layer->handle;
- int ret = buffer.ImportBuffer(sf_layer->handle, importer);
- if (ret)
- return ret;
-
- ret = handle.CopyBufferHandle(sf_layer->handle, gralloc);
- if (ret)
- return ret;
-
alpha = sf_layer->planeAlpha;
+ source_crop = DrmHwcRect<float>(
+ sf_layer->sourceCropf.left, sf_layer->sourceCropf.top,
+ sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom);
+ display_frame = DrmHwcRect<int>(
+ sf_layer->displayFrame.left, sf_layer->displayFrame.top,
+ sf_layer->displayFrame.right, sf_layer->displayFrame.bottom);
+
switch (sf_layer->transform) {
case 0:
transform = DrmHwcTransform::kIdentity;
@@ -313,12 +310,25 @@
return -EINVAL;
}
- source_crop = DrmHwcRect<float>(
- sf_layer->sourceCropf.left, sf_layer->sourceCropf.top,
- sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom);
- display_frame = DrmHwcRect<int>(
- sf_layer->displayFrame.left, sf_layer->displayFrame.top,
- sf_layer->displayFrame.right, sf_layer->displayFrame.bottom);
+ int ret = buffer.ImportBuffer(sf_layer->handle, importer);
+ if (ret)
+ return ret;
+
+ ret = handle.CopyBufferHandle(sf_layer->handle, gralloc);
+ if (ret)
+ return ret;
+
+ ret = gralloc->perform(gralloc, GRALLOC_MODULE_PERFORM_GET_USAGE,
+ handle.get(), &gralloc_buffer_usage);
+ if (ret) {
+ // TODO(zachr): Once GRALLOC_MODULE_PERFORM_GET_USAGE is implemented, remove
+ // "ret = 0" and enable the error logging code.
+ ret = 0;
+#if 0
+ ALOGE("Failed to get usage for buffer %p (%d)", handle.get(), ret);
+ return ret;
+#endif
+ }
return 0;
}
@@ -330,26 +340,20 @@
ctx->drm.compositor()->Dump(&out);
std::string out_str = out.str();
- strncpy(buff, out_str.c_str(), std::min((size_t)buff_len, out_str.length()));
+ strncpy(buff, out_str.c_str(),
+ std::min((size_t)buff_len, out_str.length() + 1));
+ buff[buff_len - 1] = '\0';
}
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;
- bool use_framebuffer_target = ctx->use_framebuffer_target;
+ bool use_framebuffer_target = false;
if (i == HWC_DISPLAY_VIRTUAL) {
use_framebuffer_target = true;
} else {
@@ -447,15 +451,10 @@
if (sf_layer->flags & HWC_SKIP_LAYER)
continue;
- if (!ctx->use_framebuffer_target) {
- if (sf_layer->compositionType == HWC_OVERLAY)
- indices_to_composite.push_back(j);
- if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
- framebuffer_target_index = j;
- } else {
- if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
- indices_to_composite.push_back(j);
- }
+ if (sf_layer->compositionType == HWC_OVERLAY)
+ indices_to_composite.push_back(j);
+ if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
+ framebuffer_target_index = j;
layer.acquire_fence.Set(sf_layer->acquireFenceFd);
sf_layer->acquireFenceFd = -1;
@@ -470,23 +469,15 @@
layer.release_fence = OutputFd(&sf_layer->releaseFenceFd);
}
- 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());
+ if (indices_to_composite.empty() && framebuffer_target_index >= 0) {
+ hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index];
+ if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) {
+ ALOGE(
+ "Expected valid layer with HWC_FRAMEBUFFER_TARGET when all "
+ "HWC_OVERLAY layers are skipped.");
ret = -EINVAL;
}
- } else {
- if (indices_to_composite.empty() && framebuffer_target_index >= 0) {
- hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index];
- if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) {
- ALOGE(
- "Expected valid layer with HWC_FRAMEBUFFER_TARGET when all "
- "HWC_OVERLAY layers are skipped.");
- ret = -EINVAL;
- }
- indices_to_composite.push_back(framebuffer_target_index);
- }
+ indices_to_composite.push_back(framebuffer_target_index);
}
}
@@ -496,18 +487,25 @@
for (size_t i = 0; i < num_displays; ++i) {
hwc_display_contents_1_t *dc = sf_display_contents[i];
DrmHwcDisplayContents &display_contents = displays_contents[i];
- if (!sf_display_contents[i])
+ if (!sf_display_contents[i] || i == HWC_DISPLAY_VIRTUAL)
continue;
layers_map.emplace_back();
DrmCompositionDisplayLayersMap &map = layers_map.back();
+ map.display = i;
+ map.geometry_changed =
+ (dc->flags & HWC_GEOMETRY_CHANGED) == HWC_GEOMETRY_CHANGED;
std::vector<size_t> &indices_to_composite = layers_indices[i];
for (size_t j : indices_to_composite) {
hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
DrmHwcLayer &layer = display_contents.layers[j];
- layer.InitFromHwcLayer(sf_layer, ctx->importer, ctx->gralloc);
+ ret = layer.InitFromHwcLayer(sf_layer, ctx->importer, ctx->gralloc);
+ if (ret) {
+ ALOGE("Failed to init composition from layer %d", ret);
+ return ret;
+ }
map.layers.emplace_back(std::move(layer));
}
}
@@ -589,7 +587,8 @@
*value = 1000 * 1000 * 1000 / 60;
break;
case HWC_DISPLAY_TYPES_SUPPORTED:
- *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL | HWC_DISPLAY_VIRTUAL;
+ *value = HWC_DISPLAY_PRIMARY_BIT | HWC_DISPLAY_EXTERNAL_BIT |
+ HWC_DISPLAY_VIRTUAL_BIT;
break;
}
return 0;
diff --git a/nvimporter.cpp b/nvimporter.cpp
index de3ed55..d5c3abc 100644
--- a/nvimporter.cpp
+++ b/nvimporter.cpp
@@ -157,10 +157,15 @@
gem_close.handle = bo->gem_handles[i];
int ret = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
- if (ret)
+ if (ret) {
ALOGE("Failed to close gem handle %d %d", i, ret);
- else
+ } else {
+ /* Clear any duplicate gem handle as well but don't close again */
+ for (int j = i + 1; j < num_gem_handles; j++)
+ if (bo->gem_handles[j] == bo->gem_handles[i])
+ bo->gem_handles[j] = 0;
bo->gem_handles[i] = 0;
+ }
}
}
diff --git a/nvimporter.h b/nvimporter.h
index a07f577..d6033db 100644
--- a/nvimporter.h
+++ b/nvimporter.h
@@ -29,12 +29,12 @@
class NvImporter : public Importer {
public:
NvImporter(DrmResources *drm);
- virtual ~NvImporter();
+ ~NvImporter() override;
int Init();
- virtual int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo);
- virtual int ReleaseBuffer(hwc_drm_bo_t *bo);
+ int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+ int ReleaseBuffer(hwc_drm_bo_t *bo) override;
private:
typedef struct NvBuffer {
diff --git a/seperate_rects.cpp b/seperate_rects.cpp
index bdf07bc..06fbe39 100644
--- a/seperate_rects.cpp
+++ b/seperate_rects.cpp
@@ -71,8 +71,8 @@
}
template <typename TNum, typename TId>
-void seperate_rects(const std::vector<Rect<TNum> > &in,
- std::vector<RectSet<TId, TNum> > *out) {
+void seperate_rects(const std::vector<Rect<TNum>> &in,
+ std::vector<RectSet<TId, TNum>> *out) {
// Overview:
// This algorithm is a line sweep algorithm that travels from left to right.
// The sweep stops at each vertical edge of each input rectangle in sorted
@@ -91,8 +91,8 @@
// Events are when the sweep line encounters the starting or ending edge of
// any input rectangle.
- std::set<SweepEvent<TId, TNum> > sweep_h_events; // Left or right bounds
- std::set<SweepEvent<TId, TNum> > sweep_v_events; // Top or bottom bounds
+ std::set<SweepEvent<TId, TNum>> sweep_h_events; // Left or right bounds
+ std::set<SweepEvent<TId, TNum>> sweep_v_events; // Top or bottom bounds
// A started rect is a rectangle whose left, top, bottom edge, and set of
// rectangle IDs is known. The key of this map includes all that information
@@ -102,7 +102,7 @@
// This is cleared after every event. Its declaration is here to avoid
// reallocating a vector and its buffers every event.
- std::vector<std::pair<TNum, IdSet<TId> > > active_regions;
+ std::vector<std::pair<TNum, IdSet<TId>>> active_regions;
// This pass will add rectangle start and end events to be triggered as the
// algorithm sweeps from left to right.
@@ -120,7 +120,7 @@
sweep_h_events.insert(evt);
}
- for (typename std::set<SweepEvent<TId, TNum> >::iterator it =
+ for (typename std::set<SweepEvent<TId, TNum>>::iterator it =
sweep_h_events.begin();
it != sweep_h_events.end(); ++it) {
const SweepEvent<TId, TNum> &h_evt = *it;
@@ -142,14 +142,14 @@
} else {
v_evt.type = START;
v_evt.y = rect.top;
- typename std::set<SweepEvent<TId, TNum> >::iterator start_it =
+ typename std::set<SweepEvent<TId, TNum>>::iterator start_it =
sweep_v_events.find(v_evt);
assert(start_it != sweep_v_events.end());
sweep_v_events.erase(start_it);
v_evt.type = END;
v_evt.y = rect.bottom;
- typename std::set<SweepEvent<TId, TNum> >::iterator end_it =
+ typename std::set<SweepEvent<TId, TNum>>::iterator end_it =
sweep_v_events.find(v_evt);
assert(end_it != sweep_v_events.end());
sweep_v_events.erase(end_it);
@@ -159,7 +159,7 @@
// with the current sweep line. If so, we want to continue marking up the
// sweep line before actually processing the rectangles the sweep line is
// intersecting.
- typename std::set<SweepEvent<TId, TNum> >::iterator next_it = it;
+ typename std::set<SweepEvent<TId, TNum>>::iterator next_it = it;
++next_it;
if (next_it != sweep_h_events.end()) {
if (next_it->x == h_evt.x) {
@@ -179,7 +179,7 @@
// 5), active_regions will be [({ 0 }, 3), {}, 5].
active_regions.clear();
IdSet<TId> active_set;
- for (typename std::set<SweepEvent<TId, TNum> >::iterator it =
+ for (typename std::set<SweepEvent<TId, TNum>>::iterator it =
sweep_v_events.begin();
it != sweep_v_events.end(); ++it) {
const SweepEvent<TId, TNum> &v_evt = *it;
@@ -199,7 +199,7 @@
#ifdef RECTS_DEBUG
std::cout << "x:" << h_evt.x;
- for (std::vector<std::pair<TNum, IdSet> >::iterator it =
+ for (std::vector<std::pair<TNum, IdSet>>::iterator it =
active_regions.begin();
it != active_regions.end(); ++it) {
std::cout << " " << it->first << "(" << it->second << ")"
@@ -226,7 +226,7 @@
// case, we have a new rectangle, and the already existing started rectangle
// will not be marked as seen ("true" in the std::pair) and will get ended
// by the for loop after this one. This is as intended.
- for (typename std::vector<std::pair<TNum, IdSet<TId> > >::iterator it =
+ for (typename std::vector<std::pair<TNum, IdSet<TId>>>::iterator it =
active_regions.begin();
it != active_regions.end(); ++it) {
IdSet<TId> region_set = it->second;
@@ -237,8 +237,7 @@
// An important property of active_regions is that each region where a set
// of rectangles applies is bounded at the bottom by the next (in the
// vector) region's starting y-coordinate.
- typename std::vector<std::pair<TNum, IdSet<TId> > >::iterator next_it =
- it;
+ typename std::vector<std::pair<TNum, IdSet<TId>>>::iterator next_it = it;
++next_it;
assert(next_it != active_regions.end());
@@ -300,8 +299,13 @@
}
}
-void seperate_frects_64(const std::vector<Rect<float> > &in,
- std::vector<RectSet<uint64_t, float> > *out) {
+void seperate_frects_64(const std::vector<Rect<float>> &in,
+ std::vector<RectSet<uint64_t, float>> *out) {
+ seperate_rects(in, out);
+}
+
+void seperate_rects_64(const std::vector<Rect<int>> &in,
+ std::vector<RectSet<uint64_t, int>> *out) {
seperate_rects(in, out);
}
diff --git a/seperate_rects.h b/seperate_rects.h
index 540a5e8..0703c97 100644
--- a/seperate_rects.h
+++ b/seperate_rects.h
@@ -18,6 +18,8 @@
#define DRM_HWCOMPOSER_SEPERATE_RECTS_H_
#include <stdint.h>
+
+#include <sstream>
#include <vector>
namespace seperate_rects {
@@ -64,6 +66,23 @@
return true;
}
+
+ TFloat width() const {
+ return bounds[2] - bounds[0];
+ }
+
+ TFloat height() const {
+ return bounds[3] - bounds[1];
+ }
+
+ TFloat area() const {
+ return width() * height();
+ }
+
+ void Dump(std::ostringstream *out) const {
+ *out << "[x/y/w/h]=" << left << "/" << top << "/" << width() << "/"
+ << height();
+ }
};
template <typename TUInt>
@@ -140,8 +159,10 @@
// rectangle indices that overlap the output rectangle encoded in a bitset. For
// example, an output rectangle that overlaps input rectangles in[0], in[1], and
// in[4], the bitset would be (ommitting leading zeroes) 10011.
-void seperate_frects_64(const std::vector<Rect<float> > &in,
- std::vector<RectSet<uint64_t, float> > *out);
+void seperate_frects_64(const std::vector<Rect<float>> &in,
+ std::vector<RectSet<uint64_t, float>> *out);
+void seperate_rects_64(const std::vector<Rect<int>> &in,
+ std::vector<RectSet<uint64_t, int>> *out);
} // namespace seperate_rects
diff --git a/virtualcompositorworker.cpp b/virtualcompositorworker.cpp
index e7acef0..ea46461 100644
--- a/virtualcompositorworker.cpp
+++ b/virtualcompositorworker.cpp
@@ -35,10 +35,10 @@
static const int kAcquireWaitTimeoutMs = 50;
VirtualCompositorWorker::VirtualCompositorWorker()
- : Worker("virtual-compositor", HAL_PRIORITY_URGENT_DISPLAY)
- , timeline_fd_(-1)
- , timeline_(0)
- , timeline_current_(0) {
+ : Worker("virtual-compositor", HAL_PRIORITY_URGENT_DISPLAY),
+ timeline_fd_(-1),
+ timeline_(0),
+ timeline_current_(0) {
}
VirtualCompositorWorker::~VirtualCompositorWorker() {
diff --git a/virtualcompositorworker.h b/virtualcompositorworker.h
index 4a15f0c..3066547 100644
--- a/virtualcompositorworker.h
+++ b/virtualcompositorworker.h
@@ -27,13 +27,13 @@
class VirtualCompositorWorker : public Worker {
public:
VirtualCompositorWorker();
- ~VirtualCompositorWorker();
+ ~VirtualCompositorWorker() override;
int Init();
void QueueComposite(hwc_display_contents_1_t *dc);
protected:
- virtual void Routine();
+ void Routine() override;
private:
struct VirtualComposition {
diff --git a/vsyncworker.h b/vsyncworker.h
index ce7b94a..98ac546 100644
--- a/vsyncworker.h
+++ b/vsyncworker.h
@@ -31,7 +31,7 @@
class VSyncWorker : public Worker {
public:
VSyncWorker();
- ~VSyncWorker();
+ ~VSyncWorker() override;
int Init(DrmResources *drm, int display);
int SetProcs(hwc_procs_t const *procs);
@@ -39,7 +39,7 @@
int VSyncControl(bool enabled);
protected:
- virtual void Routine();
+ void Routine() override;
private:
int64_t GetPhasedVSync(int64_t frame_ns, int64_t current);