OSDN Git Service

drm_hwcomposer: Create mode blob on modeset queue
[android-x86/external-drm_hwcomposer.git] / drmdisplaycompositor.cpp
index c3042f5..bcd1a14 100644 (file)
 #define LOG_TAG "hwc-drm-display-compositor"
 
 #include "drmdisplaycompositor.h"
-#include "drmcrtc.h"
-#include "drmplane.h"
-#include "drmresources.h"
-#include "glworker.h"
 
 #include <pthread.h>
 #include <sched.h>
-#include <sstream>
 #include <stdlib.h>
 #include <time.h>
+#include <sstream>
 #include <vector>
 
-#include <drm/drm_mode.h>
 #include <cutils/log.h>
+#include <drm/drm_mode.h>
 #include <sync/sync.h>
 #include <utils/Trace.h>
 
-#define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 3
+#include "autolock.h"
+#include "drmcrtc.h"
+#include "drmplane.h"
+#include "drmresources.h"
+#include "glworker.h"
+
+#define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 2
 
 namespace android {
 
@@ -52,10 +54,10 @@ void SquashState::Init(DrmHwcLayer *layers, size_t num_layers) {
     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);
+  std::vector<separate_rects::RectSet<uint64_t, int>> out_regions;
+  separate_rects::separate_rects_64(in_rects, &out_regions);
 
-  for (const seperate_rects::RectSet<uint64_t, int> &out_region : out_regions) {
+  for (const separate_rects::RectSet<uint64_t, int> &out_region : out_regions) {
     regions_.emplace_back();
     Region &region = regions_.back();
     region.rect = out_region.rect;
@@ -74,9 +76,10 @@ void SquashState::GenerateHistory(DrmHwcLayer *layers, size_t num_layers,
   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) {
+    // Protected layers can't be squashed so we treat them as constantly
+    // changing.
+    if (layer->protected_usage() || last_handles_[i] != layer->sf_handle)
       changed_layers.set(i);
-    }
   }
 
   for (size_t i = 0; i < regions_.size(); i++) {
@@ -174,13 +177,70 @@ static bool UsesSquash(const std::vector<DrmCompositionPlane> &comp_planes) {
                      });
 }
 
+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),
@@ -196,11 +256,17 @@ DrmDisplayCompositor::~DrmDisplayCompositor() {
     return;
 
   worker_.Exit();
+  frame_worker_.Exit();
 
   int ret = pthread_mutex_lock(&lock_);
   if (ret)
     ALOGE("Failed to acquire compositor lock %d", ret);
 
+  if (mode_.blob_id)
+    drm_->DestroyPropertyBlob(mode_.blob_id);
+  if (mode_.old_blob_id)
+    drm_->DestroyPropertyBlob(mode_.old_blob_id);
+
   while (!composite_queue_.empty()) {
     composite_queue_.front().reset();
     composite_queue_.pop();
@@ -229,6 +295,12 @@ int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
     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;
@@ -327,6 +399,7 @@ int DrmDisplayCompositor::PrepareFramebuffer(
   display_comp->layers().emplace_back();
   DrmHwcLayer &pre_comp_layer = display_comp->layers().back();
   pre_comp_layer.sf_handle = fb.buffer()->handle;
+  pre_comp_layer.blending = DrmHwcBlending::kCoverage;
   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,
@@ -438,7 +511,7 @@ int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
   return 0;
 }
 
-int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
+int DrmDisplayCompositor::PrepareFrame(DrmDisplayComposition *display_comp) {
   int ret = 0;
 
   std::vector<DrmHwcLayer> &layers = display_comp->layers();
@@ -470,6 +543,7 @@ int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
         return ret;
       }
       squash_layer.sf_handle = fb.buffer()->handle;
+      squash_layer.blending = DrmHwcBlending::kCoverage;
       squash_layer.source_crop = DrmHwcRect<float>(
           0, 0, squash_layer.buffer->width, squash_layer.buffer->height);
       squash_layer.display_frame = DrmHwcRect<int>(
@@ -497,6 +571,41 @@ int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
     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) {
+  ATRACE_CALL();
+
+  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_);
@@ -514,44 +623,14 @@ int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
     return -ENOMEM;
   }
 
-  uint32_t blob_id = 0;
-  uint64_t old_blob_id;
-  if (needs_modeset_) {
-    DrmProperty old_mode;
-    ret = drm_->GetCrtcProperty(*crtc, crtc->mode_property().name().c_str(),
-                                &old_mode);
-    if (ret) {
-      ALOGE("Failed to get old mode property from crtc %d", crtc->id());
-      drmModePropertySetFree(pset);
-      return ret;
-    }
-    ret = old_mode.value(&old_blob_id);
-    if (ret) {
-      ALOGE("Could not get old blob id value %d", ret);
-      drmModePropertySetFree(pset);
-      return ret;
-    }
-
-    struct drm_mode_modeinfo drm_mode;
-    memset(&drm_mode, 0, sizeof(drm_mode));
-    next_mode_.ToDrmModeModeInfo(&drm_mode);
-
-    ret = drm_->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
-                                   &blob_id);
-    if (ret) {
-      ALOGE("Failed to create mode property blob %d", ret);
-      drmModePropertySetFree(pset);
-      return ret;
-    }
-
+  if (mode_.needs_modeset) {
     ret = drmModePropertySetAdd(pset, crtc->id(), crtc->mode_property().id(),
-                                blob_id) ||
+                                mode_.blob_id) ||
           drmModePropertySetAdd(pset, connector->id(),
                                 connector->crtc_id_property().id(), crtc->id());
     if (ret) {
-      ALOGE("Failed to add blob %d to pset", blob_id);
+      ALOGE("Failed to add blob %d to pset", mode_.blob_id);
       drmModePropertySetFree(pset);
-      drm_->DestroyPropertyBlob(blob_id);
       return ret;
     }
   }
