blob: ebfb7642e2fc0590874df59d2edac2d2ce14ef88 [file] [log] [blame]
// Copyright 2025 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/openxr_space_based_anchor_manager.h"
#include <utility>
#include <vector>
#include "base/logging.h"
#include "device/vr/openxr/openxr_util.h"
#include "device/vr/public/mojom/pose.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
#include "ui/gfx/geometry/transform.h"
namespace device {
OpenXrSpaceBasedAnchorManager::OpenXrSpaceBasedAnchorManager() = default;
OpenXrSpaceBasedAnchorManager::~OpenXrSpaceBasedAnchorManager() {
for (const auto& it : openxr_anchors_) {
xrDestroySpace(it.second);
}
}
AnchorId OpenXrSpaceBasedAnchorManager::CreateAnchor(
XrPosef pose,
XrSpace space,
XrTime predicted_display_time,
std::optional<PlaneId> plane_id) {
// Note that we have no support for plane detection, so we don't bother to try
// to parent the anchor to the given plane_id. Any such ID is likely bogus
// anyways.
XrSpace anchor_space =
CreateAnchorInternal(pose, space, predicted_display_time);
if (anchor_space == XR_NULL_HANDLE) {
return kInvalidAnchorId;
}
AnchorId anchor_id = anchor_id_generator_.GenerateNextId();
CHECK(anchor_id);
openxr_anchors_.insert({anchor_id, anchor_space});
return anchor_id;
}
void OpenXrSpaceBasedAnchorManager::DetachAnchor(AnchorId anchor_id) {
DCHECK(anchor_id);
auto it = openxr_anchors_.find(anchor_id);
if (it == openxr_anchors_.end()) {
return;
}
XrSpace anchor_space = it->second;
OnDetachAnchor(anchor_space);
xrDestroySpace(anchor_space);
openxr_anchors_.erase(it);
}
std::optional<OpenXrAnchorManager::XrLocation>
OpenXrSpaceBasedAnchorManager::GetXrLocationFromAnchor(
AnchorId anchor_id,
const gfx::Transform& anchor_id_from_new_anchor) const {
return XrLocation{GfxTransformToXrPose(anchor_id_from_new_anchor),
GetAnchorSpace(anchor_id)};
}
std::optional<OpenXrAnchorManager::XrLocation>
OpenXrSpaceBasedAnchorManager::GetXrLocationFromPlane(
PlaneId plane_id,
const gfx::Transform& plane_id_from_new_anchor) const {
// We don't support planes, so this should never be called.
return std::nullopt;
}
mojom::XRAnchorsDataPtr OpenXrSpaceBasedAnchorManager::GetCurrentAnchorsData(
XrTime predicted_display_time) {
std::vector<AnchorId> all_anchors_ids;
all_anchors_ids.reserve(openxr_anchors_.size());
std::vector<mojom::XRAnchorDataPtr> updated_anchors;
updated_anchors.reserve(openxr_anchors_.size());
absl::flat_hash_set<AnchorId> deleted_ids;
for (const auto& [anchor_id, anchor_space] : openxr_anchors_) {
all_anchors_ids.push_back(anchor_id);
auto maybe_pose = GetAnchorFromMojom(anchor_space, predicted_display_time);
if (maybe_pose.has_value()) {
updated_anchors.push_back(
mojom::XRAnchorData::New(anchor_id, maybe_pose.value()));
} else {
// Regardless of why it failed, if we still have it tracked, send it up
// this frame, but remove it for future frames.
updated_anchors.push_back(
mojom::XRAnchorData::New(anchor_id, std::nullopt));
if (maybe_pose.error() == AnchorTrackingErrorType::kPermanent) {
deleted_ids.insert(anchor_id);
}
}
}
for (const auto& id : deleted_ids) {
DetachAnchor(id);
}
DVLOG(3) << __func__ << " all_anchor_ids size: " << all_anchors_ids.size();
return mojom::XRAnchorsData::New(std::move(all_anchors_ids),
std::move(updated_anchors));
}
XrSpace OpenXrSpaceBasedAnchorManager::GetAnchorSpace(
AnchorId anchor_id) const {
DCHECK(anchor_id);
auto it = openxr_anchors_.find(anchor_id);
if (it == openxr_anchors_.end()) {
return XR_NULL_HANDLE;
}
return it->second;
}
} // namespace device