| // 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_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 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() = default; |
| |
| // Ensures that the GraphicsBinding is ready for use. |
| virtual bool Initialize(XrInstance instance, XrSystemId system) = 0; |
| |
| // 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( |
| const XrSwapchain& color_swapchain) = 0; |
| |
| // Returns a list of mutable OpenXrSwapchainInfo objects. While the items |
| // themselves are mutable, the list is not. |
| // TODO(crbug.com/40909689): Make OpenXrSwapchainInfo internal to the child |
| // classes. |
| virtual base::span<OpenXrSwapchainInfo> GetSwapChainImages() = 0; |
| |
| // Const getter of the above. |
| virtual base::span<const OpenXrSwapchainInfo> GetSwapChainImages() const = 0; |
| |
| // Returns whether or not the platform believes it can support using Shared |
| // buffers/images. |
| virtual bool CanUseSharedImages() const = 0; |
| |
| // Creates SharedImages for (and thus populates the mailbox holders of) all |
| // currently held OpenXrSwapchainInfo objects. |
| virtual void CreateSharedImages(gpu::SharedImageInterface* sii) = 0; |
| |
| // Returns the currently active swapchain image. This is only valid between |
| // calls to ActivateSwapchainImage and ReleaseSwapchainImage, which happens |
| // after BeginFrame and before EndFrame. |
| // TODO(crbug.com/40909689): Make OpenXrSwapchainInfo internal to the child |
| // classes. |
| virtual const OpenXrSwapchainInfo& GetActiveSwapchainImage() = 0; |
| |
| // 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(gfx::GpuFence& gpu_fence) = 0; |
| |
| // Causes the GraphicsBinding to render the currently active swapchain image. |
| virtual bool Render( |
| const scoped_refptr<viz::ContextProvider>& context_provider) = 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; |
| |
| // Sets the layers for each view in the view configuration, which are |
| // submitted back to OpenXR on xrEndFrame. This is where we specify where in |
| // the texture each view is, as well as the properties of the views. |
| void PrepareViewConfigForRender(const XrSwapchain& color_swapchain, |
| OpenXrViewConfiguration& view_config); |
| |
| // Returns whether or not the current Swapchain is actually using SharedImages |
| // or not. |
| bool IsUsingSharedImages() const; |
| |
| // Returns the previously set swapchain image size, or 0,0 if one is not set. |
| gfx::Size GetSwapchainImageSize(); |
| |
| // 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 SetSwapchainImageSize(const gfx::Size& swapchain_image_size); |
| |
| // Gets the size of the texture that is shared between our process and the |
| // renderer process. |
| gfx::Size GetTransferSize(); |
| |
| // 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 SetTransferSize(const gfx::Size& transfer_size); |
| |
| // Updates the active swapchain image size if the transfer size has changed. |
| // No-ops if there is currently no active swapchain image. |
| void UpdateActiveSwapchainImageSize(gpu::SharedImageInterface* sii); |
| |
| // 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; |
| |
| // Acquire and activate a Swapchain image from the OpenXr system. This is the |
| // swapchain image that will be in use for the next render. |
| XrResult ActivateSwapchainImage(XrSwapchain color_swapchain, |
| gpu::SharedImageInterface* sii); |
| |
| // Release the active swapchain image from the OpenXr system. This is called |
| // before calling EndFrame and will enable acquiring a new swapchain image for |
| // the next frame. |
| XrResult ReleaseActiveSwapchainImage(XrSwapchain color_swapchain); |
| |
| // Clears the list of images allocated during `EnumerateSwapchainImages` and |
| // if a context_provider is provided and the Swapchain entries have had |
| // corresponding SharedImages created via `CreateSharedImages` will also clean |
| // up those SharedImages. |
| void DestroySwapchainImages(viz::ContextProvider* context_provider); |
| |
| // Called to indicate which of Overlay and WebXR content is expected to be |
| // composited during calls to `Render`. |
| virtual void SetOverlayAndWebXrVisibility(bool overlay_visible, |
| bool webxr_visible) = 0; |
| |
| // 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; |
| |
| // Called to indicate which graphics API produced the textures submitted to |
| // OpenXR. Does not affect the API used for compositing. |
| void SetWebGPUSession(bool is_webgpu) { webgpu_session_ = is_webgpu; } |
| bool IsWebGPUSession() const { return webgpu_session_; } |
| |
| // Append any necessary data to the `layer` object to instruct the runtime to |
| // flip the layer if necessary. |
| void MaybeFlipLayer(XrCompositionLayerProjection& layer) const; |
| |
| protected: |
| explicit OpenXrGraphicsBinding( |
| const OpenXrExtensionEnumeration* extension_enum); |
| |
| // Internal helper to clear the list of images allocated during |
| // `EnumerateSwapchainImages`, since the child classes own the actual list. |
| virtual void ClearSwapchainImages() = 0; |
| |
| // Indicates whether the graphics binding expects the submitted image to need |
| // to be flipped when being submitted to the runtime. |
| virtual bool ShouldFlipSubmittedImage() const = 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() {} |
| |
| // 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(gpu::SharedImageInterface* sii) = 0; |
| |
| // Resizes the shared buffer for the given swapchain info if the transfer size |
| // has changed. |
| virtual void ResizeSharedBuffer(OpenXrSwapchainInfo& swap_chain_info, |
| gpu::SharedImageInterface* sii) = 0; |
| |
| // Used to access the active swapchain index as returned by the system. This |
| // class does not attempt to use the index in conjunction with |
| // `GetSwapChainImages` as the children may do their own mapping. However, |
| // this corresponds to the position of the corresponding texture in the array |
| // as was returned by the OpenXr system when querying for the swapchain info. |
| uint32_t active_swapchain_index() { return active_swapchain_index_; } |
| |
| // Indicates whether or not we actually have an active swapchain image (e.g. |
| // ActivateSwapchainImage has been called, but ReleaseSwapchainImage has not). |
| bool has_active_swapchain_image() { return has_active_swapchain_image_; } |
| |
| private: |
| gfx::Size swapchain_image_size_{0, 0}; |
| gfx::Size transfer_size_{0, 0}; |
| uint32_t active_swapchain_index_; |
| bool has_active_swapchain_image_ = false; |
| bool webgpu_session_ = false; |
| bool fb_composition_layer_ext_enabled_ = 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_ |