910e62b5创建于 1月15日历史提交
// 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_OPENXR_OPENXR_GRAPHICS_BINDING_H_
#define DEVICE_VR_OPENXR_OPENXR_GRAPHICS_BINDING_H_

#include <cstdint>
#include <vector>

#include "base/containers/span.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "device/vr/openxr/openxr_composition_layer.h"
#include "device/vr/openxr/openxr_layers.h"
#include "device/vr/openxr/openxr_swapchain_info.h"
#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
#include "mojo/public/cpp/platform/platform_handle.h"
#include "third_party/openxr/src/include/openxr/openxr.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"

namespace gfx {
class GpuFence;
}  // namespace gfx

namespace gpu {
class SharedImageInterface;
}  // namespace gpu

namespace viz {
class ContextProvider;
}  // namespace viz

namespace device {
class OpenXrCompositionLayer;
class OpenXrExtensionEnumeration;
class OpenXrViewConfiguration;

// This class exists to provide an abstraction for the different rendering
// paths that can be taken by OpenXR (e.g. DirectX vs. GLES). Any OpenXr methods
// that need types specific for a given renderer type should go through this
// interface.
class OpenXrGraphicsBinding {
 public:
  // Gets the set of RequiredExtensions that need to be present on the platform.
  static void GetRequiredExtensions(std::vector<const char*>& extensions);

  // Gets any OptionalExtensions that should be enabled if present.
  static std::vector<std::string> GetOptionalExtensions();

  virtual ~OpenXrGraphicsBinding();

  // Ensures that the GraphicsBinding is ready for use.
  virtual bool Initialize(XrInstance instance, XrSystemId system) = 0;

  // Called after the XrSession has been created.
  void OnSessionCreated(XrSpace local_space, bool is_webgpu);

  // Called when the XrSession is going to destroyed.
  void OnSessionDestroyed(gpu::SharedImageInterface* sii);

  // Gets a pointer to a platform-specific XrGraphicsBindingFoo. The pointer is
  // guaranteed to live as long as this class does.
  virtual const void* GetSessionCreateInfo() const = 0;

  // Gets the format that we expect from the platform swapchain.
  virtual int64_t GetSwapchainFormat(XrSession session) const = 0;

  // Calls xrEnumerateSwapChain and updates the stored OpenXrSwapchainInfo
  // available via `GetSwapChainImages`.
  virtual XrResult EnumerateSwapchainImages(OpenXrCompositionLayer& layer) = 0;

  // Returns whether or not the platform believes it can support using Shared
  // buffers/images.
  virtual bool CanUseSharedImages() const = 0;

  // Called when a frame is going to end without any attempt at rendering, in
  // case there is any early cleanup to do that would otherwise occur during
  // `Render`.
  virtual void CleanupWithoutSubmit() = 0;

  // Returns the maximum texture size allowed to be created with the current
  // graphics binding. Textures larger than this size may be truncated during
  // cross-process transportation of the textures and result in one viewport
  // being rendered on over half of the texture, which can lead to uncomfortable
  // rendering artifacts.
  virtual gfx::Size GetMaxTextureSize() = 0;

  // Called to indicate which of Overlay and WebXR content is expected to be
  // composited during calls to `Render`.
  void SetOverlayAndWebXrVisibility(bool overlay_visible, bool webxr_visible);

  // There are three different paths that submitting an image can take. In two
  // of them, we provide the surface/image for the page to draw into. The third
  // is only supported on Windows or via the overlay code and requires
  // submitting a texture handle to us, which we don't own. The first two
  // rendering methods will have their data tied to the active swapchain image,
  // but for the third method, we don't have to do any lifecycle management and
  // will just hold a reference to the latest submitted texture. It will be
  // valid until we end the frame, but can then be overwritten independently
  // during the cycle. Since this third code-path only exists on Windows we
  // restrict this method to that platform.
#if BUILDFLAG(IS_WIN)
  virtual void SetWebXrTexture(mojo::PlatformHandle texture_handle,
                               const gpu::SyncToken& sync_token,
                               const gfx::RectF& left,
                               const gfx::RectF& right) = 0;
#endif

