[NUI] Use double buffer for NUI rendering 97/315497/7
authorYongGeol Jung <yg48.jung@samsung.com>
Mon, 2 Dec 2024 09:33:21 +0000 (01:33 -0800)
committerBot Blink <blinkbot@samsung.com>
Thu, 5 Dec 2024 05:09:57 +0000 (05:09 +0000)
In the case of NUI, TBM buffer is rendered from the web engine's gpu
thread and then used for rendering window surface via the app's render
thread. In this structure, if both threads simultaneously access a
single TBM buffer, there could be a screen flickering problem. When
using one buffer, explicit locks must be applied in both threads, but
currently, such locks cannot be added due to the existing structure. To
solve this issue, modified to use double buffer.

Change-Id: Icced89c18bc8549d61f8a9ead5ee1297bcfb30a1
Signed-off-by: YongGeol Jung <yg48.jung@samsung.com>
components/viz/service/display_embedder/skia_output_device_offscreen.cc
components/viz/service/display_embedder/skia_output_device_offscreen.h
tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.cc
tizen_src/chromium_impl/components/viz/service/display_embedder/skia_output_device_offscreen_tbm.h

index bea1d643ac21da252726380400c6ebef6c4489b1..8e43fbc8c48f3b4dbc5d63fdece5fc7744574950 100644 (file)
@@ -123,6 +123,9 @@ void SkiaOutputDeviceOffscreen::Present(
 #endif
     last_swapped_buffer_need_sync_ = frame.need_sync;
 
+  if (ForceSync())
+    last_swapped_buffer_need_sync_ = true;
+
   gr_context_->flushAndSubmit(GrSyncCpu::kYes);
 #endif
   FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK),