@@ -568,27 +647,12 @@ int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
     switch (comp_plane.source_layer) {
       case DrmCompositionPlane::kSourceNone:
         break;
-      case DrmCompositionPlane::kSourceSquash: {
-        DrmHwcLayer &layer = layers[squash_layer_index];
-        fb_id = layer.buffer->fb_id;
-        display_frame = layer.display_frame;
-        source_crop = layer.source_crop;
+      case DrmCompositionPlane::kSourceSquash:
+        ALOGE("Actual source layer index expected for squash layer");
         break;
-      }
-      case DrmCompositionPlane::kSourcePreComp: {
-        if (!do_pre_comp) {
-          ALOGE(
-              "Can not use pre composite framebuffer with no pre composite "
-              "regions");
-          ret = -EINVAL;
-          goto out;
-        }
-        DrmHwcLayer &layer = layers[pre_comp_layer_index];
-        fb_id = layer.buffer->fb_id;
-        display_frame = layer.display_frame;
-        source_crop = layer.source_crop;
+      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",
@@ -729,19 +793,17 @@ out:
     if (ret) {
       ALOGE("Failed to commit pset ret=%d\n", ret);
       drmModePropertySetFree(pset);
-      if (needs_modeset_)
-        drm_->DestroyPropertyBlob(blob_id);
       return ret;
     }
   }
   if (pset)
     drmModePropertySetFree(pset);
 
-  if (needs_modeset_) {
-    ret = drm_->DestroyPropertyBlob(old_blob_id);
+  if (mode_.needs_modeset) {
+    ret = drm_->DestroyPropertyBlob(mode_.old_blob_id);
     if (ret) {
-      ALOGE("Failed to destroy old mode property blob %lld/%d", old_blob_id,
-            ret);
+      ALOGE("Failed to destroy old mode property blob %lld/%d",
+            mode_.old_blob_id, ret);
       return ret;
     }
 
@@ -752,8 +814,10 @@ out:
       return ret;
     }
 
-    connector->set_active_mode(next_mode_);
-    needs_modeset_ = false;
+    connector->set_active_mode(mode_.mode);
+    mode_.old_blob_id = mode_.blob_id;
+    mode_.blob_id = 0;
+    mode_.needs_modeset = false;
   }
 
   return ret;
@@ -776,6 +840,55 @@ int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
   return 0;
 }
 
+std::tuple<int, uint32_t> DrmDisplayCompositor::CreateModeBlob(
+    const DrmMode &mode) {
+  struct drm_mode_modeinfo drm_mode;
+  memset(&drm_mode, 0, sizeof(drm_mode));
+  mode.ToDrmModeModeInfo(&drm_mode);
+
+  uint32_t id = 0;
+  int ret = drm_->CreatePropertyBlob(&drm_mode,
+                                     sizeof(struct drm_mode_modeinfo), &id);
+  if (ret) {
+    ALOGE("Failed to create mode property blob %d", ret);
+    return std::make_tuple(ret, 0);
+  }
+  ALOGE("Create blob_id %ld\n", id);
+  return std::make_tuple(ret, id);
+}
+
+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();
 
@@ -813,16 +926,8 @@ int DrmDisplayCompositor::Composite() {
 
   switch (composition->type()) {
     case DRM_COMPOSITION_TYPE_FRAME:
-      ret = ApplyFrame(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 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());
@@ -830,28 +935,21 @@ int DrmDisplayCompositor::Composite() {
         ALOGE("Failed to apply dpms for display %d", display_);
       return ret;
     case DRM_COMPOSITION_TYPE_MODESET:
-      next_mode_ = composition->display_mode();
-      needs_modeset_ = true;
+      mode_.mode = composition->display_mode();
+      if (mode_.blob_id)
+        drm_->DestroyPropertyBlob(mode_.blob_id);
+      std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode);
+      if (ret) {
+        ALOGE("Failed to create mode blob for display %d", display_);
+        return ret;
+      }
+      mode_.needs_modeset = true;
       return 0;
     default:
       ALOGE("Unknown composition type %d", composition->type());
       return -EINVAL;
   }
 
-  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");
-
   return ret;
 }
 
@@ -873,6 +971,128 @@ bool DrmDisplayCompositor::HaveQueuedComposites() const {
   return empty_ret;
 }
 
+int DrmDisplayCompositor::SquashAll() {
+  AutoLock lock(&lock_, "compositor");
+  int ret = lock.Lock();
+  if (ret)
+    return ret;
+
+  if (!active_composition_)
+    return 0;
+
+  if (active_composition_->type() != DRM_COMPOSITION_TYPE_FRAME)
+    return 0;
+
+  DrmDisplayComposition &active_comp = *active_composition_;
+  std::vector<DrmCompositionPlane> &active_planes =
+      active_comp.composition_planes();
+  std::vector<DrmHwcLayer> &active_layers = active_comp.layers();
+
+  // Make sure there is more than one layer to squash.
+  size_t active_planes_with_layer = std::count_if(
+      active_planes.begin(), active_planes.end(), [](DrmCompositionPlane &p) {
+        return p.source_layer <= DrmCompositionPlane::kSourceLayerMax;
+      });
+  if (active_planes_with_layer <= 1)
+    return 0;
+
+  int pre_comp_layer_index;
+
+  std::unique_ptr<DrmDisplayComposition> comp = CreateComposition();
+  ret = comp->Init(drm_, active_comp.crtc(), active_comp.importer(),
+                   active_comp.frame_no());
+  if (ret) {
+    ALOGE("Failed to init squash all composition %d", ret);
+    return ret;
+  }
+
+  std::vector<DrmPlane *> primary_planes;
+  std::vector<DrmPlane *> fake_overlay_planes;
+  std::vector<DrmHwcLayer> comp_layers;
+  for (DrmCompositionPlane &comp_plane : active_planes) {
+    // Composition planes without DRM planes should never happen
+    if (comp_plane.plane == NULL) {
+      ALOGE("Skipping squash all because of NULL plane");
+      goto move_layers_back;
+    }
+
+    if (comp_plane.source_layer == DrmCompositionPlane::kSourceNone)
+      continue;
+
+    // Out of range layers should never happen. If they do, somebody probably
+    // forgot to replace the symbolic names (kSourceSquash, kSourcePreComp) with
+    // real ones.
+    if (comp_plane.source_layer >= active_layers.size()) {
+      ALOGE("Skipping squash all because of out of range source layer %zu",
+            comp_plane.source_layer);
+      goto move_layers_back;
+    }
+
+    DrmHwcLayer &layer = active_layers[comp_plane.source_layer];
+
+    // Squashing protected layers is impossible.
+    if (layer.protected_usage())
+      goto move_layers_back;
+
+    // The OutputFds point to freed memory after hwc_set returns. They are
+    // returned to the default to prevent DrmDisplayComposition::Plan from
+    // filling the OutputFds.
+    layer.release_fence = OutputFd();
+    comp_layers.emplace_back(std::move(layer));
+
+    if (comp_plane.plane->type() == DRM_PLANE_TYPE_PRIMARY &&
+        primary_planes.size() == 0)
+      primary_planes.push_back(comp_plane.plane);
+    else
+      comp->AddPlaneDisable(comp_plane.plane);
+  }
+
+  ret = comp->SetLayers(comp_layers.data(), comp_layers.size(), false);
+  if (ret) {
+    ALOGE("Failed to set layers for squash all composition %d", ret);
+    goto move_layers_back;
+  }
+
+  ret =
+      comp->Plan(NULL /* SquashState */, &primary_planes, &fake_overlay_planes);
+  if (ret) {
+    ALOGE("Failed to plan for squash all composition %d", ret);
+    goto move_layers_back;
+  }
+
+  ret = ApplyPreComposite(comp.get());
+  if (ret) {
+    ALOGE("Failed to pre-composite for squash all composition %d", ret);
+    goto move_layers_back;
+  }
+
+  pre_comp_layer_index = comp->layers().size() - 1;
+  framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
+
+  for (DrmCompositionPlane &plane : comp->composition_planes())
+    if (plane.source_layer == DrmCompositionPlane::kSourcePreComp)
+      plane.source_layer = pre_comp_layer_index;
+
+  // ApplyFrame needs the lock
+  lock.Unlock();
+
+  ApplyFrame(std::move(comp), 0);
+
+  return 0;
+
+// TODO(zachr): think of a better way to transfer ownership back to the active
+// composition.
+move_layers_back:
+  for (size_t plane_index = 0;
+       plane_index < active_planes.size() && plane_index < comp_layers.size();
+       plane_index++) {
+    size_t source_layer_index = active_planes[plane_index].source_layer;
+    active_layers[source_layer_index] = std::move(comp_layers[plane_index]);
+  }
+
+  return ret;
+}
+
 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
   int ret = pthread_mutex_lock(&lock_);
   if (ret)