  // Much like the `SetWebXrTexture` path above, the texture submitted here is
  // owned by the browser process with corresponding lifetime management
  // and synchronization happening there. It's valid until we tell it we're done
  // with the texture, but it's not tied to a swapchain info the same way that
  // the page's textures are, so we provide this additional method and simply
  // overwrite the overlay whenever we receive it.
  virtual bool SetOverlayTexture(gfx::GpuMemoryBufferHandle texture,
                                 const gpu::SyncToken& sync_token,
                                 const gfx::RectF& left,
                                 const gfx::RectF& right) = 0;

  // Will be called when SetSwapchainImageSize is called, even if a change is
  // not made, to allow child classes/concrete implementations to override any
  // state that they may need to override as a result of the swapchain image
  // size changing. Note that the caller is responsible for recreating the
  // swapchain in response to this call, but it likely has not been recreated
  // yet.
  virtual void OnSwapchainImageSizeChanged(OpenXrCompositionLayer& layer) {}

  // Called at the end of ActivateSwapchainImage. Allows Children to setup the
  // appropriate image to be rendered to by, e.g. Render calls, if that needs
  // to happen ahead of time.
  virtual void OnSwapchainImageActivated(OpenXrCompositionLayer& layer,
                                         gpu::SharedImageInterface* sii) = 0;

  // Return if the graphics binding supports multiple XR layers.
  virtual bool SupportsLayers() const = 0;

  // Resizes the shared buffer for the given swapchain info if the transfer size
  // has changed.
  virtual void ResizeSharedBuffer(OpenXrCompositionLayer& layer,
                                  OpenXrSwapchainInfo& swap_chain_info,
                                  gpu::SharedImageInterface* sii) = 0;

  // Called to indicate which graphics API produced the textures submitted to
  // OpenXR. Does not affect the API used for compositing.
  bool IsWebGPUSession() const { return webgpu_session_; }

  // If the layer should be flipped, return a pointer to the
  // XrCompositionLayerImageLayoutFB. Otherwise, return null. The return value
  // should be set to the "next" field of the XrCompositionLayer* struct.
  const void* GetFlipLayerLayout() const;

  // We check if the base layer is using shared images.
  bool IsUsingSharedImages() const;

  // Called when context proivder is lost.
  void OnContextProviderLost();

  // Build an OpenXrLayers object that provides data needed for xrEndFrame
  // (e.g. a list of XrCompositionLayerBaseHeader).
  std::unique_ptr<OpenXrLayers> GetLayersForViewConfig(
      OpenXrApiWrapper* openxr,
      const OpenXrViewConfiguration& view_config) const;

  // A few methods that only operate on the base layer.

  // Create the XrSwapchain and swapchain images for the base layer.
  XrResult CreateBaseLayerSwapchain(XrSession session, uint32_t sample_count);

  // Clears the list of images allocated during `CreateBaseLayerSwapchain` and
  // if a context_provider is provided and the Swapchain entries have had
  // corresponding SharedImages created via `CreateBaseLayerSharedImages` will
  // also clean up those SharedImages.
  void DestroyBaseLayerSwapchain(gpu::SharedImageInterface* sii);

  // Creates SharedImages for (and thus populates the mailbox holders of) all
  // currently held OpenXrSwapchainInfo objects.
  void CreateBaseLayerSharedImages(gpu::SharedImageInterface* sii);

  // Returns the previously set swapchain image size, or 0,0 if one is not set.
  gfx::Size GetProjectionLayerSwapchainImageSize();

  // Sets the size of the swapchain images being used by the system. Does *not*
  // cause a corresponding re-creation of the Swapchain or Shared Images; which
  // should be driven by the caller. If a transfer size has not been specified
  // yet, will also set the transfer size as well.
  void SetProjectionLayerSwapchainImageSize(
      const gfx::Size& swapchain_image_size);

  // Return if the XrSwapchain is available.
  bool HasBaseLayerColorSwapchain() const;

  // Sets the size of the texture being used between the renderer process and
  // our process. This is largely driven by the page and any framebuffer scaling
  // it may apply. When rendering to the SwapchainImage scaling will be
  // performed as necessary.
  void SetProjectionLayerTransferSize(const gfx::Size& transfer_size);

  // Performs a server wait on the provided gpu_fence. Returns true if it was
  // able to successfully schedule and perform the wait, and false otherwise.
  bool WaitOnBaseLayerFence(gfx::GpuFence& gpu_fence);

