Commit 10ccacbd authored by Yash Malik's avatar Yash Malik Committed by Commit Bot

VR: Call KeyboardDelegate::OnBeginFrame every frame regardless of visibility

The gvr keyboard API requires that gvr_keyboard_advance_frame is called every
time after the keyboard is initialized. This regressed in the optimization that
doesn't call UiElement::OnBeginFrame for invisible elements.

We add a special hook to do certain thing every frame.

Bug: 831749
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_vr;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I877299165dde517fab90451788de9680700666d9
Reviewed-on: https://chromium-review.googlesource.com/1009042
Commit-Queue: Yash Malik <ymalik@chromium.org>
Reviewed-by: default avatarIan Vollick <vollick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550215}
parent fce4a6f1
...@@ -1500,6 +1500,8 @@ void VrShellGl::DrawFrame(int16_t frame_index, base::TimeTicks current_time) { ...@@ -1500,6 +1500,8 @@ void VrShellGl::DrawFrame(int16_t frame_index, base::TimeTicks current_time) {
ui_controller_update_time_.AddSample(controller_time); ui_controller_update_time_.AddSample(controller_time);
} }
ui_->scene()->CallPerFrameCallbacks();
bool textures_changed = ui_->scene()->UpdateTextures(); bool textures_changed = ui_->scene()->UpdateTextures();
// TODO(mthiesse): Determine if a visible controller is actually drawn in the // TODO(mthiesse): Determine if a visible controller is actually drawn in the
......
...@@ -164,6 +164,10 @@ TEST_F(ContentElementSceneTest, WebInputFocus) { ...@@ -164,6 +164,10 @@ TEST_F(ContentElementSceneTest, WebInputFocus) {
content->OnFocusChanged(false); content->OnFocusChanged(false);
EXPECT_TRUE(input_forwarder_->clear_focus_called()); EXPECT_TRUE(input_forwarder_->clear_focus_called());
EXPECT_TRUE(OnBeginFrame()); EXPECT_TRUE(OnBeginFrame());
// OnBeginFrame on the keyboard delegate should be called despite of
// visibility.
EXPECT_CALL(*kb_delegate, OnBeginFrame()).InSequence(in_sequence_);
scene_->CallPerFrameCallbacks();
} }
class ContentElementInputEditingTest : public UiTest { class ContentElementInputEditingTest : public UiTest {
......
...@@ -97,6 +97,16 @@ void Keyboard::OnButtonUp(const gfx::PointF& position) { ...@@ -97,6 +97,16 @@ void Keyboard::OnButtonUp(const gfx::PointF& position) {
delegate_->OnButtonUp(position); delegate_->OnButtonUp(position);
} }
void Keyboard::AdvanceKeyboardFrameIfNeeded() {
// If the update phase is not dirty, the frame will be advanced in
// OnBeginFrame. That is, we only call OnBeginFrame below when the element is
// not visible (i.e UiElement::kDirty is true).
if (!delegate_ || update_phase() != UiElement::kDirty)
return;
delegate_->OnBeginFrame();
}
bool Keyboard::OnBeginFrame(const gfx::Transform& head_pose) { bool Keyboard::OnBeginFrame(const gfx::Transform& head_pose) {
if (!delegate_) if (!delegate_)
return false; return false;
......
...@@ -19,6 +19,9 @@ class Keyboard : public UiElement { ...@@ -19,6 +19,9 @@ class Keyboard : public UiElement {
Keyboard(); Keyboard();
~Keyboard() override; ~Keyboard() override;
// The gvr keyboard requires that we advance its frame after initilization,
// for example, regardless of visibility.
void AdvanceKeyboardFrameIfNeeded();
void SetKeyboardDelegate(KeyboardDelegate* keyboard_delegate); void SetKeyboardDelegate(KeyboardDelegate* keyboard_delegate);
void OnTouchStateUpdated(bool is_touching, const gfx::PointF& touch_position); void OnTouchStateUpdated(bool is_touching, const gfx::PointF& touch_position);
void HitTest(const HitTestRequest& request, void HitTest(const HitTestRequest& request,
......
...@@ -308,7 +308,7 @@ bool UiElement::IsOrWillBeLocallyVisible() const { ...@@ -308,7 +308,7 @@ bool UiElement::IsOrWillBeLocallyVisible() const {
} }
gfx::SizeF UiElement::size() const { gfx::SizeF UiElement::size() const {
DCHECK_LE(kUpdatedSize, phase_); DCHECK_LE(kUpdatedSize, update_phase_);
return size_; return size_;
} }
...@@ -431,7 +431,7 @@ float UiElement::ComputeTargetOpacity() const { ...@@ -431,7 +431,7 @@ float UiElement::ComputeTargetOpacity() const {
} }
float UiElement::computed_opacity() const { float UiElement::computed_opacity() const {
DCHECK_LE(kUpdatedComputedOpacity, phase_) << DebugName(); DCHECK_LE(kUpdatedComputedOpacity, update_phase_) << DebugName();
return computed_opacity_; return computed_opacity_;
} }
...@@ -495,7 +495,7 @@ void UiElement::HitTest(const HitTestRequest& request, ...@@ -495,7 +495,7 @@ void UiElement::HitTest(const HitTestRequest& request,
} }
const gfx::Transform& UiElement::world_space_transform() const { const gfx::Transform& UiElement::world_space_transform() const {
DCHECK_LE(kUpdatedWorldSpaceTransform, phase_); DCHECK_LE(kUpdatedWorldSpaceTransform, update_phase_);
return world_space_transform_; return world_space_transform_;
} }
...@@ -554,21 +554,21 @@ void UiElement::DumpHierarchy(std::vector<size_t> counts, ...@@ -554,21 +554,21 @@ void UiElement::DumpHierarchy(std::vector<size_t> counts,
} }
*os << kReset; *os << kReset;
if (phase_ < kUpdatedComputedOpacity || !IsVisible()) { if (update_phase_ < kUpdatedComputedOpacity || !IsVisible()) {
*os << kBlue; *os << kBlue;
} }
*os << DebugName() << kReset << " " << kCyan << DrawPhaseToString(draw_phase_) *os << DebugName() << kReset << " " << kCyan << DrawPhaseToString(draw_phase_)
<< " " << kReset; << " " << kReset;
if (phase_ >= kUpdatedSize) { if (update_phase_ >= kUpdatedSize) {
if (size().width() != 0.0f || size().height() != 0.0f) { if (size().width() != 0.0f || size().height() != 0.0f) {
*os << kRed << "[" << size().width() << ", " << size().height() << "] " *os << kRed << "[" << size().width() << ", " << size().height() << "] "
<< kReset; << kReset;
} }
} }
if (phase_ >= kUpdatedWorldSpaceTransform) { if (update_phase_ >= kUpdatedWorldSpaceTransform) {
*os << kGreen; *os << kGreen;
DumpGeometry(os); DumpGeometry(os);
} }
...@@ -844,7 +844,7 @@ void UiElement::DoLayOutChildren() { ...@@ -844,7 +844,7 @@ void UiElement::DoLayOutChildren() {
} }
void UiElement::LayOutChildren() { void UiElement::LayOutChildren() {
DCHECK_LE(kUpdatedSize, phase_); DCHECK_LE(kUpdatedSize, update_phase_);
for (auto& child : children_) { for (auto& child : children_) {
if (!child->IsVisible()) if (!child->IsVisible())
continue; continue;
......
...@@ -430,7 +430,7 @@ class UiElement : public cc::AnimationTarget { ...@@ -430,7 +430,7 @@ class UiElement : public cc::AnimationTarget {
return children_; return children_;
} }
void set_update_phase(UpdatePhase phase) { phase_ = phase; } void set_update_phase(UpdatePhase phase) { update_phase_ = phase; }
// This is true for all elements that respect the given view model matrix. If // This is true for all elements that respect the given view model matrix. If
// this is ignored (say for head-locked elements that draw in screen space), // this is ignored (say for head-locked elements that draw in screen space),
...@@ -494,6 +494,8 @@ class UiElement : public cc::AnimationTarget { ...@@ -494,6 +494,8 @@ class UiElement : public cc::AnimationTarget {
world_space_transform_dirty_ = true; world_space_transform_dirty_ = true;
} }
UpdatePhase update_phase() const { return update_phase_; }
EventHandlers event_handlers_; EventHandlers event_handlers_;
private: private:
...@@ -634,7 +636,7 @@ class UiElement : public cc::AnimationTarget { ...@@ -634,7 +636,7 @@ class UiElement : public cc::AnimationTarget {
// TODO(crbug.com/829880): remove this once we've simplified our bindings. // TODO(crbug.com/829880): remove this once we've simplified our bindings.
bool visibility_bindings_depend_on_child_visibility_ = false; bool visibility_bindings_depend_on_child_visibility_ = false;
UpdatePhase phase_ = kClean; UpdatePhase update_phase_ = kClean;
AudioDelegate* audio_delegate_ = nullptr; AudioDelegate* audio_delegate_ = nullptr;
Sounds sounds_; Sounds sounds_;
......
...@@ -159,6 +159,12 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time, ...@@ -159,6 +159,12 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time,
return scene_dirty; return scene_dirty;
} }
void UiScene::CallPerFrameCallbacks() {
for (auto callback : per_frame_callback_) {
callback.Run();
}
}
bool UiScene::UpdateTextures() { bool UiScene::UpdateTextures() {
bool needs_redraw = false; bool needs_redraw = false;
std::vector<UiElement*> elements = GetVisibleElementsMutable(); std::vector<UiElement*> elements = GetVisibleElementsMutable();
...@@ -235,6 +241,10 @@ void UiScene::OnGlInitialized(SkiaSurfaceProvider* provider) { ...@@ -235,6 +241,10 @@ void UiScene::OnGlInitialized(SkiaSurfaceProvider* provider) {
InitializeElementRecursive(root_element_.get(), provider_); InitializeElementRecursive(root_element_.get(), provider_);
} }
void UiScene::AddPerFrameCallback(PerFrameCallback callback) {
per_frame_callback_.push_back(callback);
}
void UiScene::InitializeElement(UiElement* element) { void UiScene::InitializeElement(UiElement* element) {
CHECK_GE(element->id(), 0); CHECK_GE(element->id(), 0);
CHECK_EQ(GetUiElementById(element->id()), nullptr); CHECK_EQ(GetUiElementById(element->id()), nullptr);
......
...@@ -29,6 +29,8 @@ class UiElement; ...@@ -29,6 +29,8 @@ class UiElement;
class UiScene { class UiScene {
public: public:
typedef base::RepeatingCallback<void()> PerFrameCallback;
UiScene(); UiScene();
~UiScene(); ~UiScene();
...@@ -45,6 +47,8 @@ class UiScene { ...@@ -45,6 +47,8 @@ class UiScene {
bool OnBeginFrame(const base::TimeTicks& current_time, bool OnBeginFrame(const base::TimeTicks& current_time,
const gfx::Transform& head_pose); const gfx::Transform& head_pose);
void CallPerFrameCallbacks();
// Returns true if any textures were redrawn. // Returns true if any textures were redrawn.
bool UpdateTextures(); bool UpdateTextures();
...@@ -68,6 +72,9 @@ class UiScene { ...@@ -68,6 +72,9 @@ class UiScene {
void set_dirty() { is_dirty_ = true; } void set_dirty() { is_dirty_ = true; }
void OnGlInitialized(SkiaSurfaceProvider* provider); void OnGlInitialized(SkiaSurfaceProvider* provider);
// The callback to call on every new frame. This is used for things we want to
// do every frame regardless of element or subtree visibility.
void AddPerFrameCallback(PerFrameCallback callback);
SkiaSurfaceProvider* SurfaceProviderForTesting() { return provider_; } SkiaSurfaceProvider* SurfaceProviderForTesting() { return provider_; }
...@@ -88,6 +95,8 @@ class UiScene { ...@@ -88,6 +95,8 @@ class UiScene {
std::vector<UiElement*> all_elements_; std::vector<UiElement*> all_elements_;
std::vector<PerFrameCallback> per_frame_callback_;
SkiaSurfaceProvider* provider_ = nullptr; SkiaSurfaceProvider* provider_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(UiScene); DISALLOW_COPY_AND_ASSIGN(UiScene);
......
...@@ -1943,6 +1943,9 @@ void UiSceneCreator::CreateKeyboard() { ...@@ -1943,6 +1943,9 @@ void UiSceneCreator::CreateKeyboard() {
base::Unretained(keyboard.get())))); base::Unretained(keyboard.get()))));
VR_BIND_VISIBILITY(keyboard, VR_BIND_VISIBILITY(keyboard,
model->editing_input || model->editing_web_input); model->editing_input || model->editing_web_input);
scene_->AddPerFrameCallback(base::BindRepeating(
[](Keyboard* keyboard) { keyboard->AdvanceKeyboardFrameIfNeeded(); },
base::Unretained(keyboard.get())));
scaler->AddChild(std::move(keyboard)); scaler->AddChild(std::move(keyboard));
visibility_control_root->AddChild(std::move(scaler)); visibility_control_root->AddChild(std::move(scaler));
scene_->AddUiElement(k2dBrowsingRepositioner, scene_->AddUiElement(k2dBrowsingRepositioner,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment