[TTVD] Optimize hardware encoding performance 19/314819/1
authorJakub Gajownik <j.gajownik2@samsung.com>
Mon, 15 Jul 2024 16:58:54 +0000 (18:58 +0200)
committerj.gajownik2 <j.gajownik2@samsung.com>
Fri, 19 Jul 2024 15:16:01 +0000 (17:16 +0200)
After latest changes, gpu memory buffer that is returned
from video capture pipeline is backed by single buffer.
Moreover, graphics accelerator (GA) might access it. On the
other end we have hardware encoder that is way faster if
it receives TBM surface also backed by memory accessible
by GA.

This CL improves hardware encoder performance when used
with video capture. Intermediate TBM surface is created
and GA is used to copy data into it.
Additionally, this improves performance when video is
cropped, since platform encoder library doesn't support it.
However, when intermediate buffer is used, we can perform
cropping on our own and request encoding with zero offset.

Bug: https://jira-eu.sec.samsung.net/browse/VDGAME-532
Change-Id: Ia17d9801def09a03f10cc497b06756f59a184a6f
Signed-off-by: Jakub Gajownik <j.gajownik2@samsung.com>
media/gpu/tizen/tizen_video_encode_accelerator.cc
media/gpu/tizen/tizen_video_encode_accelerator.h
media/gpu/tizen/tizen_video_encode_accelerator_utils.cc
media/gpu/tizen/tizen_video_encode_accelerator_utils.h
tizen_src/chromium_impl/ui/gfx/tizen_gpu_buffer.cc
tizen_src/chromium_impl/ui/gfx/tizen_gpu_buffer.h

