chromium/device/vr/android/xr_image_transport_base.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef DEVICE_VR_ANDROID_XR_IMAGE_TRANSPORT_BASE_H_
#define DEVICE_VR_ANDROID_XR_IMAGE_TRANSPORT_BASE_H_

#include <memory>

#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "device/vr/android/local_texture.h"
#include "device/vr/android/web_xr_presentation_state.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gl/gl_bindings.h"

namespace gl {
class SurfaceTexture;
}  // namespace gl

namespace gfx {
class GpuFence;
}  // namespace gfx

namespace gpu {
struct MailboxHolder;
struct SyncToken;
}  // namespace gpu

namespace device {

class MailboxToSurfaceBridge;

using XrFrameCallback = base::RepeatingCallback<void(const gfx::Transform&)>;
using XrInitStatusCallback = base::OnceCallback<void(bool success)>;

// This class handles transporting WebGL rendered output from the GPU process's
// command buffer GL context to the local GL context, and compositing WebGL
// output onto the camera image using the local GL context.
// Non pure-virtual methods are only intended to be overridden for testing
// purposes.
class XrImageTransportBase {
 public:
  // If true, use shared buffer transport aka DRAW_INTO_TEXTURE_MAILBOX.
  // If false, use Surface transport aka SUBMIT_AS_MAILBOX_HOLDER.
  static bool UseSharedBuffer();

  static GLuint SharedBufferTextureTarget();

  explicit XrImageTransportBase(
      std::unique_ptr<MailboxToSurfaceBridge> mailbox_bridge);

  XrImageTransportBase(const XrImageTransportBase&) = delete;
  XrImageTransportBase& operator=(const XrImageTransportBase&) = delete;

  virtual ~XrImageTransportBase();

  virtual void DestroySharedBuffers(WebXrPresentationState* webxr);

  // All methods must be called on a valid GL thread. Initialization
  // must happen after the local GL context is ready for use. That
  // starts the asynchronous setup for the GPU process command buffer
  // GL context via MailboxToSurfaceBridge, and the callback is called
  // once that's complete.
  virtual void Initialize(WebXrPresentationState* webxr,
                          XrInitStatusCallback callback);

  // Only valid when using SharedBuffers, this ensures that the current
  // animating frame is populated with texture information for a valid and
  // correctly sized shared buffer backed by an EGL image. This function
  // intends to return to its caller a sync token as well as
  // a scoped_refptr<gpu::ClientSharedImage> pointing to this shared buffer
  // suitable to transfer to another process to allow it to write to the
  // shared buffer. The two values are currently returned together via
  // a wrapping WebXrSharedBuffer.
  // TODO(crbug.com/40286368): Change the return type to
  // scoped_refptr<gpu::ClientSharedImage> once the sync token is
  // incorporated into ClientSharedImage.
  virtual WebXrSharedBuffer* TransferFrame(WebXrPresentationState* webxr,
                                           const gfx::Size& frame_size,
                                           const gfx::Transform& uv_transform);
  virtual void CreateGpuFenceForSyncToken(
      const gpu::SyncToken& sync_token,
      base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)>);
  virtual void WaitSyncToken(const gpu::SyncToken& sync_token);
  virtual void CopyMailboxToSurfaceAndSwap(const gfx::Size& frame_size,
                                           const gpu::MailboxHolder& mailbox,
                                           const gfx::Transform& uv_transform);

  void SetFrameAvailableCallback(XrFrameCallback on_frame_available);
  void ServerWaitForGpuFence(std::unique_ptr<gfx::GpuFence> gpu_fence);

 protected:
  bool IsOnGlThread() const;

  virtual std::unique_ptr<WebXrSharedBuffer> CreateBuffer();

  // Returns true if the buffer was resized and its sync token updated.
  bool ResizeSharedBuffer(WebXrPresentationState* webxr,
                          const gfx::Size& size,
                          WebXrSharedBuffer* buffer);

  // This method provides an abstraction to the caller about whether the system
  // is running in SharedBuffer mode or not, and returns the texture that the
  // renderer has most recently populated and submitted back to the device for
  // rendering. There must be a texture in the `RenderingFrame` state of the
  // `WebXrPresentationState` machine for this to properly return data.
  LocalTexture GetRenderingTexture(WebXrPresentationState* webxr);

  // Runs before the rest of the initialization for the XrImageTransport to
  // allow for any specialized gl context setup or other setup that may be
  // needed by the particular runtime that's in use.
  virtual void DoRuntimeInitialization(int texture_target) = 0;

  std::unique_ptr<MailboxToSurfaceBridge> mailbox_bridge_;

 private:
  // Used to disable UseSharedBuffer on platforms where the feature is available
  // but unusable due to driver bugs. Must be mutable so that it can be switched
  // to true persistently before retrying session creation, so it can't be
  // constexpr or inline.
  static bool disable_shared_buffer_;

  void ResizeSurface(const gfx::Size& size);
  void OnMailboxBridgeReady(XrInitStatusCallback callback);
  void OnFrameAvailable();

  scoped_refptr<base::SingleThreadTaskRunner> gl_thread_task_runner_;

  // Used for Surface transport (Android N)
  //
  // samplerExternalOES texture data for WebXR content image.
  LocalTexture transport_texture_;
  gfx::Size surface_size_;
  scoped_refptr<gl::SurfaceTexture> transport_surface_texture_;
  gfx::Transform transport_surface_texture_uv_transform_;
  float transport_surface_texture_uv_matrix_[16];
  XrFrameCallback on_transport_frame_available_;

  // Must be last.
  base::WeakPtrFactory<XrImageTransportBase> weak_ptr_factory_{this};
};

}  // namespace device

#endif  // DEVICE_VR_ANDROID_XR_IMAGE_TRANSPORT_BASE_H_