blob: c07d29e1596ea91340eb2e66b59c092ca4d41378 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/vr/browser_renderer.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/time/time.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "chrome/browser/vr/render_info.h"
#include "chrome/browser/vr/ui_interface.h"
#include "chrome/browser/vr/ui_test_input.h"
namespace vr {
BrowserRenderer::BrowserRenderer(
std::unique_ptr<UiInterface> ui,
std::unique_ptr<GraphicsDelegate> graphics_delegate,
size_t sliding_time_size)
: graphics_delegate_(std::move(graphics_delegate)),
ui_processing_time_(sliding_time_size),
ui_(std::move(ui)) {}
BrowserRenderer::~BrowserRenderer() = default;
void BrowserRenderer::DrawBrowserFrame(base::TimeTicks current_time,
const gfx::Transform& head_pose) {
Draw(kUiFrame, current_time, head_pose);
}
void BrowserRenderer::DrawWebXrFrame(base::TimeTicks current_time,
const gfx::Transform& head_pose) {
Draw(kWebXrFrame, current_time, head_pose);
}
void BrowserRenderer::Draw(FrameType frame_type,
base::TimeTicks current_time,
const gfx::Transform& head_pose) {
TRACE_EVENT1("gpu", "BrowserRenderer::Draw", "frame_type", frame_type);
const auto& render_info =
graphics_delegate_->GetRenderInfo(frame_type, head_pose);
UpdateUi(render_info, current_time, frame_type);
if (frame_type == kWebXrFrame) {
if (ui_->HasWebXrOverlayElementsToDraw()) {
DrawWebXrOverlay(render_info);
}
} else {
DrawBrowserUi(render_info);
}
TRACE_COUNTER1("gpu", "VR UI timing (us)",
ui_processing_time_.GetAverage().InMicroseconds());
}
void BrowserRenderer::DrawWebXrOverlay(const RenderInfo& render_info) {
TRACE_EVENT0("gpu", "BrowserRenderer::DrawWebXrOverlay");
// Calculate optimized viewport and corresponding render info.
const auto& recommended_fovs = graphics_delegate_->GetRecommendedFovs();
const auto& fovs = ui_->GetMinimalFovForWebXrOverlayElements(
render_info.left_eye_model.view_matrix, recommended_fovs.first,
render_info.right_eye_model.view_matrix, recommended_fovs.second,
graphics_delegate_->GetZNear());
const auto& webxr_overlay_render_info =
graphics_delegate_->GetOptimizedRenderInfoForFovs(fovs);
ui_->DrawWebVrOverlayForeground(webxr_overlay_render_info);
}
void BrowserRenderer::DrawBrowserUi(const RenderInfo& render_info) {
TRACE_EVENT0("gpu", "BrowserRenderer::DrawBrowserUi");
ui_->Draw(render_info);
}
void BrowserRenderer::WatchElementForVisibilityStatusForTesting(
std::optional<UiVisibilityState> visibility_expectation) {
DCHECK(!ui_visibility_state_.has_value() ||
!visibility_expectation.has_value())
<< "Attempted to watch a UI element "
"for visibility changes with one "
"in progress";
ui_visibility_state_ = std::move(visibility_expectation);
}
void BrowserRenderer::UpdateUi(const RenderInfo& render_info,
base::TimeTicks current_time,
FrameType frame_type) {
TRACE_EVENT0("gpu", "UpdateUi");
// Update the render position of all UI elements.
base::TimeTicks timing_start = base::TimeTicks::Now();
ui_->OnBeginFrame(current_time, render_info.head_pose);
if (ui_->SceneHasDirtyTextures()) {
ui_->UpdateSceneTextures();
}
ReportElementVisibilityStatus(timing_start);
base::TimeDelta scene_time = base::TimeTicks::Now() - timing_start;
// Don't double-count the controller time that was part of the scene time.
ui_processing_time_.AddSample(scene_time);
}
void BrowserRenderer::ReportElementVisibilityStatus(
const base::TimeTicks& current_time) {
if (!ui_visibility_state_.has_value()) {
return;
}
base::TimeDelta time_since_start =
current_time - ui_visibility_state_->start_time;
if (ui_->GetElementVisibility(ui_visibility_state_->element_to_watch) ==
ui_visibility_state_->expected_visibile) {
ReportElementVisibilityResult(true); // IN-TEST
} else if (time_since_start > ui_visibility_state_->timeout_ms) {
ReportElementVisibilityResult(false); // IN-TEST
}
}
void BrowserRenderer::ReportElementVisibilityResult(bool result) {
// Grab the callback and then destroy 'ui_visibility_state_' to prevent
// re-entrant behavior being blocked by having the 'ui_visibility_state_' or
// overwriting it and then dropping our callback.
auto callback = std::move(ui_visibility_state_->on_visibility_change_result);
ui_visibility_state_ = std::nullopt;
std::move(callback).Run(result);
}
} // namespace vr