index 95ecb9649bd8365f8e7d40177604f5dace767be4..19cdfbcecca7632636aafcff33102e936b6e90c1 100644 (file)
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
 #include "media/base/bitstream_buffer.h"
 #include "media/base/tizen/logger/media_logger.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
 #include "media/gpu/tizen/tizen_video_encode_accelerator_helper.h"
 #include "media/gpu/tizen/tizen_video_encode_accelerator_utils.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
 
 namespace media {
 
 namespace {
 
+#define CHECK_AND_RETURN_MEDIA_PACKET(function, return_type)  \
+  do {                                                        \
+    auto error = static_cast<media_packet_error_e>(function); \
+    if (error != MEDIA_PACKET_ERROR_NONE) {                   \
+      TIZEN_MEDIA_LOG_NO_INSTANCE(ERROR)                      \
+          << #function << "() failed: `" << error << "`";     \
+      return return_type;                                     \
+    }                                                         \
+  } while (0)
+
 using EncoderState = TizenVideoEncodeAccelerator::EncoderState;
 
 #define DECLARE_CASE_VALUE(param) \
@@ -96,8 +108,152 @@ using MediaPacketTuple = std::tuple<MediaPacketType, base::ScopedClosureRunner>;
 
 constexpr const uint32_t kNumberOfBuffersPerLayer = 3;
 
+bool IsBufferCapableOfHoldingFormat(const HardwareBuffers& buffers,
+                                    VideoPixelFormat format,
+                                    gfx::Size frame_size) {
+  if (buffers.size() != VideoFrame::NumPlanes(format)) {
+    return false;
+  }
+
+  for (size_t plane = 0; plane < buffers.size(); ++plane) {
+    if (buffers[plane]->Size() <
+        static_cast<size_t>(
+            VideoFrame::PlaneSize(format, plane, frame_size).GetArea())) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace
 
+void TizenVideoEncodeAccelerator::ReturnBufferToPool(
+    HardwareBuffers buffers,
+    std::unique_ptr<gfx::TbmSurface>) {
+  temp_buffers_.push_back(std::move(buffers));
+}
+
+HardwareBuffers TizenVideoEncodeAccelerator::AllocateOrGetBufferFromPool(
+    VideoPixelFormat format,
+    gfx::Size frame_size) {
+  constexpr const size_t kMaxNumBuffers = 2;
+  if (temp_buffers_.empty() && allocated_buffers_ >= kMaxNumBuffers) {
+    return {};
+  }
+
+  if (!temp_buffers_.empty()) {
+    if (IsBufferCapableOfHoldingFormat(temp_buffers_.front(), format,
+                                       frame_size)) {
+      auto result = std::move(temp_buffers_.front());
+      temp_buffers_.pop_front();
+      return result;
+    } else {
+      temp_buffers_.pop_front();
+      allocated_buffers_ -= 1;
+    }
+  }
+
+  HardwareBuffers result;
+  for (size_t plane = 0; plane < VideoFrame::NumPlanes(format); plane++) {
+    result.push_back(gfx::TizenGpuBuffer::Allocate(
+        VideoFrame::PlaneSize(format, plane, frame_size).GetArea(), true));
+    if (!result.back()) {
+      return {};
+    }
+  }
+  allocated_buffers_ += 1;
+  return result;
+}
+
+MediaPacketTuple TizenVideoEncodeAccelerator::CreateMediaPacketFromTBMSurface(
+    const scoped_refptr<VideoFrame>& video_frame,
+    const MediaFormatType& media_format) {
+  if (!video_frame->HasGpuMemoryBuffer())
+    return {};
+
+  const auto original_native_pixmap_handle =
+      video_frame->GetGpuMemoryBuffer()->CloneHandle().native_pixmap_handle;
+  constexpr uint64_t kFormatModifierLinear = 0;
+  // It supports only linear buffers, since it copies them and pass in special
+  // mode under TBM surface.
+  if (original_native_pixmap_handle.modifier != kFormatModifierLinear) {
+    return {};
+  }
+
+  auto buffers =
+      AllocateOrGetBufferFromPool(video_frame->format(), input_visible_size_);
+  if (buffers.empty()) {
+    TIZEN_MEDIA_LOG(ERROR) << "Failed to allocate temporary buffer";
+    return {};
+  }
+
+  gfx::NativePixmapHandle native_pixmap_handle;
+  for (size_t plane = 0; plane < VideoFrame::NumPlanes(video_frame->format());
+       plane++) {
+    const auto sample_size =
+        VideoFrame::SampleSize(video_frame->format(), plane);
+    const auto src_size_in_samples = VideoFrame::PlaneSizeInSamples(
+        video_frame->format(), plane, video_frame->visible_rect().size());
+    const auto bytes_per_element =
+        VideoFrame::BytesPerElement(video_frame->format(), plane);
+    const auto src_offset =
+        original_native_pixmap_handle.planes[plane].stride *
+            (video_frame->visible_rect().y() / sample_size.height()) +
+        (video_frame->visible_rect().x() / sample_size.height()) *
+            bytes_per_element;
+
+    const auto dst_plane_size_in_samples = VideoFrame::PlaneSizeInSamples(
+        video_frame->format(), plane, input_visible_size_);
+    const auto dst_stride = VideoFrame::RowBytes(plane, video_frame->format(),
+                                                 input_visible_size_.width());
+
+    TRACE_EVENT0("gpu", "VideoEncoder.CopyPlane");
+    auto src_buffer = gfx::TizenGpuBuffer::ImportFromFd(
+        original_native_pixmap_handle.planes[plane].fd);
+    if (input_visible_size_ == video_frame->visible_rect().size()) {
+      buffers[plane]->CopyFrom(
+          *src_buffer, original_native_pixmap_handle.planes[plane].stride,
+          original_native_pixmap_handle.planes[plane].offset + src_offset,
+          dst_stride, 0, src_size_in_samples.width(),
+          src_size_in_samples.height(), bytes_per_element);
+    } else {
+      buffers[plane]->Scale(
+          *src_buffer, original_native_pixmap_handle.planes[plane].stride,
+          original_native_pixmap_handle.planes[plane].offset + src_offset,
+          dst_stride, 0, src_size_in_samples.width(),
+          src_size_in_samples.height(), dst_plane_size_in_samples.width(),
+          dst_plane_size_in_samples.height(), bytes_per_element);
+    }
+
+    native_pixmap_handle.planes.emplace_back(
+        dst_stride, 0,
+        VideoFrame::PlaneSize(video_frame->format(), plane, input_visible_size_)
+            .GetArea(),
+        buffers[plane]->ExportFd());
+  }
+
+  auto tbm_surface = gfx::TbmSurface::ImportTbmSurface(
+      native_pixmap_handle, video_frame->coded_size());
+
+  if (!tbm_surface)
+    return {};
+
+  media_packet_h media_packet_ptr{nullptr};
+
+  CHECK_AND_RETURN_MEDIA_PACKET(
+      media_packet_new_from_tbm_surface(
+          media_format.get(), **tbm_surface,
+          TizenVideoEncodeAcceleratorHelper::OnPacketProcessedByEncoderCallback,
+          this, &media_packet_ptr),
+      {});
+
+  return std::make_tuple(
+      MediaPacketType{media_packet_ptr},
+      base::ScopedClosureRunner{base::BindOnce(
+          &TizenVideoEncodeAccelerator::ReturnBufferToPool, weak_ptr_,
+          std::move(buffers), std::move(tbm_surface))});
+}
+
 VideoEncodeAccelerator::SupportedProfiles
 TizenVideoEncodeAccelerator::GetSupportedProfiles() {
   TIZEN_MEDIA_LOG(INFO);
@@ -186,6 +342,7 @@ bool TizenVideoEncodeAccelerator::Initialize(
 
   const size_t output_buffer_capacity = VideoFrame::AllocationSize(
       config.input_format, config.input_visible_size);
+  input_visible_size_ = config.input_visible_size;
 
   StartInternal();
 
@@ -719,22 +876,23 @@ void TizenVideoEncodeAccelerator::PushFrameToPlatformEncoder(
     CHECK_AND_RETURN_MEDIA_FORMAT(
         media_format_set_video_mime(media_format.get(), MEDIA_FORMAT_NV12));
     CHECK_AND_RETURN_MEDIA_FORMAT(media_format_set_video_width(
-        media_format.get(), frame->visible_rect().width()));
+        media_format.get(), input_visible_size_.width()));
     CHECK_AND_RETURN_MEDIA_FORMAT(media_format_set_video_height(
-        media_format.get(), frame->visible_rect().height()));
+        media_format.get(), input_visible_size_.height()));
     CHECK_AND_RETURN_MEDIA_FORMAT(media_format_set_video_frame_rate(
         media_format.get(), kDefaultFramerate));
   }
 
   static const std::array media_packet_creation_functions{
-      base::BindRepeating(CreateMediaPacketFromTBMSurface),
+      base::BindRepeating(
+          &TizenVideoEncodeAccelerator::CreateMediaPacketFromTBMSurface),
       base::BindRepeating(CreateMediaPacketFromGpuMemoryBuffer),
       base::BindRepeating(CreateMediaPacketFromRawData)};
 
   for (const auto& media_packet_create_function :
        media_packet_creation_functions) {
     auto [media_packet, destruction_cb] =
-        media_packet_create_function.Run(frame, media_format, this);
+        media_packet_create_function.Run(this, frame, media_format);
 
     if (!media_packet)
       continue;
index b5c984cef397f86c8c2ff4926bb230021d0ae38e..f7ac0c75967aceba2fda27afcd38c825745ae6a6 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef MEDIA_GPU_TIZEN_TIZEN_VIDEO_ENCODE_ACCELERATOR_H_
 #define MEDIA_GPU_TIZEN_TIZEN_VIDEO_ENCODE_ACCELERATOR_H_
 
+#include <list>
 #include <tuple>
 #include <unordered_map>
 #include <vector>
 #include "media/video/video_encode_accelerator.h"
 #include "ui/gfx/client_native_pixmap_factory.h"
 #include "ui/gfx/range/range.h"
+#include "ui/gfx/tbm_surface.h"
+#include "ui/gfx/tizen_gpu_buffer.h"
 
 namespace media {
 
+using HardwareBuffers = std::vector<std::unique_ptr<gfx::TizenGpuBuffer>>;
+
 class TizenVideoEncodeAccelerator : public VideoEncodeAccelerator {
  public:
   TizenVideoEncodeAccelerator();
@@ -95,9 +100,19 @@ class TizenVideoEncodeAccelerator : public VideoEncodeAccelerator {
                                   bool* is_idr_frame,
                                   int* qp);
 
+  void ReturnBufferToPool(HardwareBuffers buffers,
+                          std::unique_ptr<gfx::TbmSurface>);
+  HardwareBuffers AllocateOrGetBufferFromPool(VideoPixelFormat format,
+                                              gfx::Size frame_size);
+  MediaPacketTuple CreateMediaPacketFromTBMSurface(
+      const scoped_refptr<VideoFrame>& video_frame,
+      const MediaFormatType& media_format);
+
   EncoderState encoder_state_{EncoderState::kUninitialized};
   Client* client_{nullptr};
 
+  gfx::Size input_visible_size_;
+
   // Task runner used for executing all methods of this class.
   // Used so the callbacks from encoder can be dispatched to proper thread.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
@@ -124,6 +139,9 @@ class TizenVideoEncodeAccelerator : public VideoEncodeAccelerator {
       frames_to_encode_;
   std::vector<scoped_refptr<VideoFrame>> frames_with_data_in_encoder_;
 
+  std::list<HardwareBuffers> temp_buffers_;
+  size_t allocated_buffers_ = 0;
+
   base::queue<BitstreamBuffer> buffers_;
   absl::optional<Bitrate> last_set_bitrate_;
 
index 243da195cf090ca516b3a239c643cc84dc649f45..9ed91d630b3e61953c7a43f00d7d56120bfb9586 100644 (file)
@@ -198,62 +198,21 @@ void MediaPacketDeleter::operator()(media_packet_h packet) {
   media_packet_unref(packet);
 }
 
-MediaPacketTuple CreateMediaPacketFromTBMSurface(
+MediaPacketTuple CreateMediaPacketFromGpuMemoryBuffer(
+    TizenVideoEncodeAccelerator* thiz,
     const scoped_refptr<VideoFrame>& video_frame,
-    const MediaFormatType& media_format,
-    TizenVideoEncodeAccelerator* thiz) {
+    const MediaFormatType& media_format) {
   if (!video_frame->HasGpuMemoryBuffer())
     return {};
 
-  auto gpu_memory_buffer = video_frame->GetGpuMemoryBuffer()->CloneHandle();
-
-  // Hardware encoder platform library does not apply offset given in TBM
-  // surface. We cannot encode region indicated by visible rect, so we need
-  // to fallback to other methods.
-  if (video_frame->visible_rect().size() != video_frame->coded_size()) {
-    TIZEN_MEDIA_LOG_NO_INSTANCE(VERBOSE)
-        << "Visible rect size ("
-        << video_frame->visible_rect().size().ToString()
-        << ") is different than coded size "
-        << video_frame->coded_size().ToString() << ")";
+  auto handle = video_frame->GetGpuMemoryBuffer()->CloneHandle();
+  constexpr uint64_t kFormatModifierLinear = 0;
+  // Linear buffers has it's dedicated function and they should not be handled
+  // in this function.
+  if (handle.native_pixmap_handle.modifier == kFormatModifierLinear) {
     return {};
   }
 
-  for (const auto& plane : gpu_memory_buffer.native_pixmap_handle.planes) {
-    if (plane.offset != 0) {
-      TIZEN_MEDIA_LOG_NO_INSTANCE(VERBOSE) << "Offset is non-zero";
-      return {};
-    }
-  }
-
-  auto tbm_surface = gfx::TbmSurface::ImportTbmSurface(
-      gpu_memory_buffer.native_pixmap_handle, video_frame->coded_size());
-
-  if (!tbm_surface)
-    return {};
-
-  media_packet_h media_packet_ptr{nullptr};
-
-  CHECK_AND_RETURN_MEDIA_PACKET(
-      media_packet_new_from_tbm_surface(
-          media_format.get(), **tbm_surface,
-          TizenVideoEncodeAcceleratorHelper::OnPacketProcessedByEncoderCallback,
-          thiz, &media_packet_ptr),
-      {});
-
-  return std::make_tuple(
-      MediaPacketType{media_packet_ptr},
-      base::ScopedClosureRunner{base::BindOnce(
-          [](std::unique_ptr<gfx::TbmSurface>) {}, std::move(tbm_surface))});
-}
-
-MediaPacketTuple CreateMediaPacketFromGpuMemoryBuffer(
-    const scoped_refptr<VideoFrame>& video_frame,
-    const MediaFormatType& media_format,
-    TizenVideoEncodeAccelerator* thiz) {
-  if (!video_frame->HasGpuMemoryBuffer())
-    return {};
-
   // VideoFrame was recreated in Browser process after being passed from
   // Renderer process. Its |gfx::GpuMemoryBuffer| received
   // |VEA_READ_CAMERA_AND_CPU_READ_WRITE| buffer usage (see
@@ -270,8 +229,7 @@ MediaPacketTuple CreateMediaPacketFromGpuMemoryBuffer(
   // readonly purposes only. We can do it by changing |gfx::BufferUsage| to
   // |SCANOUT_VEA_CPU_READ|.
   auto gmb = gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle(
-      thiz->GetClientNativePixmapFactory(),
-      video_frame->GetGpuMemoryBuffer()->CloneHandle(),
+      thiz->GetClientNativePixmapFactory(), std::move(handle),
       video_frame->coded_size(), gfx::BufferFormat::YUV_420_BIPLANAR,
       gfx::BufferUsage::SCANOUT_VEA_CPU_READ, base::DoNothing());
 
@@ -353,9 +311,9 @@ MediaPacketTuple CreateMediaPacketFromGpuMemoryBuffer(
 }
 
 MediaPacketTuple CreateMediaPacketFromRawData(
+    TizenVideoEncodeAccelerator* thiz,
     const scoped_refptr<VideoFrame>& video_frame,
-    const MediaFormatType& media_format,
-    TizenVideoEncodeAccelerator* thiz) {
+    const MediaFormatType& media_format) {
   // It is possible that this function will be called after failure of
   // |CreateMediaPacketFromGpuMemoryBuffer|. As this function is not designed to
   // work with |GpuMemoryBuffer|, we need to return here if |VideoFrame|
index 34c7438ddb402d683190bcec941343e755a1d3a2..4000b8acbe56024bc9d70b70b6b61e366e9e6d65 100644 (file)
@@ -65,20 +65,15 @@ using MediaFormatType =
 
 using MediaPacketTuple = std::tuple<MediaPacketType, base::ScopedClosureRunner>;
 
-MediaPacketTuple CreateMediaPacketFromTBMSurface(
-    const scoped_refptr<VideoFrame>& video_frame,
-    const MediaFormatType& media_format,
-    TizenVideoEncodeAccelerator* thiz);
-
 MediaPacketTuple CreateMediaPacketFromGpuMemoryBuffer(
+    TizenVideoEncodeAccelerator* thiz,
     const scoped_refptr<VideoFrame>& video_frame,
-    const MediaFormatType& media_format,
-    TizenVideoEncodeAccelerator* thiz);
+    const MediaFormatType& media_format);
 
 MediaPacketTuple CreateMediaPacketFromRawData(
+    TizenVideoEncodeAccelerator* thiz,
     const scoped_refptr<VideoFrame>& video_frame,
-    const MediaFormatType& media_format,
-    TizenVideoEncodeAccelerator* thiz);
+    const MediaFormatType& media_format);
 
 }  // namespace media
 
index 379e84ea54a03ea5d4dd126b708213ba899b3628..47ebad8080c52f82a1cd53efc9328747c8caf748 100644 (file)
@@ -132,6 +132,52 @@ bool TizenGpuBuffer::CopyFrom(uint32_t phys_addr,
   return ret == 1;
 }
 
+bool TizenGpuBuffer::CopyFrom(const TizenGpuBuffer& source,
+                              int src_stride,
+                              int src_offset,
+                              int dst_stride,
+                              int dst_offset,
+                              int width,
+                              int height,
+                              size_t bytes_per_element) {
+  tbm_bo_handle src_handle = tbm_bo_get_handle(source.bo_.get(), TBM_DEVICE_2D);
+  tbm_bo_handle dst_handle = tbm_bo_get_handle(bo_.get(), TBM_DEVICE_2D);
+  GraphicsGABltRopInfo ga_info;
+  memset(&ga_info, 0, sizeof(GraphicsGABltRopInfo));
+
+  // src info
+  ga_info.src_handle = src_handle.u32;
+  ga_info.src_hbytesize = src_stride;
+  ga_info.src_rect.x = (src_offset % src_stride) / bytes_per_element;
+  ga_info.src_rect.y = src_offset / src_stride;
+  ga_info.src_rect.w = width;
+  ga_info.src_rect.h = height;
+
+  // dst info
+  ga_info.dst_handle = dst_handle.u32;
+  ga_info.dst_hbytesize = dst_stride;
+  ga_info.dst_rect.x = (dst_offset % dst_stride) / bytes_per_element;
+  ga_info.dst_rect.y = dst_offset / dst_stride;
+
+  // GA info
+  switch (bytes_per_element) {
+    case 1:
+      ga_info.color_format = GRAPHICS_GA_FORMAT_8BPP;
+      break;
+    case 2:
+      ga_info.color_format = GRAPHICS_GA_FORMAT_16BPP;
+      break;
+    default:
+      return false;
+  }
+  ga_info.rop_mode = GRAPHICS_GA_ROP_COPY;
+  ga_info.pre_alphamode = 0;
+  ga_info.ga_mode = GRAPHICS_GA_BITBLT_MODE_NORMAL;
+  ga_info.ga_op_type = GRAPHICS_GA_COPY;
+  int ret = Gfx_GA_BltRop(bufmgr_.get(), &ga_info);
+  return ret == 1;
+}
+
 bool TizenGpuBuffer::Scale(uint32_t phys_addr,
                            int stride,
                            int dst_stride,
@@ -169,6 +215,55 @@ bool TizenGpuBuffer::Scale(uint32_t phys_addr,
   return Gfx_GA_Scale(bufmgr_.get(), &ga_info) == 1;
 }
 
+bool TizenGpuBuffer::Scale(const TizenGpuBuffer& source,
+                           int src_stride,
+                           int src_offset,
+                           int dst_stride,
+                           int dst_offset,
+                           int width,
+                           int height,
+                           int dst_width,
+                           int dst_height,
+                           size_t bytes_per_element) {
+  tbm_bo_handle src_handle = tbm_bo_get_handle(source.bo_.get(), TBM_DEVICE_2D);
+  tbm_bo_handle dst_handle = tbm_bo_get_handle(bo_.get(), TBM_DEVICE_2D);
+  GraphicsGAScaleInfo ga_info;
+  memset(&ga_info, 0, sizeof(GraphicsGAScaleInfo));
+
+  // src info
+  ga_info.src_handle = src_handle.u32;
+  ga_info.src_hbytesize = src_stride;
+  ga_info.src_rect.x = (src_offset % src_stride) / bytes_per_element;
+  ga_info.src_rect.y = src_offset / src_stride;
+  ga_info.src_rect.w = width;
+  ga_info.src_rect.h = height;
+
+  // dst info
+  ga_info.dst_handle = dst_handle.u32;
+  ga_info.dst_hbytesize = dst_stride;
+  ga_info.dst_rect.x = (dst_offset % dst_stride) / bytes_per_element;
+  ga_info.dst_rect.y = dst_offset / dst_stride;
+  ga_info.dst_rect.w = dst_width;
+  ga_info.dst_rect.h = dst_height;
+
+  // GA info
+  switch (bytes_per_element) {
+    case 1:
+      ga_info.color_format = GRAPHICS_GA_FORMAT_8BPP;
+      break;
+    case 2:
+      ga_info.color_format = GRAPHICS_GA_FORMAT_16BPP;
+      break;
+    default:
+      return false;
+  }
+  ga_info.rop_mode = GRAPHICS_GA_ROP_COPY;
+  ga_info.pre_alphamode = 0;
+  ga_info.ga_mode = GRAPHICS_GA_SCALE_MODE;
+  ga_info.ga_op_type = GRAPHICS_GA_SCALE;
+  return Gfx_GA_Scale(bufmgr_.get(), &ga_info) == 1;
+}
+
 TizenGpuBuffer::TizenGpuBuffer(TbmBufMgrType bufmgr, TbmBOType bo)
     : bufmgr_(std::move(bufmgr)), bo_(std::move(bo)) {}
 
index 79854c8afa0ef88ed6870f1063448a2fe7f203b8..f01269e11837208db4ff97de53438bbcefe3d7cf 100644 (file)
@@ -37,6 +37,14 @@ class TizenGpuBuffer {
                 int height,
                 int src_offset = 0,
                 int dst_offset = 0);
+  bool CopyFrom(const TizenGpuBuffer& source,
+                int src_stride,
+                int src_offset,
+                int dst_stride,
+                int dst_offset,
+                int width,
+                int height,
+                size_t bytes_per_element);
   bool Scale(uint32_t phys_addr,
              int stride,
              int dst_stride,
@@ -45,6 +53,16 @@ class TizenGpuBuffer {
              int target_height,
              int src_offset = 0,
              int dst_offset = 0);
+  bool Scale(const TizenGpuBuffer& source,
+             int src_stride,
+             int src_offset,
+             int dst_stride,
+             int dst_offset,
+             int width,
+             int height,
+             int dst_width,
+             int dst_height,
+             size_t bytes_per_element);
   const uint8_t* Memory() const { return data_; }
   uint8_t* Memory() { return data_; }
   size_t Size() const { return tbm_bo_size(bo_.get()); }