1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/xr/xr_frame_request_callback_collection.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_xr_frame_request_callback.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/probe/async_task_context.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/modules/xr/xr_frame.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
XRFrameRequestCallbackCollection::XRFrameRequestCallbackCollection(
ExecutionContext* context)
: context_(context) {}
XRFrameRequestCallbackCollection::CallbackId
XRFrameRequestCallbackCollection::RegisterCallback(
V8XRFrameRequestCallback* callback) {
CallbackId id = ++next_callback_id_;
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("xr", "frameRequest",
TRACE_ID_LOCAL(trace_id_base_ + id));
auto add_result_frame_request = callback_frame_requests_.Set(id, callback);
auto add_result_async_task = callback_async_tasks_.Set(
id, std::make_unique<probe::AsyncTaskContext>());
DCHECK_EQ(add_result_frame_request.is_new_entry,
add_result_async_task.is_new_entry);
pending_callbacks_.push_back(id);
add_result_async_task.stored_value->value->Schedule(context_,
"XRRequestFrame");
probe::BreakableLocation(context_, "XRRequestFrame");
return id;
}
void XRFrameRequestCallbackCollection::CancelCallback(CallbackId id) {
if (IsValidCallbackId(id)) {
TRACE_EVENT_NESTABLE_ASYNC_END1("xr", "frameRequest",
TRACE_ID_LOCAL(trace_id_base_ + id),
"Cancelled", true);
callback_frame_requests_.erase(id);
callback_async_tasks_.erase(id);
current_callback_frame_requests_.erase(id);
// We intentionally do not erase from `current_callback_async_tasks_` here.
// If we are not actively processing a set of callbacks these will be empty.
// If we *are* actively processing callbacks, we cannot erase the task of
// the current callback, and these tasks will get cleaned up once the
// callbacks are finished processing. Removing the id from
// `current_callback_frame_requests_` is enough to ensure that the callback
// is not run.
}
}
void XRFrameRequestCallbackCollection::ExecuteCallbacks(XRSession* session,
double timestamp,
XRFrame* frame) {
TRACE_EVENT1("xr", "ExecuteRAFCallbacks", "session trace id",
session->GetTraceId());
// First, generate a list of callbacks to consider. Callbacks registered from
// this point on are considered only for the "next" frame, not this one.
// Conceptually we are just going to iterate through current_callbacks_, and
// call each callback. However, if we had multiple callbacks, subsequent ones
// could be removed while we are iterating. HeapHashMap iterators aren't
// valid after collection modifications, so we also store a corresponding set
// of ids for iteration purposes. current_callback_ids is the set of ids for
// callbacks we will call, and is kept in sync with current_callbacks_ but
// safe to iterate over.
DCHECK(current_callback_frame_requests_.empty());
DCHECK(current_callback_async_tasks_.empty());
current_callback_frame_requests_.swap(callback_frame_requests_);
current_callback_async_tasks_.swap(callback_async_tasks_);
Vector<CallbackId> current_callback_ids;
current_callback_ids.swap(pending_callbacks_);
for (const auto& id : current_callback_ids) {
auto it_frame_request = current_callback_frame_requests_.find(id);
auto it_async_task = current_callback_async_tasks_.find(id);
if (it_frame_request == current_callback_frame_requests_.end()) {
continue;
}
CHECK_NE(current_callback_async_tasks_.end(), it_async_task);
TRACE_EVENT_NESTABLE_ASYNC_END0("xr", "frameRequest",
TRACE_ID_LOCAL(trace_id_base_ + id));
probe::AsyncTask async_task(context_, it_async_task->value.get());
it_frame_request->value->InvokeAndReportException(session, timestamp,
frame);
}
current_callback_frame_requests_.clear();
current_callback_async_tasks_.clear();
}
void XRFrameRequestCallbackCollection::Trace(Visitor* visitor) const {
visitor->Trace(callback_frame_requests_);
visitor->Trace(current_callback_frame_requests_);
visitor->Trace(context_);
}
} // namespace blink
|