[TTVD] Allow overlay usage with linear format planes 10/314810/6
authorJakub Gajownik <j.gajownik2@samsung.com>
Wed, 3 Jul 2024 09:47:01 +0000 (11:47 +0200)
committerBot Blink <blinkbot@samsung.com>
Fri, 19 Jul 2024 15:05:27 +0000 (15:05 +0000)
Now when it's possible to render data using scanout
buffers, we can extend support for overlay promotion.
Before this CL, only decoder collection could be promoted
to use dedicated output surface. This patch reduces need
for collection when software rendering is about to be used.
Such change allows us to render MJPEG data captured in the
camera component using overlay system in future.

Bug: https://jira-eu.sec.samsung.net/browse/VDGAME-532
Change-Id: I2d95815a55b5a16d4255672a36a88c5252f6e654
Signed-off-by: Jakub Gajownik <j.gajownik2@samsung.com>
components/viz/service/display/overlay_processor_tizen.cc
media/capture/video/tizen/gpu_memory_buffer_tracker_tizen.cc
media/filters/tizen/nv12_data.h
tizen_src/chromium_impl/ui/ozone/platform/efl/efl_surface_factory.cc
tizen_src/chromium_impl/ui/ozone/platform/efl/output_surface_impl.cc
tizen_src/chromium_impl/ui/ozone/platform/efl/output_surface_impl.h
tizen_src/chromium_impl/ui/ozone/platform/efl/output_surface_state.h
tizen_src/chromium_impl/ui/ozone/platform/efl/tizen_native_pixmap.cc
tizen_src/chromium_impl/ui/ozone/platform/efl/tizen_native_pixmap.h
tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_software.cc

index 847e282e57225587f6437dfd31c1277305ddc1f3..e0748c482e316f9b7476bb2318edf2b841aa1b81 100644 (file)
@@ -309,13 +309,18 @@ void OverlayProcessorTizen::ProcessForOverlays(
       continue;
     }
 
-    if (!tizen_pixmap->PeekHandle().picture_id) {
-      LOG(ERROR) << "No picture id under mailbox: "
+    if (tizen_pixmap->PeekHandle().picture_id) {
+      pair_candidates.emplace_back(candidate.mailbox,
+                                   *tizen_pixmap->PeekHandle().picture_id);
+    } else if (tizen_pixmap->PeekHandle().modifier ==
+               ui::kFormatModifierLinear) {
+      // For now, stay with default token, since we should not have multiple
+      // videos without |picture_id|.
+      pair_candidates.emplace_back(candidate.mailbox, base::UnguessableToken{});
+    } else {
+      LOG(ERROR) << "Cannot determine token under mailbox: "
                  << candidate.mailbox.ToDebugString();
-      continue;
     }
-    pair_candidates.emplace_back(candidate.mailbox,
-                                 *tizen_pixmap->PeekHandle().picture_id);
   }
 
   auto assigned_surfaces =
@@ -364,13 +369,19 @@ void OverlayProcessorTizen::ProcessForOverlays(
       continue;
     }
 