index e14791eb9630fcd2d102f862c98098525e63a0fa..3d29a1f9a53f0adea6d51f25c12f9609465a435d 100644 (file)
@@ -52,6 +52,8 @@ class SkiaOutputDeviceOffscreen : public SkiaOutputDevice {
   size_t GetTextureID() override;
   bool NeedSync() override;
   void DeleteResizedTextures();
+
+  virtual bool ForceSync() { return false; }
 #endif
 
  protected:
index e22a8e65275ea4fc0e53aed01952f8f3e8ba85ce..214449b9200f98df042e8db800ef7a26e182f817 100644 (file)
 
 namespace viz {
 
+OffscreenTBMBuffer::OffscreenTBMBuffer() {}
+
+OffscreenTBMBuffer::~OffscreenTBMBuffer() {
+  Destroy();
+}
+
+void OffscreenTBMBuffer::Create(int width, int height) {
+  tbm_surface_ = tbm_surface_create(width, height, TBM_FORMAT_ARGB8888);
+
+  if (gpu::EGLImageTizen::IsSupported()) {
+    egl_image_ = gpu::EGLImageTizen::MakeScopedEGLImage(tbm_surface_);
+  } else if (gpu::EGLImageDMABUF::IsSupported()) {
+    egl_image_ = gpu::EGLImageDMABUF::MakeScopedEGLImage(tbm_surface_);
+  } else {
+    LOG(ERROR) << "no fallback extension for OffscreenTBMBuffer::Create";
+    assert(false);
+  }
+
+  glGenTextures(1, &texture_id_);
+  glBindTexture(GL_TEXTURE_2D, texture_id_);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_.get());
+}
+
+void OffscreenTBMBuffer::Destroy() {
+  if (egl_image_.get()) {
+    egl_image_.reset();
+  }
+
+  if (tbm_surface_) {
+    if (tbm_surface_destroy(tbm_surface_) != TBM_SURFACE_ERROR_NONE) {
+      LOG(ERROR) << "Failed to destroy tbm surface.";
+    }
+    tbm_surface_ = 0;
+  }
+}
+
 SkiaOutputDeviceOffscreenTBM::SkiaOutputDeviceOffscreenTBM(
     scoped_refptr<gpu::SharedContextState> context_state,
     gfx::SurfaceOrigin origin,
@@ -23,7 +61,7 @@ SkiaOutputDeviceOffscreenTBM::SkiaOutputDeviceOffscreenTBM(
                                 has_alpha,
                                 memory_tracker,
                                 did_swap_buffer_complete_callback) {
-  max_buffer_size_ = 1;
+  max_buffer_size_ = MAX_OFFSCREEN_BUFFER_SIZE;
 }
 
 SkiaOutputDeviceOffscreenTBM::~SkiaOutputDeviceOffscreenTBM() {
@@ -31,50 +69,36 @@ SkiaOutputDeviceOffscreenTBM::~SkiaOutputDeviceOffscreenTBM() {
 }
 
 void SkiaOutputDeviceOffscreenTBM::EnsureBackbuffer() {
-  if (size_.IsEmpty())
+  if (size_.IsEmpty()) {
     return;
-
-  tbm_surface_ = tbm_surface_create(
-      size_.width(), size_.height(), TBM_FORMAT_ARGB8888);
-
-  if (gpu::EGLImageTizen::IsSupported()) {
-    egl_image_ = gpu::EGLImageTizen::MakeScopedEGLImage(tbm_surface_);
-  } else if (gpu::EGLImageDMABUF::IsSupported()) {
-    egl_image_ = gpu::EGLImageDMABUF::MakeScopedEGLImage(tbm_surface_);
-  } else {
-    LOG(ERROR) << "no fallback extension for SkiaOutputDeviceOffscreenTBM::EnsureBackbuffer";
-    assert(false);
   }
 
-  GLuint texture_id = 0;
-  glGenTextures(1, &texture_id);
-  glBindTexture(GL_TEXTURE_2D, texture_id);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_.get());
-
-  gpu::GetGrBackendTexture(context_state_->feature_info(), GL_TEXTURE_2D, size_,
-                           texture_id, GR_GL_RGBA8,
-                           context_state_->gr_context()->threadSafeProxy(),
-                           &(backend_textures_[0]));
+  for (int i = 0; i < max_buffer_size_; i++) {
+    tbm_buffers_[i].Create(size_.width(), size_.height());
+    gpu::GetGrBackendTexture(context_state_->feature_info(), GL_TEXTURE_2D,
+                             size_, tbm_buffers_[i].texture_id(), GR_GL_RGBA8,
+                             context_state_->gr_context()->threadSafeProxy(),
+                             &(backend_textures_[i]));
+  }
 }
 
 void SkiaOutputDeviceOffscreenTBM::DiscardBackbuffer() {
-  if (tbm_surface_) {
-    if (tbm_surface_destroy(tbm_surface_) != TBM_SURFACE_ERROR_NONE)
-      LOG(ERROR) << "Failed to destroy tbm surface.";
-    tbm_surface_ = 0;
+  for (int i = 0; i < max_buffer_size_; i++) {
+    tbm_buffers_[i].Destroy();
   }
-
   SkiaOutputDeviceOffscreen::DiscardBackbuffer();
 }
 
 size_t SkiaOutputDeviceOffscreenTBM::GetTextureID() {
-  return reinterpret_cast<size_t>(tbm_surface_);
+  return reinterpret_cast<size_t>(
+      tbm_buffers_[last_swapped_buffer_index_].tbm_surface());
 }
 
 bool SkiaOutputDeviceOffscreenTBM::NeedSync() {
-  return false;
+  return SkiaOutputDeviceOffscreen::NeedSync();
+}
+
+bool SkiaOutputDeviceOffscreenTBM::ForceSync() {
+  return true;
 }
 }  // namespace viz
index 101d0d3d46390a30065d4e9867698b557218c72a..228b3f6465046f186342b5a7de756186fc702929 100644 (file)
 
 namespace viz {
 
+class OffscreenTBMBuffer {
+ public:
+  OffscreenTBMBuffer();
+  ~OffscreenTBMBuffer();
+
+  void Create(int width, int height);
+  void Destroy();
+
+  GLuint texture_id() { return texture_id_; }
+  void* tbm_surface() { return tbm_surface_; }
+
+ private:
+  tbm_surface_h tbm_surface_ = 0;
+  gl::ScopedEGLImage egl_image_;
+  GLuint texture_id_ = 0;
+};
+
 class SkiaOutputDeviceOffscreenTBM : public SkiaOutputDeviceOffscreen {
  public:
   SkiaOutputDeviceOffscreenTBM(
@@ -24,6 +41,8 @@ class SkiaOutputDeviceOffscreenTBM : public SkiaOutputDeviceOffscreen {
 
   ~SkiaOutputDeviceOffscreenTBM() override;
 
+  bool ForceSync() override;
+
   void EnsureBackbuffer() override;
   void DiscardBackbuffer() override;
 
@@ -31,8 +50,7 @@ class SkiaOutputDeviceOffscreenTBM : public SkiaOutputDeviceOffscreen {
   bool NeedSync() override;
 
  private:
-  tbm_surface_h tbm_surface_ = 0;
-  gl::ScopedEGLImage egl_image_;
+  OffscreenTBMBuffer tbm_buffers_[MAX_OFFSCREEN_BUFFER_SIZE];
 };
 
 }  // namespace viz