chromium/device/vr/openxr/msft/openxr_scene_msft.cc

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

#include "device/vr/openxr/msft/openxr_scene_msft.h"

#include <array>
#include <vector>

#include "base/check_op.h"
#include "device/vr/openxr/openxr_extension_helper.h"
#include "device/vr/openxr/openxr_util.h"
#include "third_party/openxr/src/include/openxr/openxr.h"

namespace device {

namespace {
// Insert an extension struct into the next chain of an xrStruct
template <typename XrStruct, typename XrExtension>
void InsertExtensionStruct(XrStruct& xrStruct, XrExtension& xrExtension) {
  xrExtension.next = xrStruct.next;
  xrStruct.next = &xrExtension;
}
}  // anonymous namespace

OpenXrSceneMsft::OpenXrSceneMsft(
    const device::OpenXrExtensionHelper& extensions,
    XrSceneObserverMSFT scene_observer)
    : extensions_(extensions),
      scene_(XR_NULL_HANDLE,
             OpenXrExtensionHandleTraits<XrSceneMSFT>(
                 extensions.ExtensionMethods().xrDestroySceneMSFT)) {
  XrSceneCreateInfoMSFT create_info{XR_TYPE_SCENE_CREATE_INFO_MSFT};
  XrResult create_scene_result =
      extensions.ExtensionMethods().xrCreateSceneMSFT(
          scene_observer, &create_info,
          OpenXrExtensionHandle<XrSceneMSFT>::Receiver(scene_).get());
  DCHECK(XR_SUCCEEDED(create_scene_result));
}
OpenXrSceneMsft::~OpenXrSceneMsft() = default;

XrResult OpenXrSceneMsft::GetPlanes(
    std::vector<OpenXrScenePlaneMsft>& out_planes) {
  XrSceneComponentsGetInfoMSFT get_info{XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT};
  get_info.componentType = XR_SCENE_COMPONENT_TYPE_PLANE_MSFT;

  static constexpr std::array<OpenXrSceneObjectMsft::Type, 6> kPlaneFilters{
      XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT, XR_SCENE_OBJECT_TYPE_WALL_MSFT,
      XR_SCENE_OBJECT_TYPE_FLOOR_MSFT,      XR_SCENE_OBJECT_TYPE_CEILING_MSFT,
      XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT,   XR_SCENE_OBJECT_TYPE_INFERRED_MSFT};

  XrSceneObjectTypesFilterInfoMSFT types_filter{
      XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT};
  types_filter.objectTypeCount = static_cast<uint32_t>(kPlaneFilters.size());
  types_filter.objectTypes = kPlaneFilters.data();
  device::InsertExtensionStruct(get_info, types_filter);

  // Before we get back the array of components/planes, we need to query
  // for the size of the array and has to do the allocation first.
  XrSceneComponentsMSFT scene_components{XR_TYPE_SCENE_COMPONENTS_MSFT};
  RETURN_IF_XR_FAILED(extensions_->ExtensionMethods().xrGetSceneComponentsMSFT(
      scene_.get(), &get_info, &scene_components));
  const uint32_t count = scene_components.componentCountOutput;

  // The output size (count) is the same for XrSceneComponentMSFT and
  // XrScenePlaneMSFT. It's a mapping 1:1 since we are getting back
  // plane-type components.
  std::vector<XrSceneComponentMSFT> components(count);
  scene_components.componentCapacityInput = components.size();
  scene_components.components = components.data();

  std::vector<XrScenePlaneMSFT> planes(count);
  XrScenePlanesMSFT scenePlanes{XR_TYPE_SCENE_PLANES_MSFT};
  scenePlanes.scenePlaneCount = planes.size();
  scenePlanes.scenePlanes = planes.data();
  device::InsertExtensionStruct(scene_components, scenePlanes);

  RETURN_IF_XR_FAILED(extensions_->ExtensionMethods().xrGetSceneComponentsMSFT(
      scene_.get(), &get_info, &scene_components));
  // The count should stay the same
  DCHECK_EQ(count, scene_components.componentCountOutput);

  out_planes.clear();
  out_planes.reserve(count);
  for (uint32_t k = 0; k < count; k++) {
    out_planes.emplace_back(components[k], planes[k]);
  }
  return XR_SUCCESS;
}

XrResult OpenXrSceneMsft::LocateObjects(
    XrSpace base_space,
    XrTime time,
    std::vector<OpenXrScenePlaneMsft>& planes) {
  std::vector<XrUuidMSFT> plane_ids;
  for (auto& plane : planes) {
    plane_ids.emplace_back(plane.id_);
  }

  XrSceneComponentsLocateInfoMSFT locate_info{
      XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT};
  locate_info.baseSpace = base_space;
  locate_info.time = time;
  locate_info.componentIdCount = static_cast<uint32_t>(plane_ids.size());
  locate_info.componentIds = static_cast<const XrUuidMSFT*>(plane_ids.data());

  std::vector<XrSceneComponentLocationMSFT> plane_locations;
  plane_locations.resize(plane_ids.size());
  XrSceneComponentLocationsMSFT component_locations{
      XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT};
  component_locations.locationCount =
      static_cast<uint32_t>(plane_locations.size());
  component_locations.locations = plane_locations.data();

  XrResult locate_result =
      extensions_->ExtensionMethods().xrLocateSceneComponentsMSFT(
          scene_.get(), &locate_info, &component_locations);

  if (XR_SUCCEEDED(locate_result)) {
    for (size_t i = 0; i < planes.size(); i++) {
      planes[i].location_ = plane_locations[i];
    }
  }

  return locate_result;
}

}  // namespace device