chromium/device/vr/android/arcore/arcore_device.h

// Copyright 2018 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_ARCORE_ARCORE_DEVICE_H_
#define DEVICE_VR_ANDROID_ARCORE_ARCORE_DEVICE_H_

#include <jni.h>

#include <memory>
#include <optional>
#include <unordered_set>
#include <utility>

#include "base/android/jni_android.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/task/single_thread_task_runner.h"
#include "device/vr/android/arcore/arcore_gl.h"
#include "device/vr/public/cpp/xr_frame_sink_client.h"
#include "device/vr/vr_device.h"
#include "device/vr/vr_device_base.h"
#include "gpu/ipc/common/surface_handle.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/native_widget_types.h"

namespace ui {
class WindowAndroid;
}  // namespace ui

namespace device {

class ArImageTransportFactory;
class ArCoreFactory;
class ArCoreGlThread;
class XrJavaCoordinator;
class CompositorDelegateProvider;
class MailboxToSurfaceBridge;
class MailboxToSurfaceBridgeFactory;

class COMPONENT_EXPORT(VR_ARCORE) ArCoreDevice : public VRDeviceBase {
 public:
  ArCoreDevice(
      std::unique_ptr<ArCoreFactory> arcore_factory,
      std::unique_ptr<ArImageTransportFactory> ar_image_transport_factory,
      std::unique_ptr<MailboxToSurfaceBridgeFactory>
          mailbox_to_surface_bridge_factory,
      std::unique_ptr<XrJavaCoordinator> xr_java_coordinator,
      std::unique_ptr<CompositorDelegateProvider> compositor_delegate_provider,
      XrFrameSinkClientFactory xr_frame_sink_client_factory);

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

  ~ArCoreDevice() override;

  // VRDeviceBase implementation.
  void RequestSession(
      mojom::XRRuntimeSessionOptionsPtr options,
      mojom::XRRuntime::RequestSessionCallback callback) override;

  void ShutdownSession(mojom::XRRuntime::ShutdownSessionCallback) override;

  base::WeakPtr<ArCoreDevice> GetWeakPtr() {
    return weak_ptr_factory_.GetWeakPtr();
  }

 private:
  void OnDrawingSurfaceReady(gfx::AcceleratedWidget window,
                             gpu::SurfaceHandle surface_handle,
                             ui::WindowAndroid* root_window,
                             display::Display::Rotation rotation,
                             const gfx::Size& frame_size);
  void OnDrawingSurfaceTouch(bool is_primary,
                             bool touching,
                             int32_t pointer_id,
                             const gfx::PointF& location);
  void OnDrawingSurfaceDestroyed();
  void OnSessionEnded();

  void PostTaskToGlThread(base::OnceClosure task);

  bool IsOnMainThread();

  // Called once the GL thread is started. At this point, it doesn't
  // have a valid GL context yet.
  void OnGlThreadReady(int render_process_id,
                       int render_frame_id,
                       bool use_overlay);

  // Replies to the pending mojo RequestSession request.
  void CallDeferredRequestSessionCallback(
      ArCoreGlInitializeStatus arcore_initialization_result);

  // Tells the GL thread to initialize a GL context and other resources,
  // using the supplied window as a drawing surface.
  void RequestArCoreGlInitialization(gfx::AcceleratedWidget window,
                                     gpu::SurfaceHandle surface_handle,
                                     ui::WindowAndroid* root_window,
                                     int rotation,
                                     const gfx::Size& size);

  // Called when the GL thread's GL context initialization completes.
  void OnArCoreGlInitializationComplete(
      ArCoreGlInitializeStatus arcore_initialization_result);

  void OnCreateSessionCallback(
      mojom::XRRuntime::RequestSessionCallback deferred_callback,
      ArCoreGlInitializeResult initialize_result,
      ArCoreGlCreateSessionResult create_session_result);

  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
  std::unique_ptr<ArCoreFactory> arcore_factory_;
  std::unique_ptr<ArImageTransportFactory> ar_image_transport_factory_;
  std::unique_ptr<MailboxToSurfaceBridgeFactory> mailbox_bridge_factory_;
  std::unique_ptr<XrJavaCoordinator> xr_java_coordinator_;
  std::unique_ptr<CompositorDelegateProvider> compositor_delegate_provider_;
  XrFrameSinkClientFactory xr_frame_sink_client_factory_;

  std::unique_ptr<MailboxToSurfaceBridge> mailbox_bridge_;

  // Because the FrameSinkClient needs to have a teardown method called on it
  // before it is destructed, we need to own it rather than the ArCoreGl. Note
  // that this *also* means that we need to guarantee that it outlives the Gl
  // thread.
  std::unique_ptr<XrFrameSinkClient> frame_sink_client_;

  // Encapsulates data with session lifetime.
  struct SessionState {
    SessionState();
    ~SessionState();

    std::unique_ptr<ArCoreGlThread> arcore_gl_thread_;
    bool is_arcore_gl_initialized_ = false;

    base::OnceClosure start_immersive_activity_callback_;

    // The initial requestSession triggers the initialization sequence, store
    // the callback for replying once that initialization completes. Only one
    // concurrent session is supported, other requests are rejected.
    mojom::XRRuntime::RequestSessionCallback pending_request_session_callback_;

    // Collections of features that were requested on the session.
    std::unordered_set<device::mojom::XRSessionFeature> required_features_;
    std::unordered_set<device::mojom::XRSessionFeature> optional_features_;

    device::mojom::XRDepthOptionsPtr depth_options_;

    // Collection of features that have been enabled on the session. Initially
    // empty, will be set only once the ArCoreGl has been initialized.
    std::unordered_set<device::mojom::XRSessionFeature> enabled_features_;

    std::optional<device::mojom::XRDepthConfig> depth_configuration_;

    std::vector<device::mojom::XRTrackedImagePtr> tracked_images_;

    viz::FrameSinkId frame_sink_id_;

    // Trace ID of the requestSession() call that resulted in creating this
    // session state.
    uint64_t request_session_trace_id_;

    // In case of driver bugs that need workarounds (see
    // ArImageTransport::OnSurfaceBridgeReady), allow a one-time
    // retry of session creation. This needs a copy of the original
    // session creation options.
    bool allow_retry_ = true;
    mojom::XRRuntimeSessionOptionsPtr options_clone_for_retry_;
    bool initiate_retry_ = false;
  };

  // This object is reset to initial values when ending a session. This helps
  // ensure that each session has consistent per-session state.
  std::unique_ptr<SessionState> session_state_;

  base::OnceCallback<void(bool)>
      on_request_arcore_install_or_update_result_callback_;
  base::OnceCallback<void(bool)> on_request_ar_module_result_callback_;

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

}  // namespace device

#endif  // DEVICE_VR_ANDROID_ARCORE_ARCORE_DEVICE_H_