-    in_tree_textures_.erase(*tizen_pixmap->PeekHandle().picture_id);
+    const auto picture_id = tizen_pixmap->PeekHandle().picture_id.value_or(
+        base::UnguessableToken{});
+
+    in_tree_textures_.erase(picture_id);
+
+    const bool has_texture_planes = tizen_pixmap->GetNumberOfPlanes() != 0;
+    const bool is_linear_framebuffer =
+        tizen_pixmap->PeekHandle().modifier == ui::kFormatModifierLinear;
 
     auto prepare_result = surface_proxy->PrepareToRender(
-        *tizen_pixmap->PeekHandle().picture_id,
-        tizen_pixmap->GetNumberOfPlanes() != 0,
+        picture_id, has_texture_planes && !is_linear_framebuffer,
         base::BindRepeating(&OverlayProcessorTizen::NotifyMode, weak_this_,
-                            *tizen_pixmap->PeekHandle().picture_id));
+                            picture_id));
     prepare_results_.emplace((*candidates)[i].mailbox,
                              std::make_pair(surface_proxy, prepare_result));
     if (prepare_result != gfx::VideoOutputMode::kOverlay) {
@@ -528,20 +539,21 @@ void OverlayProcessorTizen::ScheduleOverlaysOnGpu(
       continue;
     }
     auto* tizen_pixmap = reinterpret_cast<ui::TizenNativePixmap*>(pixmap.get());
-    last_promotions_.erase(tizen_pixmap->PeekHandle().picture_id.value());
-    if (it->second.second != gfx::VideoOutputMode::kTexture) {
-      promotions.emplace(tizen_pixmap->PeekHandle().picture_id.value());
-    }
+    if (tizen_pixmap->PeekHandle().picture_id) {
+      last_promotions_.erase(tizen_pixmap->PeekHandle().picture_id.value());
+      if (it->second.second != gfx::VideoOutputMode::kTexture) {
+        promotions.emplace(tizen_pixmap->PeekHandle().picture_id.value());
+      }
 
-    auto collection = plane_collection_manager_->Collection(
-        tizen_pixmap->PeekHandle().picture_id.value());
-    if (collection) {
-      collection->NotifyModeChange(it->second.second);
-    } else {
-      LOG(ERROR) << "Cannot find overlay: "
-                 << tizen_pixmap->PeekHandle().picture_id->ToString();
+      auto collection = plane_collection_manager_->Collection(
+          tizen_pixmap->PeekHandle().picture_id.value());
+      if (collection) {
+        collection->NotifyModeChange(it->second.second);
+      } else {
+        LOG(ERROR) << "Cannot find overlay: "
+                   << tizen_pixmap->PeekHandle().picture_id->ToString();
+      }
     }
-
     PaintSingleOnGpu(candidate.mailbox, it->second.first,
                      OverlayPlaneDataFromCandidate(candidate));
   }
@@ -698,11 +710,12 @@ base::flat_set<base::UnguessableToken> OverlayProcessorTizen::FindAllVideoQuads(
       }
 
       auto* tizen_pixmap = static_cast<ui::TizenNativePixmap*>(pixmap.get());
-      if (!tizen_pixmap->PeekHandle().picture_id) {
-        continue;
+      if (tizen_pixmap->PeekHandle().picture_id) {
+        result.emplace(*tizen_pixmap->PeekHandle().picture_id);
+      } else if (tizen_pixmap->PeekHandle().modifier ==
+                 ui::kFormatModifierLinear) {
+        result.emplace(base::UnguessableToken{});
       }
-
-      result.emplace(*tizen_pixmap->PeekHandle().picture_id);
     }
   }
   return result;
index 0c8fc02c5420ea2c9398921b4479b6b7e894ef3b..aaac74a5d52d9aa13519d42e0324d780c6b36e4b 100644 (file)
@@ -61,6 +61,9 @@ bool GpuMemoryBufferTrackerTizen::Init(const gfx::Size& dimensions,
                                 plane_size.GetArea(), buffer->ExportFd());
     offset += plane_size.GetArea();
   }
+
+  constexpr uint64_t kFormatModifierLinear = 0;
+  handle_.modifier = kFormatModifierLinear;
   return true;
 }
 
index cb7e235bf321755a3ce0c06c3a56c5822806aa4b..c4afde9a4e729d95977bce75ef710b67243c394d 100644 (file)
@@ -15,11 +15,13 @@ struct NV12Data {
   // through Graphic Accelerator. Note that it's not DMA related file
   // descriptor, but another platform specific concept.
   uint32_t y_phys_data;
+  uint64_t y_phys_offset = 0;
   uint32_t y_stride;
 
   uint8_t* uv_data;
   // Same as |y_phys_data| except it's handle to UV plane.
   uint32_t uv_phys_data;
+  uint64_t uv_phys_offset = 0;
   uint32_t uv_stride;
 };
 
