blob: fffc44d32279964f611577d554ff01094ba3607a [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/vr/win/vr_browser_renderer_thread_win.h"
#include "chrome/browser/vr/audio_delegate.h"
#include "chrome/browser/vr/browser_renderer.h"
#include "chrome/browser/vr/content_input_delegate.h"
#include "chrome/browser/vr/keyboard_delegate.h"
#include "chrome/browser/vr/model/location_bar_state.h"
#include "chrome/browser/vr/text_input_delegate.h"
#include "chrome/browser/vr/ui.h"
#include "chrome/browser/vr/ui_browser_interface.h"
#include "chrome/browser/vr/ui_initial_state.h"
#include "chrome/browser/vr/win/graphics_delegate_win.h"
#include "chrome/browser/vr/win/input_delegate_win.h"
#include "chrome/browser/vr/win/scheduler_delegate_win.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/gles2_lib.h"
#include "ui/gfx/geometry/quaternion.h"
namespace vr {
VRBrowserRendererThreadWin::VRBrowserRendererThreadWin()
: MaybeThread("VRBrowserRenderThread") {}
VRBrowserRendererThreadWin::~VRBrowserRendererThreadWin() {
Stop();
}
void VRBrowserRendererThreadWin::SetVRDisplayInfo(
device::mojom::VRDisplayInfoPtr display_info) {
task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VRBrowserRendererThreadWin::SetDisplayInfoOnRenderThread,
base::Unretained(this), std::move(display_info)));
}
void VRBrowserRendererThreadWin::SetLocationInfo(GURL gurl) {
task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VRBrowserRendererThreadWin::SetLocationInfoOnRenderThread,
base::Unretained(this), std::move(gurl)));
}
void VRBrowserRendererThreadWin::SetVisibleExternalPromptNotification(
ExternalPromptNotificationType prompt) {
task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VRBrowserRendererThreadWin::
SetVisibleExternalPromptNotificationOnRenderThread,
base::Unretained(this), prompt));
}
void VRBrowserRendererThreadWin::SetDisplayInfoOnRenderThread(
device::mojom::VRDisplayInfoPtr display_info) {
display_info_ = std::move(display_info);
if (graphics_)
graphics_->SetVRDisplayInfo(display_info_.Clone());
}
void VRBrowserRendererThreadWin::SetLocationInfoOnRenderThread(GURL gurl) {
// TODO(https://crbug.com/905375): Set more of this state. Only the GURL is
// currently used, so its the only thing we are setting correctly.
DCHECK(ui_) << "Must be called after StartOverlay";
LocationBarState state(gurl, security_state::SecurityLevel::SECURE,
nullptr /* vector icon */, true /* display url */,
false /* offline */);
ui_->SetLocationBarState(state);
}
void VRBrowserRendererThreadWin::
SetVisibleExternalPromptNotificationOnRenderThread(
ExternalPromptNotificationType prompt) {
bool currently_showing_ui = ShouldPauseWebXrAndDrawUI();
current_external_prompt_notification_type_ = prompt;
ui_->SetVisibleExternalPromptNotification(prompt);
bool show_ui = ShouldPauseWebXrAndDrawUI();
if (!show_ui && currently_showing_ui) {
// Draw WebXR instead of UI.
overlay_->SetOverlayAndWebXRVisibility(false, true);
} else if (!currently_showing_ui && show_ui) {
// Draw UI instead of WebXR.
overlay_->SetOverlayAndWebXRVisibility(true, false);
overlay_->RequestNextOverlayPose(base::BindOnce(
&VRBrowserRendererThreadWin::OnPose, base::Unretained(this)));
}
}
void VRBrowserRendererThreadWin::StartOverlay(
device::mojom::XRCompositorHost* compositor) {
device::mojom::ImmersiveOverlayPtrInfo overlay_info;
compositor->CreateImmersiveOverlay(mojo::MakeRequest(&overlay_info));
initializing_graphics_ = std::make_unique<GraphicsDelegateWin>();
if (!initializing_graphics_->InitializeOnMainThread()) {
return;
}
// Post a task to the thread to start an overlay.
task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VRBrowserRendererThreadWin::StartOverlayOnRenderThread,
base::Unretained(this), std::move(overlay_info)));
}
void VRBrowserRendererThreadWin::StopOverlay() {
// Post a task to the thread to stop the overlay.
task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&VRBrowserRendererThreadWin::StopOverlayOnRenderThread,
base::Unretained(this)));
}
void VRBrowserRendererThreadWin::CleanUp() {
browser_renderer_ = nullptr;
initializing_graphics_ = nullptr;
overlay_ = nullptr;
}
namespace {
// Number of frames to use for sliding averages for pose timings,
// as used for estimating prediction times.
constexpr unsigned kSlidingAverageSize = 5;
} // namespace
class VRUiBrowserInterface : public UiBrowserInterface {
public:
~VRUiBrowserInterface() override = default;
void ExitPresent() override {}
void ExitFullscreen() override {}
void Navigate(GURL gurl, NavigationMethod method) override {}
void NavigateBack() override {}
void NavigateForward() override {}
void ReloadTab() override {}
void OpenNewTab(bool incognito) override {}
void OpenBookmarks() override {}
void OpenRecentTabs() override {}
void OpenHistory() override {}
void OpenDownloads() override {}
void OpenShare() override {}
void OpenSettings() override {}
void CloseAllIncognitoTabs() override {}
void OpenFeedback() override {}
void CloseHostedDialog() override {}
void OnUnsupportedMode(UiUnsupportedMode mode) override {}
void OnExitVrPromptResult(ExitVrPromptChoice choice,
UiUnsupportedMode reason) override {}
void OnContentScreenBoundsChanged(const gfx::SizeF& bounds) override {}
void SetVoiceSearchActive(bool active) override {}
void StartAutocomplete(const AutocompleteRequest& request) override {}
void StopAutocomplete() override {}
void ShowPageInfo() override {}
};
void VRBrowserRendererThreadWin::StartOverlayOnRenderThread(
device::mojom::ImmersiveOverlayPtrInfo overlay) {
overlay_.Bind(std::move(overlay));
initializing_graphics_->InitializeOnGLThread();
initializing_graphics_->BindContext();
// Create a vr::Ui
BrowserRendererBrowserInterface* browser_renderer_interface = nullptr;
ui_browser_interface_ = std::make_unique<VRUiBrowserInterface>();
PlatformInputHandler* input = nullptr;
std::unique_ptr<KeyboardDelegate> keyboard_delegate;
std::unique_ptr<TextInputDelegate> text_input_delegate;
std::unique_ptr<AudioDelegate> audio_delegate;
UiInitialState ui_initial_state = {};
ui_initial_state.in_web_vr = true;
ui_initial_state.browsing_disabled = true;
ui_initial_state.supports_selection = false;
std::unique_ptr<Ui> ui = std::make_unique<Ui>(
ui_browser_interface_.get(), input, std::move(keyboard_delegate),
std::move(text_input_delegate), std::move(audio_delegate),
ui_initial_state);
static_cast<UiInterface*>(ui.get())->OnGlInitialized(
kGlTextureLocationLocal,
0 /* content_texture_id - we don't support content */,
0 /* content_overlay_texture_id - we don't support content overlays */,
0 /* platform_ui_texture_id - we don't support platform UI */);
ui_ = static_cast<BrowserUiInterface*>(ui.get());
ui_->SetWebVrMode(true);
// Create the delegates, and keep raw pointers to them. They are owned by
// browser_renderer_.
std::unique_ptr<SchedulerDelegateWin> scheduler_delegate =
std::make_unique<SchedulerDelegateWin>();
scheduler_ = scheduler_delegate.get();
graphics_ = initializing_graphics_.get();
graphics_->SetVRDisplayInfo(display_info_.Clone());
std::unique_ptr<InputDelegateWin> input_delegate =
std::make_unique<InputDelegateWin>();
input_ = input_delegate.get();
// Create the BrowserRenderer to drive UI rendering based on the delegates.
browser_renderer_ = std::make_unique<BrowserRenderer>(
std::move(ui), std::move(scheduler_delegate),
std::move(initializing_graphics_), std::move(input_delegate),
browser_renderer_interface, kSlidingAverageSize);
bool draw_ui = ShouldPauseWebXrAndDrawUI();
overlay_->SetOverlayAndWebXRVisibility(draw_ui, !draw_ui);
if (draw_ui) {
overlay_->RequestNextOverlayPose(base::BindOnce(
&VRBrowserRendererThreadWin::OnPose, base::Unretained(this)));
}
graphics_->ClearContext();
}
void VRBrowserRendererThreadWin::StopOverlayOnRenderThread() {
overlay_->SetOverlayAndWebXRVisibility(false, true);
CleanUp();
}
void VRBrowserRendererThreadWin::OnPose(device::mojom::XRFrameDataPtr data) {
if (!ShouldPauseWebXrAndDrawUI()) {
// We shouldn't be showing UI.
overlay_->SetOverlayAndWebXRVisibility(false, true);
graphics_->ResetMemoryBuffer();
return;
}
// Deliver pose to input and scheduler.
const std::vector<float>& quat = *data->pose->orientation;
const std::vector<float>& pos = *data->pose->position;
// The incoming pose represents where the headset is in "world space". So
// we'll need to invert to get the view transform.
// Negating the w component will invert the rotation.
gfx::Transform head_from_unoriented_head(
gfx::Quaternion(quat[0], quat[1], quat[2], -quat[3]));
// Negating all components will invert the translation.
gfx::Transform unoriented_head_from_world;
unoriented_head_from_world.Translate3d(-pos[0], -pos[1], -pos[2]);
// Compose these to get the base "view" matrix (before accounting for per-eye
// transforms).
gfx::Transform head_from_world =
head_from_unoriented_head * unoriented_head_from_world;
input_->OnPose(head_from_world);
graphics_->PreRender();
// base::Unretained is safe because scheduler_ will be destroyed without
// calling the callback if we are destroyed.
scheduler_->OnPose(base::BindOnce(&VRBrowserRendererThreadWin::SubmitFrame,
base::Unretained(this), std::move(data)),
head_from_world, ShouldPauseWebXrAndDrawUI());
}
void VRBrowserRendererThreadWin::SubmitFrame(
device::mojom::XRFrameDataPtr data) {
graphics_->PostRender();
overlay_->SubmitOverlayTexture(
data->frame_id, graphics_->GetTexture(), graphics_->GetLeft(),
graphics_->GetRight(),
base::BindOnce(&VRBrowserRendererThreadWin::SubmitResult,
base::Unretained(this)));
}
void VRBrowserRendererThreadWin::SubmitResult(bool success) {
if (!success) {
graphics_->ResetMemoryBuffer();
}
if (overlay_) {
overlay_->RequestNextOverlayPose(base::BindOnce(
&VRBrowserRendererThreadWin::OnPose, base::Unretained(this)));
}
}
bool VRBrowserRendererThreadWin::ShouldPauseWebXrAndDrawUI() {
return current_external_prompt_notification_type_ !=
ExternalPromptNotificationType::kPromptNone;
}
} // namespace vr