[TTVD] Introduce software video rendering method 41/314041/2
authorJakub Gajownik <j.gajownik2@samsung.com>
Fri, 21 Jun 2024 08:58:37 +0000 (10:58 +0200)
committerBot Blink <blinkbot@samsung.com>
Thu, 4 Jul 2024 09:48:20 +0000 (09:48 +0000)
For some boards (like NikeL), using direct video rendering
has poor performance, due to some post-processing being
applied on hardware scaler. This is not suitable for low
latency scenarios (e.g game streaming), where balance
between latency and playback quality is different than for
buffered video.
This patch introduces new video rendering method that copies
data directly onto display buffers and bypasses some video
quality enhancement mechanisms, so has lower latency.
It gives some better performance on NikeL board, so it's
prefered method when playing RTC streams for game streaming.
Legacy implementation on EsPlusPlayer uses same path
(MFC+JPEG), as mentioned above it gives better performance
on some specific boards (e.g NikeL).

Bug: https://jira-eu.sec.samsung.net/browse/VDGAME-514
Change-Id: I111e19d1592968d38be6ecf6db05de31225b9386
Signed-off-by: Jakub Gajownik <j.gajownik2@samsung.com>
31 files changed:
components/viz/service/display/overlay_processor_tizen.cc
gpu/config/gpu_driver_bug_list.json
gpu/config/gpu_workaround_list.txt
media/capture/video/tizen/video_capture_device_tizen_tv.cc
media/filters/tizen/decoder_facade_factory.cc
media/filters/tizen/decoder_facade_factory.h
media/filters/tizen/omx/omx_facade_video.cc
media/filters/tizen/omx/omx_facade_video.h
media/filters/tizen/omx/omx_facade_video_test.cc
media/filters/tizen/ttvd_video_decoder.cc
media/filters/tizen/ttvd_video_decoder.h
media/filters/tizen/ttvd_video_decoder_base.cc
media/filters/tizen/ttvd_video_decoder_base.h
media/filters/tizen/ttvd_video_decoder_impl.cc
media/filters/tizen/ttvd_video_decoder_impl.h
tizen_src/build/BUILD.gn
tizen_src/chromium_impl/ui/gfx/tizen_gpu_buffer.cc
tizen_src/chromium_impl/ui/gfx/tizen_gpu_buffer.h
tizen_src/chromium_impl/ui/gfx/tizen_overlay_plane.h
tizen_src/chromium_impl/ui/ozone/platform/efl/BUILD.gn
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/rendering_workarounds.cc
tizen_src/chromium_impl/ui/ozone/platform/efl/rendering_workarounds.h
tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering.h [new file with mode: 0644]
tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_direct.cc [new file with mode: 0644]
tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_direct.h [new file with mode: 0644]
tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_software.cc [new file with mode: 0644]
tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_software.h [new file with mode: 0644]
tizen_src/chromium_impl/ui/ozone/platform/efl/video_surface.cc
tizen_src/chromium_impl/ui/ozone/platform/efl/video_surface.h

index 9a5d6e9bfbc05aff2e2489a4d73ab79073fbdd5e..847e282e57225587f6437dfd31c1277305ddc1f3 100644 (file)
@@ -72,18 +72,6 @@ uint32_t MailboxToUInt32(const gpu::Mailbox& mailbox) {
   return (mailbox.name[0] << 24) + (mailbox.name[1] << 16) +
          (mailbox.name[2] << 8) + mailbox.name[3];
 }