  // Updates the active swapchain image size if the transfer size has changed.
  // No-ops if there is currently no active swapchain image.
  void UpdateProjectionLayerActiveSwapchainImageSize(
      gpu::SharedImageInterface* sii);

  // Build XR projection views for the base layer.
  std::vector<XrCompositionLayerProjectionView> GetBaseLayerProjectionViews(
      const OpenXrViewConfiguration& view_config) const;

  // A few methods that operate on all layers.

  // Acquire and activate swapchain images from the OpenXr system
  XrResult ActivateSwapchainImages(gpu::SharedImageInterface* sii);

  // Release the active swapchain images from the OpenXr system. This is called
  // before calling EndFrame and will enable acquiring a new swapchain image for
  // the next frame.
  XrResult ReleaseActiveSwapchainImages();

  // Populate the shared image data in XRFrameData.
  void PopulateSharedImageData(mojom::XRFrameData& frame_data);

  // Causes the GraphicsBinding to render the currently active swapchain image.
  bool Render(const scoped_refptr<viz::ContextProvider>& context_provider,
              const std::vector<LayerId>& updated_layers);

  // Create a composition layer. The id is given in layer_data.
  bool CreateCompositionLayer(
      mojom::XRCompositionLayerDataPtr layer_data,
      gpu::SharedImageInterface* shared_image_interface);

  // Get a composition layer by its layer id. Returns nullptr
  // if the layer id doesn't exist.
  OpenXrCompositionLayer* GetCompositionLayer(LayerId layer_id);

  // Destroy a composition layer.
  void DestroyCompositionLayer(LayerId layer_id,
                               gpu::SharedImageInterface* sii);

  // Specify the layers that should be rendered and should have shared
  // images available.
  void SetEnabledCompositionLayers(const std::vector<LayerId>& layer_ids,
                                   XrSession session,
                                   uint32_t swapchain_sample_count,
                                   gpu::SharedImageInterface* sii);

 protected:
  explicit OpenXrGraphicsBinding(
      const OpenXrExtensionEnumeration* extension_enum);

  bool ShouldRenderBaseLayer() const;

  // Performs a server wait on the provided gpu_fence. Returns true if it was
  // able to successfully schedule and perform the wait, and false otherwise.
  virtual bool WaitOnFence(OpenXrCompositionLayer& layer,
                           gfx::GpuFence& gpu_fence) = 0;

  // Render a single layer.
  virtual bool RenderLayer(
      OpenXrCompositionLayer& layer,
      const scoped_refptr<viz::ContextProvider>& context_provider) = 0;

  // Creates SharedImages for (and thus populates the mailbox holders of) all
  // currently held OpenXrSwapchainInfo objects.
  virtual void CreateSharedImages(OpenXrCompositionLayer& layer,
                                  gpu::SharedImageInterface* sii) = 0;

  // Indicates whether the graphics binding expects the submitted image to need
  // to be flipped when being submitted to the runtime.
  virtual bool ShouldFlipSubmittedImage(
      OpenXrCompositionLayer& layer) const = 0;

  // Create a graphics binding specific data.
  virtual std::unique_ptr<OpenXrCompositionLayer::GraphicsBindingData>
  CreateLayerGraphicsBindingData() const = 0;

  // Called when SetOverlayAndWebXrVisibility is called and the internal flags
  // have been updated.
  virtual void OnSetOverlayAndWebXrVisibility() {}

  // Build XR projection views for a projection layer.
  std::vector<XrCompositionLayerProjectionView> GetProjectionViews(
      const OpenXrViewConfiguration& view_config,
      OpenXrCompositionLayer& layer) const;

  std::unique_ptr<OpenXrCompositionLayer> base_layer_;
  // Each client created layer has a unique ID.
  std::map<LayerId, std::unique_ptr<OpenXrCompositionLayer>> layers_;
  // This sequence defines which layers should be composed.
  std::vector<LayerId> layers_sequence_;
  bool has_custom_projection_layer_ = false;
  bool webgpu_session_ = false;
  bool fb_composition_layer_ext_enabled_ = false;
  bool webxr_visible_ = true;
  bool overlay_visible_ = false;

  // This will only be valid if `fb_composition_layer_ext_enabled_` is true.
  XrCompositionLayerImageLayoutFB y_flip_layer_layout_;
};

}  // namespace device

#endif  // DEVICE_VR_OPENXR_OPENXR_GRAPHICS_BINDING_H_