Commit a002a087 authored by Ian Vollick's avatar Ian Vollick Committed by Commit Bot

[vr] Avoid some unnecessary work in UpdateWorldSpaceTransforms

Previously, we would do the local update unconditionally. With this
change, we keep track of a dirty bit for the world space transform as
well as a baked version of the local transform so we don't need to
call cc::TransformOperations::Apply repeatedly to realize the same
results.

Some elements have special conditions for the dirtiness of their local
transform, so I have also created a ShouldUpdateWorldSpaceTransform
function so that subclasses can customize this behavior. The reticle,
for example, is always dirty.

Bug: 828684
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: I5b581a72d7caa39d47dcdc686d212879b3da3093
Reviewed-on: https://chromium-review.googlesource.com/995573Reviewed-by: default avatarTibor Goldschwendt <tiborg@chromium.org>
Commit-Queue: Ian Vollick <vollick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548075}
parent 597be546
......@@ -21,6 +21,7 @@ class Controller : public UiElement {
void set_local_transform(const gfx::Transform& transform) {
local_transform_ = transform;
set_world_space_transform_dirty();
}
class Renderer : public BaseRenderer {
......
......@@ -65,9 +65,12 @@ void Repositioner::SetEnabled(bool enabled) {
void Repositioner::Reset() {
transform_.MakeIdentity();
set_world_space_transform_dirty();
}
void Repositioner::UpdateTransform(const gfx::Transform& head_pose) {
set_world_space_transform_dirty();
gfx::Vector3dF head_up = vr::GetUpVector(head_pose);
gfx::Vector3dF head_forward = vr::GetForwardVector(head_pose);
......
......@@ -56,6 +56,7 @@ void Resizer::SetEnabled(bool enabled) {
void Resizer::Reset() {
transform_.MakeIdentity();
set_world_space_transform_dirty();
t_ = initial_t_ = kDefaultFraction;
}
......@@ -66,6 +67,7 @@ void Resizer::UpdateTransform(const gfx::Transform& head_pose) {
gfx::Tween::FloatValueBetween(t_, kMinResizerScale, kMaxResizerScale);
transform_.MakeIdentity();
transform_.Scale(scale, scale);
set_world_space_transform_dirty();
}
bool Resizer::OnBeginFrame(const base::TimeTicks& time,
......
......@@ -183,4 +183,9 @@ gfx::Transform Reticle::GetTargetLocalTransform() const {
return LocalTransform();
}
bool Reticle::ShouldUpdateWorldSpaceTransform(
bool parent_transform_changed) const {
return true;
}
} // namespace vr
......@@ -49,6 +49,8 @@ class Reticle : public UiElement {
const CameraModel& model) const final;
gfx::Transform LocalTransform() const final;
gfx::Transform GetTargetLocalTransform() const final;
bool ShouldUpdateWorldSpaceTransform(
bool parent_transform_changed) const final;
gfx::Point3F origin_;
gfx::Point3F target_;
......
......@@ -45,6 +45,7 @@ bool ScaledDepthAdjuster::OnBeginFrame(const base::TimeTicks& time,
float z = -o.z() + delta_z_;
transform_.Scale3d(z, z, z);
transform_.Translate3d(0, 0, -1);
set_world_space_transform_dirty();
return true;
}
......
......@@ -302,15 +302,29 @@ void UiElement::SetLayoutOffset(float x, float y) {
} else if (y_centering() == BOTTOM) {
y += size_.height() / 2;
}
if (x == layout_offset_.at(0).translate.x &&
y == layout_offset_.at(0).translate.y &&
!IsAnimatingProperty(LAYOUT_OFFSET)) {
return;
}
cc::TransformOperations operations = layout_offset_;
cc::TransformOperation& op = operations.at(0);
op.translate = {x, y, 0};
op.Bake();
animation_.TransitionTransformOperationsTo(last_frame_time_, LAYOUT_OFFSET,
transform_operations_, operations);
layout_offset_, operations);
}
void UiElement::SetTranslate(float x, float y, float z) {
if (x == transform_operations_.at(kTranslateIndex).translate.x &&
y == transform_operations_.at(kTranslateIndex).translate.y &&
z == transform_operations_.at(kTranslateIndex).translate.z &&
!IsAnimatingProperty(TRANSFORM)) {
return;
}
cc::TransformOperations operations = transform_operations_;
cc::TransformOperation& op = operations.at(kTranslateIndex);
op.translate = {x, y, z};
......@@ -320,16 +334,33 @@ void UiElement::SetTranslate(float x, float y, float z) {
}
void UiElement::SetRotate(float x, float y, float z, float radians) {
float degrees = gfx::RadToDeg(radians);
if (x == transform_operations_.at(kRotateIndex).rotate.axis.x &&
y == transform_operations_.at(kRotateIndex).rotate.axis.y &&
z == transform_operations_.at(kRotateIndex).rotate.axis.z &&
degrees == transform_operations_.at(kRotateIndex).rotate.angle &&
!IsAnimatingProperty(TRANSFORM)) {
return;
}
cc::TransformOperations operations = transform_operations_;
cc::TransformOperation& op = operations.at(kRotateIndex);
op.rotate.axis = {x, y, z};
op.rotate.angle = gfx::RadToDeg(radians);
op.rotate.angle = degrees;
op.Bake();
animation_.TransitionTransformOperationsTo(last_frame_time_, TRANSFORM,
transform_operations_, operations);
}
void UiElement::SetScale(float x, float y, float z) {
if (x == transform_operations_.at(kScaleIndex).scale.x &&
y == transform_operations_.at(kScaleIndex).scale.y &&
z == transform_operations_.at(kScaleIndex).scale.z &&
!IsAnimatingProperty(TRANSFORM)) {
return;
}
cc::TransformOperations operations = transform_operations_;
cc::TransformOperation& op = operations.at(kScaleIndex);
op.scale = {x, y, z};
......@@ -654,12 +685,17 @@ void UiElement::NotifyClientTransformOperationsAnimated(
} else {
NOTREACHED();
}
local_transform_ = layout_offset_.Apply() * transform_operations_.Apply();
world_space_transform_dirty_ = true;
}
void UiElement::NotifyClientSizeAnimated(const gfx::SizeF& size,
int target_property_id,
cc::KeyframeModel* keyframe_model) {
if (size_ == size)
return;
size_ = size;
world_space_transform_dirty_ = true;
}
void UiElement::SetTransitionedProperties(
......@@ -747,7 +783,10 @@ void UiElement::DoLayOutChildren() {
bounds.Inset(-left_padding_, -bottom_padding_, -right_padding_,
-top_padding_);
bounds.set_origin(bounds.CenterPoint());
local_origin_ = bounds.origin();
if (local_origin_ != bounds.origin()) {
world_space_transform_dirty_ = true;
local_origin_ = bounds.origin();
}
if (bounds.size() == GetTargetSize())
return;
......@@ -801,35 +840,40 @@ void UiElement::UpdateComputedOpacity() {
updated_visibility_this_frame_ = IsVisible() != was_visible;
}
void UiElement::UpdateWorldSpaceTransformRecursive() {
gfx::Transform transform;
transform.Translate(local_origin_.x(), local_origin_.y());
if (!size_.IsEmpty()) {
transform.Scale(size_.width(), size_.height());
}
void UiElement::UpdateWorldSpaceTransformRecursive(bool parent_changed) {
bool changed = false;
if (ShouldUpdateWorldSpaceTransform(parent_changed)) {
gfx::Transform transform;
transform.Translate(local_origin_.x(), local_origin_.y());
// Compute an inheritable transformation that can be applied to this element,
// and it's children, if applicable.
gfx::Transform inheritable = LocalTransform();
if (!size_.IsEmpty()) {
transform.Scale(size_.width(), size_.height());
}
if (parent_) {
inheritable.ConcatTransform(parent_->inheritable_transform());
// Compute an inheritable transformation that can be applied to this
// element, and it's children, if applicable.
gfx::Transform inheritable = LocalTransform();
if (parent_) {
inheritable.ConcatTransform(parent_->inheritable_transform());
}
transform.ConcatTransform(inheritable);
set_world_space_transform(transform);
set_inheritable_transform(inheritable);
changed = true;
}
transform.ConcatTransform(inheritable);
set_world_space_transform(transform);
set_inheritable_transform(inheritable);
set_update_phase(kUpdatedWorldSpaceTransform);
for (auto& child : children_) {
child->UpdateWorldSpaceTransformRecursive();
child->UpdateWorldSpaceTransformRecursive(changed);
}
OnUpdatedWorldSpaceTransform();
}
gfx::Transform UiElement::LocalTransform() const {
return layout_offset_.Apply() * transform_operations_.Apply();
return local_transform_;
}
gfx::Transform UiElement::GetTargetLocalTransform() const {
......@@ -840,4 +884,9 @@ const Sounds& UiElement::GetSounds() const {
return sounds_;
}
bool UiElement::ShouldUpdateWorldSpaceTransform(
bool parent_transform_changed) const {
return parent_transform_changed || world_space_transform_dirty_;
}
} // namespace vr
......@@ -337,6 +337,7 @@ class UiElement : public cc::AnimationTarget {
const gfx::Transform& world_space_transform() const;
void set_world_space_transform(const gfx::Transform& transform) {
world_space_transform_ = transform;
world_space_transform_dirty_ = false;
}
gfx::Transform ComputeTargetWorldSpaceTransform() const;
......@@ -413,7 +414,7 @@ class UiElement : public cc::AnimationTarget {
virtual gfx::Transform GetTargetLocalTransform() const;
void UpdateComputedOpacity();
void UpdateWorldSpaceTransformRecursive();
void UpdateWorldSpaceTransformRecursive(bool parent_changed);
std::vector<std::unique_ptr<UiElement>>& children() { return children_; }
const std::vector<std::unique_ptr<UiElement>>& children() const {
......@@ -492,6 +493,13 @@ class UiElement : public cc::AnimationTarget {
virtual const Sounds& GetSounds() const;
virtual bool ShouldUpdateWorldSpaceTransform(
bool parent_transform_changed) const;
void set_world_space_transform_dirty() {
world_space_transform_dirty_ = true;
}
EventHandlers event_handlers_;
private:
......@@ -601,12 +609,16 @@ class UiElement : public cc::AnimationTarget {
// the translation, but leave the rotation and scale in tact).
cc::TransformOperations transform_operations_;
// This is a cached version of the local transform.
gfx::Transform local_transform_;
// This is set by the parent and is combined into LocalTransform()
cc::TransformOperations layout_offset_;
// This is the combined, local to world transform. It includes
// |inheritable_transform_|, |transform_|, and anchoring adjustments.
gfx::Transform world_space_transform_;
bool world_space_transform_dirty_ = false;
UiElement* parent_ = nullptr;
std::vector<std::unique_ptr<UiElement>> children_;
......
......@@ -115,7 +115,7 @@ TEST(UiElement, IgnoringAsymmetricPadding) {
a->AddChild(std::move(b));
a->DoLayOutChildren();
a->UpdateWorldSpaceTransformRecursive();
a->UpdateWorldSpaceTransformRecursive(false);
gfx::Point3F p;
a->world_space_transform().TransformPoint(&p);
......
......@@ -128,7 +128,8 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time,
// Now that we have finalized our local values, we can safely update our
// final, baked transform.
root_element_->UpdateWorldSpaceTransformRecursive();
const bool parent_transform_changed = false;
root_element_->UpdateWorldSpaceTransformRecursive(parent_transform_changed);
}
return scene_dirty;
......
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