-
-ui::RenderingWorkarounds ConvertToRenderingWorkarounds(
-    const gpu::GpuDriverBugWorkarounds& gpu_driver_workarounds) {
-  ui::RenderingWorkarounds result;
-  result.rotation_180_degrees_workaround =
-      gpu_driver_workarounds.rotation_180_degrees_workaround;
-  result.replace_rotate_180_with_hv_flip =
-      gpu_driver_workarounds.replace_rotate_180_with_hv_flip;
-  result.limit_rotation_to_single_plane =
-      gpu_driver_workarounds.limit_rotation_to_single_plane;
-  return result;
-}
 }  // namespace
 
 OverlayProcessorTizen::OverlayProcessorTizen(
@@ -93,9 +81,9 @@ OverlayProcessorTizen::OverlayProcessorTizen(
     : gpu_task_scheduler_(display_controller->gpu_task_scheduler()),
       shared_image_interface_(shared_image_interface),
       overlay_candidates_(std::move(overlay_candidates)),
-      rendering_workarounds_(
-          ConvertToRenderingWorkarounds(display_controller->skia_dependency()
-                                            ->GetGpuDriverBugWorkarounds())) {
+      rendering_workarounds_(ui::ConvertToRenderingWorkarounds(
+          display_controller->skia_dependency()
+              ->GetGpuDriverBugWorkarounds())) {
   weak_this_ = weak_factory_.GetWeakPtr();
 
   plane_collection_manager_ =
index 0a946007e26b6a5cea983353b2a6925745e70a4f..3e69922fafccba3f94e83b0df94d42c983ed0c74 100644 (file)
       "features": [
         "ttvd_disable_buffer_parallel_copy"
       ]
+    },
+    {
+      "id": 413,
+      "description": "Prefer manual rendering within TTVD when used for low latency playback",
+      "os": {
+        "type": "linux"
+      },
+      "machine_model_name": ["NIKEL"],
+      "features": [
+        "ttvd_prefer_manual_rendering_for_low_latency",
+        "ttvd_disable_faster_decoder_selection"
+      ]
     }
   ]
 }
index ffc73fa5be239ca6869e542fe40ea48f6e4754af..e314ab8c8986c038e484b525f7e29b6aaf1f698f 100644 (file)
@@ -127,6 +127,7 @@ ttvd_force_first_frame_rendering
 ttvd_force_frames_rendering
 ttvd_disable_buffer_parallel_copy
 ttvd_disable_faster_decoder_selection
+ttvd_prefer_manual_rendering_for_low_latency
 scalarize_vec_and_mat_constructor_args
 set_zero_level_before_generating_mipmap
 simulate_out_of_memory_on_large_textures
index 0881b10f61bffe32143e26672db129df8212129f..dcc04f349815674b9378100f284824d4200c76a7 100644 (file)
@@ -560,7 +560,8 @@ void VideoCaptureDeviceTizenTv::Impl::OnDecodedFrame(RawFrame frame) {
     case MediaVideoPixelFormat::kPixelFormatNV12:
       hw_buffers_[VideoFrame::kUVPlane]->CopyFrom(
           frame.nv12_data.uv_phys_data, frame.nv12_data.uv_stride,
-          frame.image_size.width(), frame.image_size.height() / 2);
+          frame.image_size.width(), frame.image_size.width(),
+          frame.image_size.height() / 2);
       break;
     case MediaVideoPixelFormat::kPixelFormatNV16:
       hw_buffers_[VideoFrame::kUVPlane]->Scale(
@@ -572,7 +573,8 @@ void VideoCaptureDeviceTizenTv::Impl::OnDecodedFrame(RawFrame frame) {
 
   hw_buffers_[VideoFrame::kYPlane]->CopyFrom(
       frame.nv12_data.y_phys_data, frame.nv12_data.y_stride,
-      frame.image_size.width(), frame.image_size.height());
+      frame.image_size.width(), frame.image_size.width(),
+      frame.image_size.height());
 
   std::array<base::ScopedClosureRunner, kNumNV12Planes> hw_buffers_unmappers;
 
index 000688ce52dc51907cc5c1d443b2390584fcd2e1..af4c30f325ff1c1c9699cf4cf4a3992bd342870c 100644 (file)
@@ -9,8 +9,10 @@
 
 namespace media {
 
-std::unique_ptr<DecoderFacadeVideo> CreateDecoderFacadeVideo() {
-  return std::make_unique<OmxFacadeVideo>(std::make_unique<OmxWrapper>());
+std::unique_ptr<DecoderFacadeVideo> CreateDecoderFacadeVideo(
+    const gpu::GpuDriverBugWorkarounds* workarounds) {
+  return std::make_unique<OmxFacadeVideo>(std::make_unique<OmxWrapper>(),
+                                          workarounds);
 }
 
 }  // namespace media
index 5c4e231fc83e1d261bc93f10d3fea6f882878413..0e7ff2d9ca94429e852d824d71af6759958f9aec 100644 (file)
@@ -5,11 +5,13 @@
 #ifndef MEDIA_FILTERS_TIZEN_DECODER_FACADE_FACTORY_H_
 #define MEDIA_FILTERS_TIZEN_DECODER_FACADE_FACTORY_H_
 
+#include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "media/filters/tizen/decoder_facade_video.h"
 
 namespace media {
 
-std::unique_ptr<DecoderFacadeVideo> CreateDecoderFacadeVideo();
+std::unique_ptr<DecoderFacadeVideo> CreateDecoderFacadeVideo(
+    const gpu::GpuDriverBugWorkarounds* workarounds = nullptr);
 
 }  // namespace media
 
index 2b32aa4b420a16fda78d2cd8a26b7655149e2ca7..6a7664905a16cae82bcee6116f0823732dfdfa0f 100644 (file)
@@ -89,8 +89,11 @@ OMX_VIDEO_N_DEC_INFO DecodingModeToOmxNDecoding(DecodingMode mode) {
 #endif  // TIZEN_VERSION_AT_LEAST(6, 5, 0)
 }  // namespace
 
-OmxFacadeVideo::OmxFacadeVideo(std::unique_ptr<OmxWrapper> wrapper)
-    : OmxFacade(std::move(wrapper)) {
+OmxFacadeVideo::OmxFacadeVideo(std::unique_ptr<OmxWrapper> wrapper,
+                               const gpu::GpuDriverBugWorkarounds* workarounds)
+    : OmxFacade(std::move(wrapper)),
+      workarounds_(workarounds ? *workarounds
+                               : gpu::GpuDriverBugWorkarounds()) {
   weak_this_ = weak_factory_.GetWeakPtr();
 }
 
@@ -222,6 +225,13 @@ bool OmxFacadeVideo::InitializeComponent(const std::string& component_name,
   param.bPresetMode = OMX_FALSE;
   param.nCodecExtraDataSize = 0;
   param.bErrorConcealment = OMX_FALSE;
+
+  const bool is_mfc = component_name.find("mfc") != std::string::npos;
+  if (is_mfc && low_delay_ &&
+      workarounds_.ttvd_prefer_manual_rendering_for_low_latency) {
+    param.bNoVideoOut = OMX_TRUE;
+  }
+
   switch (codec_) {
     case MediaVideoCodec::kCodecH264:
     case MediaVideoCodec::kCodecHEVC:
index 3520a3f9365c0982b69776b8d271a9eba34b2c94..b4110ba42ede63e962931679bef5c093d53b33fb 100644 (file)
@@ -6,6 +6,7 @@
 #define MEDIA_FILTERS_TIZEN_OMX_OMX_FACADE_VIDEO_H_
 
 #include "base/memory/weak_ptr.h"
+#include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "media/base/video_color_space.h"
 #include "media/filters/tizen/decoder_facade_video.h"
 #include "media/filters/tizen/omx/omx_facade.h"
@@ -14,7 +15,8 @@ namespace media {
 
 class OmxFacadeVideo : public DecoderFacadeVideo, public OmxFacade {
  public:
-  explicit OmxFacadeVideo(std::unique_ptr<OmxWrapper> wrapper);
+  explicit OmxFacadeVideo(std::unique_ptr<OmxWrapper> wrapper,
+                          const gpu::GpuDriverBugWorkarounds* workarounds);
   ~OmxFacadeVideo() override = default;
 
   // DecoderFacadeVideo impl.
@@ -59,6 +61,8 @@ class OmxFacadeVideo : public DecoderFacadeVideo, public OmxFacade {
   HdrMetadataCB hdr_metadata_cb_;
   ColorSpaceCB color_space_cb_;
 
+  const gpu::GpuDriverBugWorkarounds workarounds_;
+
   base::WeakPtr<OmxFacadeVideo> weak_this_;
   base::WeakPtrFactory<OmxFacadeVideo> weak_factory_{this};
 };
index f38a3d35612f3a07fa37d862ad911e0c4964f823..b455d94d4be231efb859c6b9676ec967ca9c77ca 100644 (file)
@@ -21,7 +21,7 @@ class OmxFacadeVideoTest : public testing::Test {
   OmxFacadeVideoTest() {
     auto wrapper = std::make_unique<testing::NiceMock<MockOmxWrapper>>();
     mock_omx_wrapper_ = wrapper.get();
-    facade_ = std::make_unique<OmxFacadeVideo>(std::move(wrapper));
+    facade_ = std::make_unique<OmxFacadeVideo>(std::move(wrapper), nullptr);
 
     memset(&decoded_spec_, 0, sizeof(decoded_spec_));
   }
index daf976f21b4230b94cf6316b6f81a131c605adca..d16c7da3d044140c16122effba88ab7dc269a52b 100644 (file)
@@ -21,8 +21,8 @@ namespace media {
 TTvdVideoDecoder::TTvdVideoDecoder(
     base::RepeatingCallback<gpu::CommandBufferStub*()> get_command_buffer_cb,
     scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
-    base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
-        get_video_facade_cb,
+    base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+        const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb,
     const gpu::GpuDriverBugWorkarounds& workarounds)
     : workarounds_(workarounds),
       decoder_thread_("ttvd_decoder_thread"),
index 06845a6e740ad5ffc1f67ce7810e31a0bde02fb0..178b5cee4d67fda78b2cca57ded4a8c417568264 100644 (file)
@@ -28,8 +28,8 @@ class MEDIA_EXPORT TTvdVideoDecoder
   TTvdVideoDecoder(
       base::RepeatingCallback<gpu::CommandBufferStub*()> get_command_buffer_cb,
       scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
-      base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
-          get_video_facade_cb,
+      base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+          const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb,
       const gpu::GpuDriverBugWorkarounds& workarounds);
   ~TTvdVideoDecoder() override;
 
@@ -72,7 +72,8 @@ class MEDIA_EXPORT TTvdVideoDecoder
   base::Thread decoder_thread_;
 
   base::SequenceBound<TTvdVideoDecoderImpl> decoder_impl_;
-  base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
+  base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+      const gpu::GpuDriverBugWorkarounds*)>
       get_video_facade_cb_;
 
   base::RepeatingCallback<gpu::CommandBufferStub*()> get_command_buffer_cb_;
index 7032f23226d04d4c226bafb9a21e0452b37b2d1d..92917a2216ae1a170ab2bb2916342f085428c5ce 100644 (file)
@@ -24,8 +24,8 @@
 namespace media {
 
 TTvdVideoDecoderBase::TTvdVideoDecoderBase(
-    base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
-        get_video_facade_cb)
+    base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+        const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb)
     : get_video_facade_cb_(std::move(get_video_facade_cb)),
       weak_self_(weak_factory_.GetWeakPtr()) {}
 TTvdVideoDecoderBase::~TTvdVideoDecoderBase() {
@@ -85,7 +85,7 @@ void TTvdVideoDecoderBase::Initialize(MediaVideoCodec codec,
   allocated_decoder_ = std::move(decoder);
   init_cb_ = std::move(init_cb);
 
-  decoder_facade_ = get_video_facade_cb_.Run();
+  decoder_facade_ = get_video_facade_cb_.Run(nullptr);
   decoder_facade_->Initialize(
       codec, coded_size, low_delay, false /* secure_mode */,
       allocated_decoder_->decoding_mode, allocated_decoder_->component_name,
index f97d1ada24e3f98036ccc95a0a45b1be6d6ca381..7412ec770f5b1b63619b703ae5e5ed933a238854 100644 (file)
@@ -28,8 +28,8 @@ using RawFrameCB = base::RepeatingCallback<void(RawFrame)>;
 class MEDIA_EXPORT TTvdVideoDecoderBase {
  public:
   explicit TTvdVideoDecoderBase(
-      base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
-          get_video_facade_cb);
+      base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+          const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb);
   ~TTvdVideoDecoderBase();
 
   void Initialize(MediaVideoCodec codec,
@@ -81,7 +81,8 @@ class MEDIA_EXPORT TTvdVideoDecoderBase {
   };
 
   std::list<Decoding> decoding_requests_;
-  base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
+  base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+      const gpu::GpuDriverBugWorkarounds*)>
       get_video_facade_cb_;
 
   base::WeakPtrFactory<TTvdVideoDecoderBase> weak_factory_{this};
index 63904ccd2b235153ddff779ddf5492fa4c1131d7..140000c7a62647374914ab66228a7d8e1a3c9058 100644 (file)
@@ -95,8 +95,8 @@ TTvdVideoDecoderImpl::TTvdVideoDecoderImpl(
     GetCommandbufferCB get_command_buffer_cb,
     scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> decoder_task_runner,
-    base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
-        get_video_facade_cb,
+    base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+        const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb,
     const gpu::GpuDriverBugWorkarounds& workarounds)
     : workarounds_(workarounds),
       last_processing_frame_(
@@ -245,6 +245,12 @@ void TTvdVideoDecoderImpl::RenderToOverlay(
     render_data.timestamp = ttvd_decoded_frame->Timestamp();
     render_data.low_latency = config_.is_rtc();
     render_data.collection_token = collection_token_;
+
+    // As we're about to render buffer that already sits in decoded queue
+    // (comparing to the rendering just decoded frame), we cannot be sure that
+    // data provided by facade is still valid (refers to this specific frame),
+    // so just skip rendering. It should not affect negatively on rendering,
+    // just potentially increase delay (1 frame) for normal latency playbback.
     render_cb_.Run(render_data);
   }
 
@@ -1225,7 +1231,7 @@ void TTvdVideoDecoderImpl::InitializeFacade() {
         << "Not supported video codec: " << config_.codec();
   }
 
-  decoder_facade_ = get_video_facade_cb_.Run();
+  decoder_facade_ = get_video_facade_cb_.Run(&workarounds_);
   const bool is_secure_mode = cdm_bridge_ != nullptr;
   decoder_facade_->Initialize(
       codec, config_.coded_size(), low_delay_, is_secure_mode,
@@ -1423,6 +1429,10 @@ void TTvdVideoDecoderImpl::UpdateLazyFrame(
     render_data.timestamp = output_data.timestamp;
     render_data.low_latency = config_.is_rtc();
     render_data.collection_token = collection_token_;
+
+    if (supports_software_rendering_) {
+      render_data.nv12_data = &output_data.nv12_data;
+    }
     render_cb_.Run(render_data);
     pending_render_ = false;
   }
@@ -1467,6 +1477,9 @@ void TTvdVideoDecoderImpl::OnBufferFilled(
     render_data.timestamp = output_data.timestamp;
     render_data.low_latency = config_.is_rtc();
     render_data.collection_token = collection_token_;
+    if (supports_software_rendering_) {
+      render_data.nv12_data = &output_data.nv12_data;
+    }
 
     if (surface_prepare_cb_) {
       TIZEN_MEDIA_LOG(INFO) << "Prepare surface with first frame";
@@ -1911,6 +1924,7 @@ void TTvdVideoDecoderImpl::UpdateDecoderCapabilities() {
        allocated_decoder_->decoding_mode != DecodingMode::kDecodingNormal) &&
       !cdm_bridge_;
 
+  supports_software_rendering_ = supports_texturing;
   supports_overlay_ =
       (allocated_decoder_->decoding_mode == DecodingMode::kDecodingNormal);
 
index 5c259e9143d9f561da4044ac09efd22ad6507114..d613c4cead4f109831f40b547b4cdffb7070fe4d 100644 (file)
@@ -90,8 +90,8 @@ class MEDIA_EXPORT TTvdVideoDecoderImpl {
       GetCommandbufferCB get_command_buffer_cb,
       scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> decoder_task_runner,
-      base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
-          get_video_facade_cb,
+      base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+          const gpu::GpuDriverBugWorkarounds*)> get_video_facade_cb,
       const gpu::GpuDriverBugWorkarounds& workarounds);
   ~TTvdVideoDecoderImpl();
 
@@ -293,6 +293,7 @@ class MEDIA_EXPORT TTvdVideoDecoderImpl {
   std::deque<scoped_refptr<TTvdDecodedFrame>> ttvd_decoded_frame_pool_;
 
   bool supports_texturing_ = false;
+  bool supports_software_rendering_ = false;
   bool supports_overlay_ = false;
 
   gfx::VideoOutputMode output_mode_ = gfx::VideoOutputMode::kUnknown;
@@ -444,7 +445,8 @@ class MEDIA_EXPORT TTvdVideoDecoderImpl {
   // decoder buffer. See |unique_id| in |DecodingRequest| structure.
   DecoderFacade::DecodingUniqueId next_decode_unique_id_ = 0;
 
-  base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>()>
+  base::RepeatingCallback<std::unique_ptr<DecoderFacadeVideo>(
+      const gpu::GpuDriverBugWorkarounds*)>
       get_video_facade_cb_;
 
   GetCommandbufferCB get_command_buffer_cb_;
index 11712848390ac44b13767191c41a368e3cad4114..b8c3a46c43ce8d0f239a8d93f507837927c5c7ba 100644 (file)
@@ -803,6 +803,13 @@ tizen_pkg_config("video-render-ctrl-c-glue") {
   }
 }
 
+tizen_pkg_config("video-mm-control") {
+  packages = []
+  if (tizen_tv_upstream_multimedia) {
+    packages = [ "video-mm-control" ]
+  }
+}
+
 config("notification") {
   if (is_tizen) {
     ldflags = [ "-lnotification" ]
index 5a373e6d2d3462221152feec7e1749b6eff59c57..9521f6502ca96eccab8d60f794feaa62e3545be8 100644 (file)
@@ -6,10 +6,12 @@
 
 #include <capi-graphics-control.h>
 #include <tbm_type_common.h>
+
 #include <cstring>
 
 #include "base/files/scoped_file.h"
 #include "tizen_src/chromium_impl/ui/gfx/tbm_utils.h"
+#include "ui/gfx/tizen_gpu_buffer.h"
 
 namespace gfx {
 
@@ -31,6 +33,30 @@ std::unique_ptr<TizenGpuBuffer> TizenGpuBuffer::Allocate(size_t size,
   return std::make_unique<TizenGpuBuffer>(std::move(bufmgr), std::move(bo));
 }
 
+std::unique_ptr<TizenGpuBuffer> TizenGpuBuffer::AllocateForDisplay(
+    size_t size,
+    size_t plane_type,
+    size_t plane,
+    size_t index) {
+  auto bufmgr = TbmBufMgrType(tbm_bufmgr_init(-1));
+  if (!bufmgr) {
+    return nullptr;
+  }
+
+  constexpr const int kDisplayMemoryType = 1 << 16;
+  const int plane_type_bits = (plane_type == 0 ? 2 : 3) << 20;
+
+  const int plane_index = plane << 3;
+  const int plane_bits = (plane_index | index) << 24;
+
+  const int mode = kDisplayMemoryType | plane_type_bits | plane_bits;
+  auto bo = TbmBOType(tbm_bo_alloc(bufmgr.get(), size, mode));
+  if (!bo) {
+    return nullptr;
+  }
+  return std::make_unique<TizenGpuBuffer>(std::move(bufmgr), std::move(bo));
+}
+
 std::unique_ptr<TizenGpuBuffer> TizenGpuBuffer::ImportFromFd(
     const base::ScopedFD& fd) {
   auto bufmgr = TbmBufMgrType(tbm_bufmgr_init(-1));
@@ -73,6 +99,7 @@ base::ScopedFD TizenGpuBuffer::ExportFd() {
 
 bool TizenGpuBuffer::CopyFrom(uint32_t phys_addr,
                               int stride,
+                              int dst_stride,
                               int width,
                               int height) {
   tbm_bo_handle handle = tbm_bo_get_handle(bo_.get(), TBM_DEVICE_2D);
@@ -89,7 +116,7 @@ bool TizenGpuBuffer::CopyFrom(uint32_t phys_addr,
 
   // dst info
   ga_info.dst_handle = handle.u32;
-  ga_info.dst_hbytesize = width;
+  ga_info.dst_hbytesize = dst_stride;
   ga_info.dst_rect.x = 0;
   ga_info.dst_rect.y = 0;
 
index 4c37900452be01346d5576fdf7a07fe874e675a5..a3ffe827b0e390f76614aaefd4ce2de9c8d7af00 100644 (file)
@@ -20,13 +20,21 @@ class TizenGpuBuffer {
 
   static std::unique_ptr<TizenGpuBuffer> Allocate(size_t size,
                                                   bool use_for_scanout);
+  static std::unique_ptr<TizenGpuBuffer> AllocateForDisplay(size_t size,
+                                                            size_t plane_type,
+                                                            size_t plane,
+                                                            size_t index);
   static std::unique_ptr<TizenGpuBuffer> ImportFromFd(const base::ScopedFD& fd);
 
   bool Map(AccessMode);
   bool Unmap();
 
   base::ScopedFD ExportFd();
-  bool CopyFrom(uint32_t phys_addr, int stride, int width, int height);
+  bool CopyFrom(uint32_t phys_addr,
+                int stride,
+                int dst_stride,
+                int width,
+                int height);
   bool Scale(uint32_t phys_addr,
              int stride,
              int width,
@@ -40,6 +48,8 @@ class TizenGpuBuffer {
 
   size_t UniqueId() const { return std::hash<TbmBOType>{}(bo_); }
 
+  TbmBOType Release() { return std::move(bo_); }
+
  private:
   // GCC compiler requires namespace specification for `Tbm*` wrappers,
   // otherwise compile error is being reported.
index 0b6fcef385a43e5f689e4010df7e2a2b2e656b14..375efd724e9ddf81fde8bf476a6a7c8704a0d521 100644 (file)
@@ -9,6 +9,7 @@
 #include "base/time/time.h"
 #include "base/unguessable_token.h"
 #include "gpu/command_buffer/common/mailbox.h"
+#include "media/filters/tizen/nv12_data.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/video_output_mode.h"
 
@@ -20,6 +21,10 @@ struct OverlayRenderData {
   base::TimeDelta timestamp;
   base::UnguessableToken collection_token;
 
+  // Available only with specific decoders, |nullptr| value means it
+  // does not support software rendering.
+  media::NV12Data* nv12_data = nullptr;
+
   bool low_latency = false;
 };
 
index 6cf403a3c893949e4b62950b19f3b8ca5d5f577d..34a21773bd4fe83d895b039c958d8997a9e94881 100644 (file)
@@ -40,6 +40,7 @@ source_set("efl") {
     configs += [
       "//tizen_src/build:tizen-extension-client",
       "//tizen_src/build:tizen-hwc-client",
+      "//tizen_src/build:video-mm-control",
       "//tizen_src/build:video-render-ctrl-c-glue",
     ]
     sources += [
@@ -65,6 +66,11 @@ source_set("efl") {
       "tizen_native_pixmap.h",
       "video_surface.cc",
       "video_surface.h",
+      "video_rendering.h",
+      "video_rendering_direct.cc",
+      "video_rendering_direct.h",
+      "video_rendering_software.cc",
+      "video_rendering_software.h",
       "wayland_object.cc",
       "wayland_object.h",
     ]
index 5ca9af4db090b858962dfbf29f6cc40858be0c08..e3b00d7d6f3dcb45ea3fab04d8d376c3257ee16c 100644 (file)
@@ -18,6 +18,8 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/efl/video_rendering_direct.h"
+#include "ui/ozone/platform/efl/video_rendering_software.h"
 
 // This may happen on older tizens (e.g. 6.0) due to using the same
 // include header guard `_DRM_MODE_H` by different headers.
@@ -158,13 +160,21 @@ Geometry CalculateGeometry(gfx::Size image_size,
       gfx::ScaleRect(crop_rect, image_size.width(), image_size.height())));
   return {screen_rect, picture_rect};
 }
+
+bool IsSoftwareRenderingCapable(const gfx::OverlayRenderData& render_data) {
+  return render_data.nv12_data != nullptr &&
+         render_data.nv12_data->y_phys_data != 0 &&
+         render_data.nv12_data->y_stride != 0 &&
+         render_data.nv12_data->uv_phys_data != 0 &&
+         render_data.nv12_data->uv_stride != 0;
+}
 }  // namespace
 
 OutputSurfaceImpl::OutputSurfaceImpl(
     int device_id,
     const RenderingWorkarounds& rendering_workarounds)
     : video_surface_(device_id, rendering_workarounds),
-      rendering_workarounds_(rendering_workarounds){};
+      rendering_workarounds_(rendering_workarounds) {}
 
 OutputSurfaceImpl::~OutputSurfaceImpl() {
   TIZEN_MEDIA_LOG(INFO) << "Destroy output surface impl";
@@ -335,7 +345,16 @@ void OutputSurfaceImpl::Render(const gfx::OverlayPlaneData& overlay_plane_data,
   }
 
   if (pending_source_change_ || !last_picture_plane_) {
-    video_surface_.UsePlane(render_data.plane_id);
+    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
@@ -372,12 +391,7 @@ void OutputSurfaceImpl::Render(const gfx::OverlayPlaneData& overlay_plane_data,
 
   TIZEN_MEDIA_LOG(VERBOSE) << "Display: " << geometry_.picture.ToString()
                            << " on: " << geometry_.screen.ToString();
-
-  if (!video_surface_.Render(render_data.plane_id)) {
-    TIZEN_MEDIA_LOG(ERROR) << "Error displaying picture";
-    return;
-  }
-  return;
+  video_surface_.RenderPlane(render_data, current_rendering_method_);
 }
 
 void OutputSurfaceImpl::SetBelow(OutputSurfaceImpl& above) {
@@ -434,11 +448,19 @@ void OutputSurfaceImpl::ChangeResolutionSettings() {
   res_data.color_ycbcr = 0;
   res_data.colorimetry = AVOC_COLORIMETRY_NODATA;
   res_data.rgb_range = ConvertColorRange(color_space_.GetRangeID());
-  res_data.netflix_max_v_size = 1920;
-  res_data.netflix_max_h_size = 1080;
+  res_data.netflix_max_h_size = 1920;
+  res_data.netflix_max_v_size = 1080;
   res_data.video_pack = 0;
   res_data.res_screen_mirroring = 0;
+#if TIZEN_VERSION_AT_LEAST(7, 0, 0)
+  if (use_game_mode) {
+    res_data.sub_source_mode = AVOC_SUB_SOURCE_UNIPLAYER_CLOUD_GAME;
+  } else {
+    res_data.sub_source_mode = AVOC_SUB_SOURCE_UNIPLAYER_OTT;
+  }
+#else
   res_data.sub_source_mode = AVOC_SUB_SOURCE_UNIPLAYER_OTT;
+#endif  // TIZEN_VERSION_AT_LEAST(7, 0, 0)
   res_data.graphic_mode = 0;
   res_data.freesync_max_vfreq = 0;
   res_data.hdmi_dsc = 0;
@@ -474,6 +496,9 @@ bool OutputSurfaceImpl::Initialize(Plane plane) {
     return false;
   }
 
+  rendering_software_ = std::make_unique<VideoRenderingSoftware>(plane_);
+  rendering_direct_ = std::make_unique<VideoRenderingDirect>(plane_);
+
   return true;
 }
 
index 1909c3f44996ad0d7b1699fc1a21f1acec3fb1b9..cee6ac4982e92e7926dde5d01c66adc7282fd64f 100644 (file)
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/hdr_metadata.h"
+#include "ui/gfx/tizen_gpu_buffer.h"
 #include "ui/gfx/tizen_overlay_plane.h"
 #include "ui/ozone/platform/efl/output_surface.h"
 #include "ui/ozone/platform/efl/rendering_workarounds.h"
+#include "ui/ozone/platform/efl/video_rendering.h"
 #include "ui/ozone/platform/efl/video_surface.h"
 
 namespace ui {
@@ -42,7 +44,6 @@ class OutputSurfaceImpl : public OutputSurface {
   void SetBelow(OutputSurfaceImpl& above);
 
  private:
-
   void EnableSeqMode(bool enabled);
   void SetHdrMetadata(gfx::HDRMetadata hdr_metadata);
 
@@ -99,6 +100,10 @@ class OutputSurfaceImpl : public OutputSurface {
   absl::optional<bool> low_latency_source_;
   bool has_decoded_frame_ = false;
 
+  std::unique_ptr<VideoRendering> rendering_software_;
+  std::unique_ptr<VideoRendering> rendering_direct_;
+  VideoRendering* current_rendering_method_ = nullptr;
+
   VideoSurface video_surface_;
 
   Plane plane_;
index 930a430f40c4ab29808c95295bba11318f834400..622ba47f60cc2398f1a9572e06f8e7a4a77b91fe 100644 (file)
@@ -15,6 +15,8 @@ RenderingWorkarounds ConvertToRenderingWorkarounds(
       gpu_driver_workarounds.replace_rotate_180_with_hv_flip;
   result.limit_rotation_to_single_plane =
       gpu_driver_workarounds.limit_rotation_to_single_plane;
+  result.prefer_manual_rendering_for_low_latency =
+      gpu_driver_workarounds.ttvd_prefer_manual_rendering_for_low_latency;
   return result;
 }
 
index 40af59b028f031952ae9f20d4375c9462882c265..d1d700e305dd8d847613544a982ea4781421e565 100644 (file)
@@ -13,6 +13,7 @@ struct RenderingWorkarounds {
   bool rotation_180_degrees_workaround = false;
   bool replace_rotate_180_with_hv_flip = false;
   bool limit_rotation_to_single_plane = false;
+  bool prefer_manual_rendering_for_low_latency = false;
 };
 
 RenderingWorkarounds ConvertToRenderingWorkarounds(
diff --git a/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering.h b/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering.h
new file mode 100644 (file)
index 0000000..360731d
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2024 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_H_
+#define UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_H_
+
+#include <avoc/avoc_defs.h>
+#include <tbm_bo.h>
+#include <tbm_type.h>
+#include <tbm_type_common.h>
+#include <video-sink-defs.h>
+#include <wayland-extension/tizen-hwc-client-protocol.h>
+
+#include "base/containers/flat_map.h"
+#include "base/functional/callback_helpers.h"
+#include "tizen_src/chromium_impl/build/tizen_version.h"
+#include "tizen_src/chromium_impl/ui/gfx/tbm_utils.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/hdr_metadata.h"
+#include "ui/ozone/platform/efl/output_surface.h"
+#include "ui/ozone/platform/efl/rendering_workarounds.h"
+#include "ui/ozone/platform/efl/wayland_object.h"
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+#include <video-common-defs.h>
+#else
+#include <ivideo-renderer.hpp>
+#include <ivideo-swdec.hpp>
+#endif
+
+namespace ui {
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+using FrameInfo = VideoSink_SetPlaneInfo;
+#else
+using FrameInfo = IVideoRenderer::SetPlaneInfo;
+#endif  // TIZEN_VERSION_AT_LEAST(8, 0, 0)
+
+class VideoRendering {
+ public:
+  VideoRendering(OutputSurface::Plane plane) : plane_(plane) {}
+  virtual ~VideoRendering() = default;
+
+  virtual VideoSink_SrcBufferTypes GetType() const = 0;
+  // Called by client every time we're preparing for rendering video
+  // decoded by new decoder.
+  virtual gfx::TbmBOType PreparePlane(const gfx::OverlayRenderData& render_data,
+                                      void* video_sink,
+                                      void* bufmgr) = 0;
+  // Implementation should fill |frame_info| with values specific for
+  // rendering method.
+  virtual void PrepareForRenderingFrame(
+      FrameInfo* frame_info,
+      const gfx::OverlayRenderData& render_data) = 0;
+
+ protected:
+  OutputSurface::Plane plane_;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_H_
diff --git a/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_direct.cc b/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_direct.cc
new file mode 100644 (file)
index 0000000..3b0f58b
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2024 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/efl/video_rendering_direct.h"
+
+namespace ui {
+
+gfx::TbmBOType VideoRenderingDirect::PreparePlane(
+    const gfx::OverlayRenderData& render_data,
+    void* video_sink,
+    void* bufmgr) {
+  return gfx::TbmBOType{tbm_bo_import_fd(reinterpret_cast<tbm_bufmgr>(bufmgr),
+                                         render_data.plane_id)};
+}
+
+void VideoRenderingDirect::PrepareForRenderingFrame(
+    FrameInfo* frame_info,
+    const gfx::OverlayRenderData& render_data) {
+  // We need to use |v4l2_drm| as there's no other structure that
+  // matches with the layout. Platform library interally casts
+  // to this structure so no other solution is possible.
+  v4l2_info_.plane = render_data.plane_id;
+  v4l2_info_.reserved = 0x1234ABCD;
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+  frame_info->v4l2_ptr = &v4l2_info_;
+#else
+  // |VideoBufMetaData| does not match |v4l2_drm|, that's why we need to do
+  // it this way.
+  frame_info->metadata =
+      reinterpret_cast<IVideoRenderer::VideoBufMetaData*>(&v4l2_info_);
+#endif
+
+  // Do not set seamless resolution for now.
+  frame_info->max_hres = -1;
+  frame_info->max_vres = -1;
+}
+
+}  // namespace ui
diff --git a/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_direct.h b/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_direct.h
new file mode 100644 (file)
index 0000000..b19e819
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2024 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_DIRECT_H_
+#define UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_DIRECT_H_
+
+#include <avoc/avoc_defs.h>
+#include <libdrm/drm_mode.h>
+#include <linux/videodev2_tztv.h>
+#include <tbm_bo.h>
+#include <tbm_type.h>
+#include <tbm_type_common.h>
+#include <tztv-kernel-headers/drm/drm_mode.h>
+#include <video-sink-defs.h>
+#include <wayland-extension/tizen-hwc-client-protocol.h>
+
+#include "tizen_src/chromium_impl/ui/gfx/tbm_utils.h"
+#include "ui/ozone/platform/efl/output_surface.h"
+#include "ui/ozone/platform/efl/video_rendering.h"
+
+namespace ui {
+
+class VideoRenderingDirect : public VideoRendering {
+ public:
+  explicit VideoRenderingDirect(OutputSurface::Plane plane)
+      : VideoRendering(plane) {}
+  ~VideoRenderingDirect() override = default;
+
+  VideoSink_SrcBufferTypes GetType() const override {
+    return VIDEOSINK_SRC_BUFFER_HW;
+  };
+  gfx::TbmBOType PreparePlane(const gfx::OverlayRenderData& render_data,
+                              void* video_sink,
+                              void* bufmgr) override;
+  void PrepareForRenderingFrame(
+      FrameInfo* frame_info,
+      const gfx::OverlayRenderData& render_data) override;
+
+ private:
+  v4l2_drm v4l2_info_{};
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_DIRECT_H_
diff --git a/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_software.cc b/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_software.cc
new file mode 100644 (file)
index 0000000..70fd11d
--- /dev/null
@@ -0,0 +1,185 @@
+// Copyright 2024 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/efl/video_rendering_software.h"
+
+#include <tbm_surface_internal.h>
+#include <video-render-ctrl-c-glue.h>
+#include <ivideo-dp-control.hpp>
+
+#include "media/base/tizen/logger/media_logger.h"
+#include "ui/gfx/tbm_utils.h"
+#include "ui/gfx/tizen_gpu_buffer.h"
+
+namespace ui {
+
+namespace {
+constexpr const size_t kDefaultFramerate = 60 * 100;
+constexpr const uint32_t kProgressiveScanType = 1;
+
+IVideoDpControl::ScalerIndex PlaneToScalerIndex(OutputSurface::Plane plane) {
+  switch (plane) {
+    case OutputSurface::Plane::kMain:
+      return IVideoDpControl::VIDEO_MAIN_SCALER;
+    case OutputSurface::Plane::kSub:
+      return IVideoDpControl::VIDEO_SUB_SCALER;
+    case OutputSurface::Plane::kSub2:
+      return IVideoDpControl::VIDEO_SUB2_SCALER;
+    case OutputSurface::Plane::kSub3:
+      return IVideoDpControl::VIDEO_BG_SCALER;
+  }
+  return IVideoDpControl::VIDEO_MAX_SCALER;
+}
+
+size_t PlaneToIndex(OutputSurface::Plane plane) {
+  switch (plane) {
+    case OutputSurface::Plane::kMain:
+      return 0;
+    case OutputSurface::Plane::kSub:
+      return 1;
+    case OutputSurface::Plane::kSub2:
+      return 2;
+    case OutputSurface::Plane::kSub3:
+      return 3;
+  }
+  // We should not reach here, keep it to suppress warnings.
+  return 0;
+}
+}  // namespace
+
+VideoRenderingSoftware::VideoRenderingSoftware(OutputSurface::Plane plane)
+    : VideoRendering(plane) {
+  IVideoDpControl::getInstance()->getFrameBufferProp(
+      IVideoDpControl::VIDEO_Y_FB_BYTEPERLINE, PlaneToScalerIndex(plane_),
+      IVideoDpControl::COLOR_FMT_YC420, &fb_bytes_per_line_);
+}
+
+gfx::TbmBOType VideoRenderingSoftware::PreparePlane(
+    const gfx::OverlayRenderData& render_data,
+    void* video_sink,
+    void* bufmgr) {
+  constexpr const size_t kMaxDisplayBuffers = 8;
+
+  for (size_t i = display_buffers_.size(); i < kMaxDisplayBuffers; ++i) {
+    constexpr size_t kPlaneY = 0;
+    constexpr size_t kPlaneUV = 1;
+    // Actual allocation size does not matter, any value might be provided.
+    auto y_buffer = gfx::TizenGpuBuffer::AllocateForDisplay(
+        fb_bytes_per_line_, kPlaneY, PlaneToIndex(plane_), i);
+    if (!y_buffer) {
+      break;
+    }
+
+    auto uv_buffer = gfx::TizenGpuBuffer::AllocateForDisplay(
+        fb_bytes_per_line_ / 2, kPlaneUV, PlaneToIndex(plane_), i);
+    if (!uv_buffer) {
+      break;
+    }
+
+    display_buffers_.emplace_back(
+        DisplayBuffers{.y = std::move(y_buffer), .uv = std::move(uv_buffer)});
+  }
+
+  TIZEN_MEDIA_LOG(INFO) << "Allocated buffers for software rendering: "
+                        << display_buffers_.size();
+
+  constexpr const size_t kMetaBufferSize = 4096;
+  auto tbm_bo = gfx::TizenGpuBuffer::Allocate(kMetaBufferSize, false);
+  if (!tbm_bo) {
+    TIZEN_MEDIA_LOG(ERROR) << "Cannot allocate meta buffer";
+    return nullptr;
+  }
+
+  if (!tbm_bo->Map(gfx::TizenGpuBuffer::AccessMode::kReadWrite)) {
+    TIZEN_MEDIA_LOG(ERROR) << "Cannot map meta buffer";
+    return nullptr;
+  }
+
+  constexpr const uint32_t kInvalidDisplayIndex = 0xffffffff;
+#if TIZEN_VERSION_AT_LEAST(7, 0, 0)
+  VideoSink_DecInfo dec_info{};
+  dec_info.width = render_data.picture_size.width();
+  dec_info.height = render_data.picture_size.height();
+  dec_info.framerate = kDefaultFramerate;
+  dec_info.colorformat = VIDEOSINK_DRM_COLORFORMAT_YUV420;
+  dec_info.scantype = kProgressiveScanType;
+  dec_info.display_index = kInvalidDisplayIndex;
+
+  if (videoRenderCtrl_getBufferMetaData(video_sink, &dec_info,
+                                        tbm_bo->Memory()) != 0) {
+    TIZEN_MEDIA_LOG(ERROR) << "Error when setting SW renderer metadata";
+    return nullptr;
+  }
+#else
+  IVideoSWDec::DecInfo dec_info{};
+  dec_info.width = render_data.picture_size.width();
+  dec_info.height = render_data.picture_size.height();
+  dec_info.framerate = kDefaultFramerate;
+  dec_info.colorformat = IVideoSWDec::COLORFORMAT_YUV420;
+  dec_info.scantype = kProgressiveScanType;
+  dec_info.display_index = kInvalidDisplayIndex;
+
+  if (IVideoSWDec::getInstance()->getBufferMetaData(
+          &dec_info, reinterpret_cast<IVideoRenderer::VideoBufMetaData*>(
+                         tbm_bo->Memory())) != 0) {
+    TIZEN_MEDIA_LOG(ERROR) << "Error when setting SW renderer metadata";
+    return nullptr;
+  }
+#endif  // TIZEN_VERSION_AT_LEAST(7, 0, 0)
+
+  if (!tbm_bo->Unmap()) {
+    TIZEN_MEDIA_LOG(ERROR) << "Cannot unmap meta buffer";
+    return nullptr;
+  }
+
+  return tbm_bo->Release();
+}
+
+void VideoRenderingSoftware::PrepareForRenderingFrame(
+    FrameInfo* frame_info,
+    const gfx::OverlayRenderData& render_data) {
+  if (!render_data.nv12_data) {
+    TIZEN_MEDIA_LOG(WARNING) << "No rendering data source";
+    return;
+  }
+
+  current_index_ += 1;
+  if (current_index_ >= display_buffers_.size()) {
+    current_index_ = 0;
+  }
+
+  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());
+  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);
+
+  dec_info_.width = render_data.picture_size.width();
+  dec_info_.height = render_data.picture_size.height();
+  dec_info_.framerate = kDefaultFramerate;
+  dec_info_.scantype = kProgressiveScanType;
+  dec_info_.display_index = current_index_;
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+  dec_info_.colorformat = VIDEORCTRL_COLORFORMAT_YUV420;
+  dec_info_.stereoscopic_info = VIDEOCTRL_STEREOSCOPIC_2D;
+
+  frame_info->v4l2_ptr = &dec_info_;
+#else
+  dec_info_.colorformat = IVideoSWDec::COLORFORMAT_YUV420;
+  dec_info_.stereoscopic_info = IVideoSWDec::STEREOSCOPIC_2D;
+
+  // See above why it's needed. |VideoBufMetaData| does not match |v4l2_drm|.
+  frame_info->metadata =
+      reinterpret_cast<IVideoRenderer::VideoBufMetaData*>(&dec_info_);
+#endif
+
+  frame_info->sw_hres = render_data.picture_size.width();
+  frame_info->sw_vres = render_data.picture_size.height();
+}
+
+}  // namespace ui
diff --git a/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_software.h b/tizen_src/chromium_impl/ui/ozone/platform/efl/video_rendering_software.h
new file mode 100644 (file)
index 0000000..4ce9c41
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2024 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_SOFTWARE_H_
+#define UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_SOFTWARE_H_
+
+#include <avoc/avoc_defs.h>
+#include <tbm_bo.h>
+#include <tbm_surface.h>
+#include <tbm_type.h>
+#include <tbm_type_common.h>
+#include <video-sink-defs.h>
+#include <wayland-extension/tizen-hwc-client-protocol.h>
+
+#include "ui/gfx/tizen_gpu_buffer.h"
+#include "ui/ozone/platform/efl/output_surface.h"
+#include "ui/ozone/platform/efl/video_rendering.h"
+
+namespace ui {
+
+class VideoRenderingSoftware : public VideoRendering {
+ public:
+  explicit VideoRenderingSoftware(OutputSurface::Plane plane);
+  ~VideoRenderingSoftware() override = default;
+
+  VideoSink_SrcBufferTypes GetType() const override {
+    return VIDEOSINK_SRC_BUFFER_SW;
+  };
+  gfx::TbmBOType PreparePlane(const gfx::OverlayRenderData& render_data,
+                              void* video_sink,
+                              void* bufmgr) override;
+  void PrepareForRenderingFrame(
+      FrameInfo* frame_info,
+      const gfx::OverlayRenderData& render_data) override;
+
+ private:
+  int fb_bytes_per_line_ = 0;
+
+  size_t current_index_ = 0;
+  struct DisplayBuffers {
+    std::unique_ptr<gfx::TizenGpuBuffer> y;
+    std::unique_ptr<gfx::TizenGpuBuffer> uv;
+  };
+  std::vector<DisplayBuffers> display_buffers_;
+
+#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
+  VideoCtrlDecInfo_s dec_info_;
+#else
+  IVideoSWDec::DecInfo dec_info_;
+#endif  // TIZEN_VERSION_AT_LEAST(8, 0, 0)
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_EFL_VIDEO_RENDERING_SOFTWARE_H_
index e788e2fa967d71f338fc675df01c143b4f1fa69a..c14af2d75e85f4197f7ebfd4399ef8c92b42cb1b 100644 (file)
 #include "tizen_src/chromium_impl/ui/gfx/tbm_utils.h"
 #include "ui/ozone/platform/efl/efl_window.h"
 
-#if !TIZEN_VERSION_AT_LEAST(8, 0, 0)
-#include <ivideo-renderer.hpp>
-#endif
-
 namespace {
 
 // TODO(vdwasm) Currently graphics resolution is capped to 1920x1080.
@@ -256,14 +252,6 @@ bool VideoSurface::Initialize(ui::OutputSurface::Plane plane) {
     return false;
   }
 
-  res = videoRenderCtrl_setSrcBufferType(video_sink_.get(),
-                                         VIDEOSINK_SRC_BUFFER_HW);
-  if (res != 0) {
-    TIZEN_MEDIA_LOG(ERROR) << "Cannot set video sink buffer type, error: "
-                           << res;
-    return false;
-  }
-
   return true;
 }
 
@@ -405,8 +393,9 @@ void VideoSurface::CommitFeedbackFinish(uint32_t serial) {
   pending_commit_feedbacks_.erase(it);
 }
 
-void VideoSurface::UsePlane(int plane_id) {
-  TIZEN_MEDIA_LOG(VERBOSE) << "Use plane: " << plane_id;
+void VideoSurface::PreparePlane(const gfx::OverlayRenderData& render_data,
+                                VideoRendering* renderer) {
+  TIZEN_MEDIA_LOG(VERBOSE) << "Use plane: " << render_data.plane_id;
 
   auto temp_surface = std::move(tbm_surface_);
   auto temp_bo = std::move(tbm_bo_);
@@ -419,28 +408,44 @@ void VideoSurface::UsePlane(int plane_id) {
     return;
   }
 
-  tbm_bo_ = gfx::TbmBOType{
-      tbm_bo_import_fd(reinterpret_cast<tbm_bufmgr>(bufmgr), plane_id)};
-  if (!tbm_bo_) {
+  // Set new buffer type that could change from the last one used.
+  int res =
+      videoRenderCtrl_setSrcBufferType(video_sink_.get(), renderer->GetType());
+  if (res != 0) {
+    TIZEN_MEDIA_LOG(ERROR) << "Cannot set video sink buffer type, error: "
+                           << res;
+  }
+
+  auto tbm_bo = renderer->PreparePlane(render_data, video_sink_.get(), bufmgr);
+  if (!tbm_bo) {
     TIZEN_MEDIA_LOG(ERROR) << "Cannot import video tbm_bo";
     return;
   }
+
+  // Dummy frame buffer size. It's not really used for rendering, just to
+  // notify renderer with metadata from the buffer object underneath what
+  // should be rendered.
+  constexpr const size_t kFrameBufferSize = 4096;
   tbm_surface_info_s ts_info;
-  ts_info.width = 4096;
-  ts_info.height = 4096;
+  ts_info.width = kFrameBufferSize;
+  ts_info.height = kFrameBufferSize;
   ts_info.format = TBM_FORMAT_XRGB8888;
-  ts_info.bpp = 4096;
+  ts_info.bpp = tbm_surface_internal_get_bpp(ts_info.format);
   ts_info.num_planes = 1;
-  ts_info.planes[0].stride = 4096 * 4;
+  ts_info.planes[0].stride = kFrameBufferSize * 4;
   ts_info.planes[0].offset = 0;
 
-  auto tbm_bo_raw = tbm_bo_.get();
-  tbm_surface_ = gfx::TbmSurfaceType{
+  auto tbm_bo_raw = tbm_bo.get();
+  auto tbm_surface = gfx::TbmSurfaceType{
       tbm_surface_internal_create_with_bos(&ts_info, &tbm_bo_raw, 1)};
-  if (!tbm_surface_) {
+  if (!tbm_surface) {
     TIZEN_MEDIA_LOG(ERROR) << "Cannot create tbm surface for video";
     return;
   }
+
+  tbm_bo_ = std::move(tbm_bo);
+  tbm_surface_ = std::move(tbm_surface);
+
   buffer_.reset(
       wayland_tbm_client_create_buffer(tbm_client, tbm_surface_.get()));
   if (!buffer_) {
@@ -460,14 +465,14 @@ void VideoSurface::UsePlane(int plane_id) {
 
   // In case of same |plane_id| used, we need to ensure that framebuffer is
   // recreated correctly. To do that, use nullptr as data for |renderFrame|.
-  if (last_plane_id_ == plane_id) {
+  if (last_plane_id_ == render_data.plane_id) {
     TIZEN_MEDIA_LOG(INFO) << "Reset video surface for same plane";
     if (videoRenderCtrl_renderFrame(video_sink_.get(), nullptr) != 0) {
       TIZEN_MEDIA_LOG(ERROR)
           << "Error when reseting video surface for same plane";
     }
   }
-  last_plane_id_ = plane_id;
+  last_plane_id_ = render_data.plane_id;
 }
 
 void VideoSurface::Hide() {
@@ -485,7 +490,8 @@ void VideoSurface::Hide() {
   WaitForCallbacksToFinish();
 }
 
-bool VideoSurface::Render(uint32_t plane_id) {
+bool VideoSurface::RenderPlane(const gfx::OverlayRenderData& render_data,
+                               VideoRendering* renderer) {
   // If geometry of plane to be used has changed, we need to go through
   // platform compositor path, so changes for subsurface are applied.
   if (full_commit_pending_) {
@@ -502,26 +508,8 @@ bool VideoSurface::Render(uint32_t plane_id) {
     WaitForCallbacksToFinish();
   }
 
-  // We need to use |v4l2_drm| as there's no other structure that
-  // matches with the layout. Platform library interally casts
-  // to this structure so no other solution is possible.
-  v4l2_drm v4l2_info{};
-  v4l2_info.plane = plane_id;
-  v4l2_info.reserved = 0x1234ABCD;
-
-#if TIZEN_VERSION_AT_LEAST(8, 0, 0)
-  VideoSink_SetPlaneInfo frame_info{};
-  frame_info.v4l2_ptr = &v4l2_info;
-#else
-  IVideoRenderer::SetPlaneInfo frame_info{};
-  // See above why it's needed. |VideoBufMetaData| does not match |v4l2_drm|.
-  frame_info.metadata =
-      reinterpret_cast<IVideoRenderer::VideoBufMetaData*>(&v4l2_info);
-#endif
-
-  // Do not set seamless resolution for now.
-  frame_info.max_hres = -1;
-  frame_info.max_vres = -1;
+  FrameInfo frame_info{};
+  renderer->PrepareForRenderingFrame(&frame_info, render_data);
   return videoRenderCtrl_renderFrame(video_sink_.get(), &frame_info) == 0;
 }
 
index 65d2b8bdc746b26bbee59a08475a0418bf13c617..b8f98304af3d844218cdc571c28856a43d3c05fb 100644 (file)
@@ -19,6 +19,7 @@
 #include "ui/gfx/hdr_metadata.h"
 #include "ui/ozone/platform/efl/output_surface.h"
 #include "ui/ozone/platform/efl/rendering_workarounds.h"
+#include "ui/ozone/platform/efl/video_rendering.h"
 #include "ui/ozone/platform/efl/wayland_object.h"
 
 class IVideoSink;
@@ -40,9 +41,11 @@ class VideoSurface {
                    absl::optional<gfx::Rect> destination,
                    absl::optional<gfx::OverlayTransform> transform);
 
-  void UsePlane(int plane_id);
+  void PreparePlane(const gfx::OverlayRenderData& render_data,
+                    VideoRendering* renderer);
   void Hide();
-  bool Render(uint32_t plane_id);
+  bool RenderPlane(const gfx::OverlayRenderData& render_data,
+                   VideoRendering* renderer);
 
   bool SetResolution(const avoc_tpt_resolution_s& data);
   bool SetPreResolution(const avoc_tpt_resolution_s& data);