index d90ca15d3f5e6aacb5901f1b67383ac79412a23c..e0af5c6e1b6712788d7dd849bffad11dc6dae61c 100644 (file)
@@ -154,8 +154,8 @@ EflSurfaceFactory::CreateNativePixmapFromHandle(
     gfx::Size size,
     gfx::BufferFormat format,
     gfx::NativePixmapHandle handle) {
-  return base::MakeRefCounted<ui::TizenNativePixmap>(this, std::move(handle),
-                                                     plane_collection_manager_);
+  return base::MakeRefCounted<ui::TizenNativePixmap>(
+      this, std::move(handle), size, plane_collection_manager_);
 }
 
 scoped_refptr<OutputSurfaceProxy> EflSurfaceFactory::GetSurface(
index e7fd54800b680bea80a99cec6e8f30b14bb0bdaa..a58148c2cf590b6bdd357596b31b435355b1e34f 100644 (file)
@@ -271,11 +271,6 @@ gfx::VideoOutputMode OutputSurfaceImpl::PrepareToRender(
 
 void OutputSurfaceImpl::Render(const gfx::OverlayPlaneData& overlay_plane_data,
                                gfx::OverlayRenderData render_data) {
-  if (!render_data.plane_id) {
-    TIZEN_MEDIA_LOG(ERROR) << "Invalid plane id: " << render_data.plane_id;
-    return;
-  }
-
   if (last_picture_plane_ && render_data.picture_size.IsZero()) {
     if (last_picture_plane_ != render_data.plane_id) {
       TIZEN_MEDIA_LOG(INFO)
@@ -345,6 +340,13 @@ void OutputSurfaceImpl::Render(const gfx::OverlayPlaneData& overlay_plane_data,
     damage_rect_ = overlay_plane_data.damage_rect;
   }
 
+  if (pending_source_change_ || !last_picture_plane_) {
+    if (!SelectRenderingMethod(render_data)) {
+      return;
+    }
+    video_surface_.PreparePlane(render_data, current_rendering_method_);
+  }
+
   const bool recalculate_geometry = rotation_changed || picture_size_changed ||
                                     display_bounds_changed ||
                                     crop_rect_changed || damage_changed;
@@ -353,23 +355,11 @@ void OutputSurfaceImpl::Render(const gfx::OverlayPlaneData& overlay_plane_data,
   if (!recalculate_geometry && !pending_source_change_ && last_picture_plane_ &&
       last_picture_plane_.value() == render_data.plane_id &&
       last_picture_timestamp_ &&
-      last_picture_timestamp_.value() == render_data.timestamp) {
+      last_picture_timestamp_.value() == render_data.timestamp &&
+      !uses_software_rendering_) {
     return;
   }
 
-  if (pending_source_change_ || !last_picture_plane_) {
-    if (IsSoftwareRenderingCapable(render_data) && render_data.low_latency &&
-        rendering_workarounds_.prefer_manual_rendering_for_low_latency) {
-      TIZEN_MEDIA_LOG(INFO) << "Use software video rendering method";
-      current_rendering_method_ = rendering_software_.get();
-    } else {
-      TIZEN_MEDIA_LOG(INFO) << "Use direct video rendering method";
-      current_rendering_method_ = rendering_direct_.get();
-    }
-
-    video_surface_.PreparePlane(render_data, current_rendering_method_);
-  }
-
   // Ensure that new values are set before returning due to the wrong
   // framebuffer. It allows for recovery in case some wrong value is
   // passed here for some reason.
@@ -605,6 +595,31 @@ void OutputSurfaceImpl::UpdateScalerState(bool muted, bool synced) {
   }
 }
 
+bool OutputSurfaceImpl::SelectRenderingMethod(
+    const gfx::OverlayRenderData& render_data) {
+  const bool supports_software_rendering =
+      IsSoftwareRenderingCapable(render_data);
+  const bool supports_direct_rendering = render_data.plane_id != 0;
+  const bool force_software_rendering =
+      supports_software_rendering && render_data.low_latency &&
+      rendering_workarounds_.prefer_manual_rendering_for_low_latency;
+
+  uses_software_rendering_ = false;
+  if (supports_direct_rendering && !force_software_rendering) {
+    TIZEN_MEDIA_LOG(INFO) << "Use direct video rendering method";
+    current_rendering_method_ = rendering_direct_.get();
+    return true;
+  } else if (supports_software_rendering) {
+    TIZEN_MEDIA_LOG(INFO) << "Use software video rendering method";
+    current_rendering_method_ = rendering_software_.get();
+    uses_software_rendering_ = true;
+    return true;
+  }
+
+  TIZEN_MEDIA_LOG(ERROR) << "Cannot choose rendering method";
+  return false;
+}
+
 std::ostream& operator<<(std::ostream& stream,
                          OutputSurfaceImpl::ScalerState state) {
   switch (state) {
index cee6ac4982e92e7926dde5d01c66adc7282fd64f..827b7393ec1d5902eb157543887e18dfbb71762e 100644 (file)
@@ -72,6 +72,8 @@ class OutputSurfaceImpl : public OutputSurface {
 
   void UpdateScalerState(bool muted, bool synced);
 
+  bool SelectRenderingMethod(const gfx::OverlayRenderData& render_data);
+
   ScalerState scaler_state_ = ScalerState::kUnknown;
 
   // Indicates last decoder which used this surface.
@@ -108,6 +110,8 @@ class OutputSurfaceImpl : public OutputSurface {
 
   Plane plane_;
 
+  bool uses_software_rendering_ = false;
+
   const RenderingWorkarounds rendering_workarounds_;
 };
 
index 7096430ed32bd612439e745969ecf2a99f957049..b7278faeabda5c7ba9b89d684e8eff4f21b5fede 100644 (file)
@@ -5,6 +5,8 @@
 #ifndef UI_OZONE_PLATFORM_EFL_OUTPUT_SURFACE_STATE_H_
 #define UI_OZONE_PLATFORM_EFL_OUTPUT_SURFACE_STATE_H_
 
+#include <optional>
+
 #include "base/functional/callback_forward.h"
 #include "base/timer/timer.h"
 #include "base/unguessable_token.h"
@@ -63,7 +65,7 @@ class OutputSurfaceState {
     picture_usage_ = PictureUsage::kRender;
     last_picture_id_ = collection_token;
   }
-  void reset_using() { last_picture_id_ = base::UnguessableToken::Null(); }
+  void reset_using() { last_picture_id_.reset(); }
 
   // Before calling this method, state should be verified.
   ui::OutputSurfaceProxy& surface() { return *surface_; }
@@ -82,7 +84,9 @@ class OutputSurfaceState {
 
   // Token identification of client. Note it should be used only when
   // |IsUsedByClient| returns true.
-  const base::UnguessableToken& ClientToken() const { return last_picture_id_; }
+  const base::UnguessableToken& ClientToken() const {
+    return last_picture_id_.value();
+  }
 
   // Returns true iff scaler is fully allocated and used by compositor
   // to render decoded video frames.
@@ -117,7 +121,7 @@ class OutputSurfaceState {
   base::DeadlineTimer removing_timer_;
 
   PictureUsage picture_usage_;
-  base::UnguessableToken last_picture_id_;
+  std::optional<base::UnguessableToken> last_picture_id_;
 };
 
 }  // namespace ui
index a83e1e0dc7e4ad589b5b0247772a5222eb4e5de1..573202aca0ff41df72c1f62c5d42bb1311b04f26 100644 (file)
@@ -20,8 +20,10 @@ namespace ui {
 TizenNativePixmap::TizenNativePixmap(
     ui::EflSurfaceFactory* surface_factory,
     gfx::NativePixmapHandle handle,
+    gfx::Size size,
     scoped_refptr<gfx::TizenPlaneCollectionManager> plane_collection_manager)
     : handle_(std::move(handle)),
+      size_(size),
       plane_collection_manager_(plane_collection_manager),
       surface_factory_(surface_factory) {}
 
@@ -65,8 +67,7 @@ uint64_t TizenNativePixmap::GetBufferFormatModifier() const {
 }
 
 gfx::Size TizenNativePixmap::GetBufferSize() const {
-  // TODO(j.gajownik2)
-  return gfx::Size();
+  return size_;
 }
 
 uint32_t TizenNativePixmap::GetUniqueId() const {
@@ -77,11 +78,56 @@ gfx::NativePixmapHandle TizenNativePixmap::ExportHandle() {
   return gfx::CloneHandleForIPC(handle_);
 }
 
+bool TizenNativePixmap::ScheduleSoftwareOverlayPlane(
+    gfx::AcceleratedWidget widget,
+    const gfx::OverlayPlaneData& overlay_plane_data) {
+  auto surface = surface_factory_->GetSurface(widget);
+  if (!surface) {
+    return true;
+  }
+
+  gfx::OverlayRenderData render_data;
+  render_data.plane_id = 0;
+  render_data.picture_size = size_;
+
+  auto y_buffer_holder =
+      gfx::TizenGpuBuffer::ImportFromFd(handle_.planes[0].fd);
+  if (!y_buffer_holder) {
+    LOG(ERROR) << "Cannot import y buffer";
+    return false;
+  }
+  auto y_buffer = y_buffer_holder->Release();
+
+  auto uv_buffer_holder =
+      gfx::TizenGpuBuffer::ImportFromFd(handle_.planes[1].fd);
+  if (!uv_buffer_holder) {
+    LOG(ERROR) << "Cannot import uv buffer";
+    return false;
+  }
+  auto uv_buffer = uv_buffer_holder->Release();
+
+  media::NV12Data nv12_data;
+  nv12_data.y_phys_data = tbm_bo_get_handle(y_buffer.get(), TBM_DEVICE_2D).u32;
+  nv12_data.y_stride = handle_.planes[0].stride;
+  nv12_data.y_phys_offset = handle_.planes[0].offset;
+  nv12_data.uv_phys_data =
+      tbm_bo_get_handle(uv_buffer.get(), TBM_DEVICE_2D).u32;
+  nv12_data.uv_stride = handle_.planes[1].stride;
+  nv12_data.uv_phys_offset = handle_.planes[1].offset;
+  render_data.nv12_data = &nv12_data;
+  surface->Render(overlay_plane_data, render_data);
+  return true;
+}
+
 bool TizenNativePixmap::ScheduleOverlayPlane(
     gfx::AcceleratedWidget widget,
     const gfx::OverlayPlaneData& overlay_plane_data,
     std::vector<gfx::GpuFence> /* acquire_fences */,
     std::vector<gfx::GpuFence> /* release_fences */) {
+  if (handle_.modifier == kFormatModifierLinear) {
+    return ScheduleSoftwareOverlayPlane(widget, overlay_plane_data);
+  }
+
   CHECK(handle_.picture_id);
   auto collection = plane_collection_manager_->Collection(*handle_.picture_id);
   if (!collection) {
index 0b510eb22dc7f6fa835d509a0a09bbcabec97ba0..d91ca99803d70a723e2766688d8af5718b09faff 100644 (file)
@@ -14,11 +14,14 @@ namespace ui {
 
 class EflSurfaceFactory;
 
+constexpr const uint64_t kFormatModifierLinear = 0;
+
 class TizenNativePixmap : public gfx::NativePixmap {
  public:
   explicit TizenNativePixmap(
       ui::EflSurfaceFactory* surface_factory,
       gfx::NativePixmapHandle handle,
+      gfx::Size size,
       scoped_refptr<gfx::TizenPlaneCollectionManager> plane_collection_manager);
 
   TizenNativePixmap(const TizenNativePixmap&) = delete;
@@ -49,10 +52,18 @@ class TizenNativePixmap : public gfx::NativePixmap {
   gfx::NativePixmapHandle& PeekHandle() { return handle_; }
   const gfx::NativePixmapHandle& PeekHandle() const { return handle_; }
 
-  bool SupportsOverlayPlane() const { return handle_.picture_id.has_value(); }
+  bool SupportsOverlayPlane() const {
+    return handle_.picture_id.has_value() ||
+           handle_.modifier == kFormatModifierLinear;
+  }
 
  private:
+  bool ScheduleSoftwareOverlayPlane(
+      gfx::AcceleratedWidget widget,
+      const gfx::OverlayPlaneData& overlay_plane_data);
+
   gfx::NativePixmapHandle handle_;
+  const gfx::Size size_;
   scoped_refptr<gfx::TizenPlaneCollectionManager> plane_collection_manager_;
   ui::EflSurfaceFactory* surface_factory_;
 };
index 70fd11d26c8ce66963370a0af45819cdbaabf866..f60c1040fa98bd5223f7edc04b9bb9092172ff4d 100644 (file)
@@ -59,9 +59,13 @@ gfx::TbmBOType VideoRenderingSoftware::PreparePlane(
     const gfx::OverlayRenderData& render_data,
     void* video_sink,
     void* bufmgr) {
-  constexpr const size_t kMaxDisplayBuffers = 8;
+  constexpr const size_t kMaxDisplayBuffers = 3;
+  constexpr const size_t kMaxDisplayBuffersForLowLatency = 5;
+  const size_t max_display_buffers = render_data.low_latency
+                                         ? kMaxDisplayBuffersForLowLatency
+                                         : kMaxDisplayBuffers;
 
-  for (size_t i = display_buffers_.size(); i < kMaxDisplayBuffers; ++i) {
+  for (size_t i = display_buffers_.size(); i < max_display_buffers; ++i) {
     constexpr size_t kPlaneY = 0;
     constexpr size_t kPlaneUV = 1;
     // Actual allocation size does not matter, any value might be provided.
@@ -152,11 +156,12 @@ void VideoRenderingSoftware::PrepareForRenderingFrame(
   display_buffers_[current_index_].y->CopyFrom(
       render_data.nv12_data->y_phys_data, render_data.nv12_data->y_stride,
       fb_bytes_per_line_, render_data.picture_size.width(),
-      render_data.picture_size.height());
+      render_data.picture_size.height(), render_data.nv12_data->y_phys_offset);
   display_buffers_[current_index_].uv->CopyFrom(
       render_data.nv12_data->uv_phys_data, render_data.nv12_data->uv_stride,
       fb_bytes_per_line_, render_data.picture_size.width(),
-      render_data.picture_size.height() / 2);
+      render_data.picture_size.height() / 2,
+      render_data.nv12_data->uv_phys_offset);
 
   dec_info_.width = render_data.picture_size.width();
   dec_info_.height = render_data.picture_size.height();