vrwm: Add support for multiple independent displays
This doesn't change much, just splits ShellView and shuffles code
around.
Display-related things go into DisplayView - everything related to
processing and drawing buffers, hit detection, visibility.
ShellView retains overall state management, touchpad, controller and
is the initial recipient of all incoming frames
The composer library is modified to accept and pass multiple displays
Bug: 35996499
Test: Works for the existing single-display output
Change-Id: Ied5061b4dad9e7d68bb187bf86c3d0f2f3b7a55e
diff --git a/services/vr/vr_window_manager/Android.mk b/services/vr/vr_window_manager/Android.mk
index ddb58e9..59ef63c 100644
--- a/services/vr/vr_window_manager/Android.mk
+++ b/services/vr/vr_window_manager/Android.mk
@@ -17,6 +17,7 @@
native_src := \
application.cpp \
controller_mesh.cpp \
+ display_view.cpp \
elbow_model.cpp \
hwc_callback.cpp \
reticle.cpp \
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index dba797f..eb9f407 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -224,6 +224,8 @@
DrawEye(kRightEye, fov_[kRightEye].GetProjectionMatrix(0.1f, 500.0f),
eye_from_head_[kRightEye], head_matrix);
+ OnEndFrame();
+
dvrPresent(graphics_context_);
}
}
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index 2c60e0a..6215561 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -57,6 +57,7 @@
virtual void OnDrawFrame() = 0;
virtual void DrawEye(EyeType eye, const mat4& perspective,
const mat4& eye_matrix, const mat4& head_matrix) = 0;
+ virtual void OnEndFrame() = 0;
void SetVisibility(bool visible);
virtual void OnVisibilityChanged(bool visible);
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index bd801f0..8b50c01 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -102,7 +102,8 @@
HwcLayer* HwcDisplay::GetLayer(Layer id) {
for (size_t i = 0; i < layers_.size(); ++i)
- if (layers_[i].info.id == id) return &layers_[i];
+ if (layers_[i].info.id == id)
+ return &layers_[i];
return nullptr;
}
@@ -219,7 +220,7 @@
////////////////////////////////////////////////////////////////////////////////
// VrHwcClient
-VrHwc::VrHwc() {}
+VrHwc::VrHwc() { displays_[kDefaultDisplayId].reset(new HwcDisplay()); }
VrHwc::~VrHwc() {}
@@ -231,7 +232,6 @@
}
void VrHwc::enableCallback(bool enable) {
- std::lock_guard<std::mutex> guard(mutex_);
if (enable && client_ != nullptr) {
client_.promote()->onHotplug(kDefaultDisplayId,
IComposerCallback::Connection::CONNECTED);
@@ -247,31 +247,43 @@
return Error::NONE;
}
-Error VrHwc::destroyVirtualDisplay(Display display) { return Error::NONE; }
+Error VrHwc::destroyVirtualDisplay(Display display) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (display == kDefaultDisplayId || displays_.erase(display) == 0)
+ return Error::BAD_DISPLAY;
+ ComposerView::Frame frame;
+ frame.display_id = display;
+ frame.removed = true;
+ if (observer_)
+ observer_->OnNewFrame(frame);
+ return Error::NONE;
+}
Error VrHwc::createLayer(Display display, Layer* outLayer) {
- if (display != kDefaultDisplayId) {
- return Error::BAD_DISPLAY;
- }
-
std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* layer = display_.CreateLayer();
+ HwcLayer* layer = display_ptr->CreateLayer();
*outLayer = layer->info.id;
return Error::NONE;
}
Error VrHwc::destroyLayer(Display display, Layer layer) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr) {
+ return Error::BAD_DISPLAY;
+ }
- return display_.DestroyLayer(layer) ? Error::NONE : Error::BAD_LAYER;
+ return display_ptr->DestroyLayer(layer) ? Error::NONE : Error::BAD_LAYER;
}
Error VrHwc::getActiveConfig(Display display, Config* outConfig) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
*outConfig = kDefaultConfigId;
return Error::NONE;
}
@@ -291,10 +303,9 @@
Error VrHwc::getDisplayAttribute(Display display, Config config,
IComposerClient::Attribute attribute,
int32_t* outValue) {
- if (display != kDefaultDisplayId) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
return Error::BAD_DISPLAY;
- }
-
if (config != kDefaultConfigId) {
return Error::BAD_CONFIG;
}
@@ -321,10 +332,9 @@
}
Error VrHwc::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
- if (display != kDefaultDisplayId) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
return Error::BAD_DISPLAY;
- }
-
std::vector<Config> configs(1, kDefaultConfigId);
*outConfigs = hidl_vec<Config>(configs);
return Error::NONE;
@@ -337,7 +347,9 @@
Error VrHwc::getDisplayType(Display display,
IComposerClient::DisplayType* outType) {
- if (display != kDefaultDisplayId) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr) {
*outType = IComposerClient::DisplayType::INVALID;
return Error::BAD_DISPLAY;
}
@@ -348,10 +360,10 @@
Error VrHwc::getDozeSupport(Display display, bool* outSupport) {
*outSupport = false;
- if (display == kDefaultDisplayId)
- return Error::NONE;
- else
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
return Error::BAD_DISPLAY;
+ return Error::NONE;
}
Error VrHwc::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
@@ -365,35 +377,41 @@
}
Error VrHwc::setActiveConfig(Display display, Config config) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
- if (config != kDefaultConfigId) return Error::BAD_CONFIG;
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
+ if (config != kDefaultConfigId)
+ return Error::BAD_CONFIG;
return Error::NONE;
}
Error VrHwc::setColorMode(Display display, ColorMode mode) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setPowerMode(Display display, IComposerClient::PowerMode mode) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setColorTransform(Display display, const float* matrix,
int32_t hint) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
@@ -401,13 +419,15 @@
int32_t acquireFence, int32_t dataspace,
const std::vector<hwc_rect_t>& damage) {
base::unique_fd fence(acquireFence);
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
- if (target == nullptr) return Error::NONE;
-
std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- if (!display_.SetClientTarget(target, std::move(fence)))
+ if (target == nullptr)
+ return Error::NONE;
+
+ if (!display_ptr->SetClientTarget(target, std::move(fence)))
return Error::BAD_PARAMETER;
return Error::NONE;
@@ -416,7 +436,10 @@
Error VrHwc::setOutputBuffer(Display display, buffer_handle_t buffer,
int32_t releaseFence) {
base::unique_fd fence(releaseFence);
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
ALOGE("Virtual display support not implemented");
return Error::UNSUPPORTED;
@@ -427,13 +450,13 @@
std::vector<IComposerClient::Composition>* outCompositionTypes,
uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
std::vector<uint32_t>* outRequestMasks) {
- if (display != kDefaultDisplayId) {
- return Error::BAD_DISPLAY;
- }
-
std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- display_.GetChangedCompositionTypes(outChangedLayers, outCompositionTypes);
+ display_ptr->GetChangedCompositionTypes(outChangedLayers,
+ outCompositionTypes);
return Error::NONE;
}
@@ -446,18 +469,20 @@
outLayers->clear();
outReleaseFences->clear();
- if (display != kDefaultDisplayId) {
- return Error::BAD_DISPLAY;
- }
-
- std::vector<ComposerView::ComposerLayer> frame;
- std::vector<Layer> last_frame_layers;
std::lock_guard<std::mutex> guard(mutex_);
- Error status = display_.GetFrame(&frame);
+ auto display_ptr = FindDisplay(display);
+
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
+
+ ComposerView::Frame frame;
+ std::vector<Layer> last_frame_layers;
+ Error status = display_ptr->GetFrame(&frame.layers);
+ frame.display_id = display;
if (status != Error::NONE)
return status;
- last_frame_layers = display_.UpdateLastFrameAndGetLastFrameLayers();
+ last_frame_layers = display_ptr->UpdateLastFrameAndGetLastFrameLayers();
base::unique_fd fence;
if (observer_)
@@ -476,18 +501,23 @@
Error VrHwc::setLayerCursorPosition(Display display, Layer layer, int32_t x,
int32_t y) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerBuffer(Display display, Layer layer,
buffer_handle_t buffer, int32_t acquireFence) {
base::unique_fd fence(acquireFence);
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.buffer = GetBufferFromHandle(buffer);
hwc_layer->info.fence = new Fence(fence.release());
@@ -497,16 +527,21 @@
Error VrHwc::setLayerSurfaceDamage(Display display, Layer layer,
const std::vector<hwc_rect_t>& damage) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerBlendMode(Display display, Layer layer, int32_t mode) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.blend_mode =
static_cast<ComposerView::ComposerLayer::BlendMode>(mode);
@@ -516,17 +551,22 @@
Error VrHwc::setLayerColor(Display display, Layer layer,
IComposerClient::Color color) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerCompositionType(Display display, Layer layer,
int32_t type) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->composition_type = static_cast<HwcLayer::Composition>(type);
@@ -535,17 +575,22 @@
Error VrHwc::setLayerDataspace(Display display, Layer layer,
int32_t dataspace) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerDisplayFrame(Display display, Layer layer,
const hwc_rect_t& frame) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.display_frame =
{frame.left, frame.top, frame.right, frame.bottom};
@@ -554,10 +599,14 @@
}
Error VrHwc::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.alpha = alpha;
@@ -566,17 +615,22 @@
Error VrHwc::setLayerSidebandStream(Display display, Layer layer,
buffer_handle_t stream) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerSourceCrop(Display display, Layer layer,
const hwc_frect_t& crop) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.crop = {crop.left, crop.top, crop.right, crop.bottom};
@@ -585,23 +639,29 @@
Error VrHwc::setLayerTransform(Display display, Layer layer,
int32_t transform) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerVisibleRegion(Display display, Layer layer,
const std::vector<hwc_rect_t>& visible) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
-
+ std::lock_guard<std::mutex> guard(mutex_);
+ if (!FindDisplay(display))
+ return Error::BAD_DISPLAY;
return Error::NONE;
}
Error VrHwc::setLayerZOrder(Display display, Layer layer, uint32_t z) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->z_order = z;
@@ -610,10 +670,14 @@
Error VrHwc::setLayerInfo(Display display, Layer layer, uint32_t type,
uint32_t appId) {
- if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
- HwcLayer* hwc_layer = display_.GetLayer(layer);
- if (!hwc_layer) return Error::BAD_LAYER;
+ HwcLayer* hwc_layer = display_ptr->GetLayer(layer);
+ if (!hwc_layer)
+ return Error::BAD_LAYER;
hwc_layer->info.type = type;
hwc_layer->info.app_id = appId;
@@ -665,6 +729,11 @@
observer_ = nullptr;
}
+HwcDisplay* VrHwc::FindDisplay(Display display) {
+ auto iter = displays_.find(display);
+ return iter == displays_.end() ? nullptr : iter->second.get();
+}
+
ComposerView* GetComposerViewFromIComposer(
hardware::graphics::composer::V2_1::IComposer* composer) {
return static_cast<VrHwc*>(composer);
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index df09687..b869d3e 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -24,6 +24,7 @@
#include <utils/StrongPointer.h>
#include <mutex>
+#include <unordered_map>
using namespace android::hardware::graphics::common::V1_0;
using namespace android::hardware::graphics::composer::V2_1;
@@ -67,7 +68,14 @@
uint32_t app_id;
};
- using Frame = std::vector<ComposerLayer>;
+ struct Frame {
+ Display display_id;
+ // This is set to true to notify the upper layer that the display is
+ // being removed, or left false in the case of a normal frame. The upper
+ // layer tracks display IDs and will handle new ones showing up.
+ bool removed = false;
+ std::vector<ComposerLayer> layers;
+ };
class Observer {
public:
@@ -231,13 +239,15 @@
void UnregisterObserver(Observer* observer) override;
private:
+ HwcDisplay* FindDisplay(Display display);
+
wp<VrComposerClient> client_;
sp<IComposerCallback> callbacks_;
// Guard access to internal state from binder threads.
std::mutex mutex_;
- HwcDisplay display_;
+ std::unordered_map<Display, std::unique_ptr<HwcDisplay>> displays_;
Observer* observer_ = nullptr;
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
new file mode 100644
index 0000000..5f1e73e
--- /dev/null
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -0,0 +1,432 @@
+#include "display_view.h"
+
+#include "texture.h"
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+constexpr float kLayerScaleFactor = 3.0f;
+constexpr unsigned int kVRAppLayerCount = 2;
+constexpr unsigned int kMaximumPendingFrames = 8;
+
+// clang-format off
+const GLfloat kVertices[] = {
+ -1, -1, 0,
+ 1, -1, 0,
+ -1, 1, 0,
+ 1, 1, 0,
+};
+
+const GLfloat kTextureVertices[] = {
+ 0, 1,
+ 1, 1,
+ 0, 0,
+ 1, 0,
+};
+// clang-format on
+
+// Returns true if the given point is inside the given rect.
+bool IsInside(const vec2& pt, const vec2& tl, const vec2& br) {
+ return pt.x() >= tl.x() && pt.x() <= br.x() && pt.y() >= tl.y() &&
+ pt.y() <= br.y();
+}
+
+mat4 GetScalingMatrix(float width, float height) {
+ float xscale = 1, yscale = 1;
+ float ar = width / height;
+ if (ar > 1)
+ yscale = 1.0 / ar;
+ else
+ xscale = ar;
+
+ xscale *= kLayerScaleFactor;
+ yscale *= kLayerScaleFactor;
+
+ return mat4(Eigen::Scaling<float>(xscale, yscale, 1.0));
+}
+
+// Helper function that applies the crop transform to the texture layer and
+// positions (and scales) the texture layer in the appropriate location in the
+// display space.
+mat4 GetLayerTransform(const TextureLayer& texture_layer, float display_width,
+ float display_height) {
+ // Map from vertex coordinates to [0, 1] coordinates:
+ // 1) Flip y since in vertex coordinates (-1, -1) is at the bottom left and
+ // in texture coordinates (0, 0) is at the top left.
+ // 2) Translate by (1, 1) to map vertex coordinates to [0, 2] on x and y.
+ // 3) Scale by 1 / 2 to map coordinates to [0, 1] on x and y.
+ mat4 unit_space(Eigen::AlignedScaling3f(0.5f, 0.5f, 1.0f) *
+ Eigen::Translation3f(1.0f, 1.0f, 0.0f) *
+ Eigen::AlignedScaling3f(1.0f, -1.0f, 1.0f));
+
+ mat4 texture_space(Eigen::AlignedScaling3f(
+ texture_layer.texture->width(), texture_layer.texture->height(), 1.0f));
+
+ // 1) Translate the layer to crop the left and top edge.
+ // 2) Scale the layer such that the cropped right and bottom edges map outside
+ // the exture region.
+ float crop_width = texture_layer.crop.right - texture_layer.crop.left;
+ float crop_height = texture_layer.crop.bottom - texture_layer.crop.top;
+ mat4 texture_crop(Eigen::AlignedScaling3f(
+ texture_layer.texture->width() / crop_width,
+ texture_layer.texture->height() / crop_height, 1.0f) *
+ Eigen::Translation3f(-texture_layer.crop.left,
+ -texture_layer.crop.top, 0.0f));
+
+ mat4 display_space(
+ Eigen::AlignedScaling3f(display_width, display_height, 1.0f));
+
+ // 1) Scale the texture to fit the display frame.
+ // 2) Translate the texture in the display frame location.
+ float display_frame_width =
+ texture_layer.display_frame.right - texture_layer.display_frame.left;
+ float display_frame_height =
+ texture_layer.display_frame.bottom - texture_layer.display_frame.top;
+ mat4 display_frame(
+ Eigen::Translation3f(texture_layer.display_frame.left,
+ texture_layer.display_frame.top, 0.0f) *
+ Eigen::AlignedScaling3f(display_frame_width / display_width,
+ display_frame_height / display_height, 1.0f));
+
+ mat4 layer_transform = unit_space.inverse() * display_space.inverse() *
+ display_frame * display_space *
+ texture_space.inverse() * texture_crop *
+ texture_space * unit_space;
+ return layer_transform;
+}
+
+// Determine if ths frame should be shown or hidden.
+ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
+ uint32_t vr_app) {
+ auto& layers = frame.layers();
+
+ // TODO(achaulk): Figure out how to identify the current VR app for 2D app
+ // detection.
+
+ size_t index;
+ // Skip all layers that we don't know about.
+ for (index = 0; index < layers.size(); index++) {
+ if (layers[index].type != 0xFFFFFFFF && layers[index].type != 0)
+ break;
+ }
+
+ if (index == layers.size())
+ return ViewMode::Hidden;
+
+ if (layers[index].type != 1) {
+ // We don't have a VR app layer? Abort.
+ return ViewMode::Hidden;
+ }
+
+ // This is the VR app, ignore it.
+ index++;
+
+ // Now, find a dim layer if it exists.
+ // If it does, ignore any layers behind it for visibility determination.
+ for (size_t i = index; i < layers.size(); i++) {
+ if (layers[i].appid == HwcCallback::HwcLayer::kSurfaceFlingerLayer) {
+ index = i + 1;
+ }
+ }
+
+ // If any non-skipped layers exist now then we show, otherwise hide.
+ for (size_t i = index; i < layers.size(); i++) {
+ if (!layers[i].should_skip_layer())
+ return ViewMode::VR;
+ }
+ return ViewMode::Hidden;
+}
+
+} // namespace
+
+DisplayView::DisplayView(uint32_t id, int touchpad_id)
+ : id_(id), touchpad_id_(touchpad_id) {
+ translate_ = Eigen::Translation3f(0, 0, -2.5f);
+ ime_translate_ = mat4(Eigen::Translation3f(0.0f, -0.5f, 0.25f));
+ ime_top_left_ = vec2(0, 0);
+ ime_size_ = vec2(0, 0);
+}
+
+DisplayView::~DisplayView() {}
+
+void DisplayView::Recenter(const mat4& initial) {
+ initial_head_matrix_ = initial;
+}
+
+void DisplayView::SetPrograms(ShaderProgram* program,
+ ShaderProgram* overlay_program) {
+ program_ = program;
+ overlay_program_ = overlay_program;
+}
+
+void DisplayView::DrawEye(EyeType /* eye */, const mat4& perspective,
+ const mat4& eye_matrix, const mat4& head_matrix,
+ const vec2& size, float fade_value) {
+ size_ = size;
+ scale_ = GetScalingMatrix(size_.x(), size_.y());
+
+ DrawOverlays(perspective, eye_matrix, head_matrix, fade_value);
+}
+
+void DisplayView::AdvanceFrame() {
+ if (!pending_frames_.empty()) {
+ // Check if we should advance the frame.
+ auto& frame = pending_frames_.front();
+ if (frame.visibility == ViewMode::Hidden ||
+ frame.frame->Finish() == HwcCallback::FrameStatus::kFinished) {
+ current_frame_ = std::move(frame);
+ pending_frames_.pop_front();
+ }
+ }
+}
+
+void DisplayView::OnDrawFrame(SurfaceFlingerView* surface_flinger_view,
+ bool debug_mode) {
+ textures_.clear();
+ has_ime_ = false;
+
+ if (!visible())
+ return;
+
+ surface_flinger_view->GetTextures(*current_frame_.frame.get(), &textures_,
+ &ime_texture_, debug_mode,
+ current_frame_.visibility == ViewMode::VR);
+ has_ime_ = ime_texture_.texture != nullptr;
+}
+
+base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
+ bool debug_mode, bool* showing) {
+ ViewMode visibility =
+ CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
+
+ if (visibility == ViewMode::Hidden && debug_mode)
+ visibility = ViewMode::VR;
+
+ if (frame->layers().empty())
+ current_vr_app_ = 0;
+ else
+ current_vr_app_ = frame->layers().front().appid;
+
+ pending_frames_.emplace_back(std::move(frame), visibility);
+
+ if (pending_frames_.size() > kMaximumPendingFrames) {
+ pending_frames_.pop_front();
+ }
+
+ if (visibility == ViewMode::Hidden &&
+ current_frame_.visibility == ViewMode::Hidden) {
+ // Consume all frames while hidden.
+ while (!pending_frames_.empty())
+ AdvanceFrame();
+ }
+
+ // If we are showing ourselves the main thread is not processing anything,
+ // so give it a kick.
+ if (visibility != ViewMode::Hidden &&
+ current_frame_.visibility == ViewMode::Hidden) {
+ *showing = true;
+ }
+
+ return base::unique_fd(dup(release_fence_.get()));
+}
+
+bool DisplayView::IsHit(const vec3& view_location, const vec3& view_direction,
+ vec3* hit_location, vec2* hit_location_in_window_coord,
+ bool test_ime) {
+ mat4 m = initial_head_matrix_ * translate_;
+ if (test_ime)
+ m = m * ime_translate_;
+ mat4 inverse = (m * scale_).inverse();
+ vec4 transformed_loc =
+ inverse * vec4(view_location[0], view_location[1], view_location[2], 1);
+ vec4 transformed_dir = inverse * vec4(view_direction[0], view_direction[1],
+ view_direction[2], 0);
+
+ if (transformed_dir.z() >= 0 || transformed_loc.z() <= 0)
+ return false;
+
+ float distance = -transformed_loc.z() / transformed_dir.z();
+ vec4 transformed_hit_loc = transformed_loc + transformed_dir * distance;
+ if (transformed_hit_loc.x() < -1 || transformed_hit_loc.x() > 1)
+ return false;
+ if (transformed_hit_loc.y() < -1 || transformed_hit_loc.y() > 1)
+ return false;
+
+ hit_location_in_window_coord->x() =
+ (1 + transformed_hit_loc.x()) / 2 * size_.x();
+ hit_location_in_window_coord->y() =
+ (1 - transformed_hit_loc.y()) / 2 * size_.y();
+
+ *hit_location = view_location + view_direction * distance;
+ return true;
+}
+
+void DisplayView::DrawOverlays(const mat4& perspective, const mat4& eye_matrix,
+ const mat4& head_matrix, float fade_value) {
+ if (textures_.empty())
+ return;
+
+ program_->Use();
+ mat4 mvp = perspective * eye_matrix * head_matrix;
+ GLint view_projection_location =
+ glGetUniformLocation(program_->GetProgram(), "uViewProjection");
+ glUniformMatrix4fv(view_projection_location, 1, 0, mvp.data());
+
+ GLint alpha_location = glGetUniformLocation(program_->GetProgram(), "uAlpha");
+
+ GLint tex_location = glGetUniformLocation(program_->GetProgram(), "tex");
+ glUniform1i(tex_location, 0);
+ glActiveTexture(GL_TEXTURE0);
+
+ for (const auto& texture_layer : textures_) {
+ switch (texture_layer.blending) {
+ case HWC2_BLEND_MODE_PREMULTIPLIED:
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ break;
+ case HWC2_BLEND_MODE_COVERAGE:
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ break;
+ default:
+ break;
+ }
+
+ glUniform1f(alpha_location, fade_value * texture_layer.alpha);
+
+ glBindTexture(GL_TEXTURE_2D, texture_layer.texture->id());
+
+ mat4 layer_transform =
+ GetLayerTransform(texture_layer, size_.x(), size_.y());
+
+ mat4 transform =
+ initial_head_matrix_ * translate_ * scale_ * layer_transform;
+ DrawWithTransform(transform, *program_);
+
+ glDisable(GL_BLEND);
+ }
+
+ if (has_ime_) {
+ ime_top_left_ = vec2(static_cast<float>(ime_texture_.display_frame.left),
+ static_cast<float>(ime_texture_.display_frame.top));
+ ime_size_ = vec2(static_cast<float>(ime_texture_.display_frame.right -
+ ime_texture_.display_frame.left),
+ static_cast<float>(ime_texture_.display_frame.bottom -
+ ime_texture_.display_frame.top));
+
+ DrawDimOverlay(mvp, textures_[0], ime_top_left_, ime_top_left_ + ime_size_);
+
+ DrawIme();
+ }
+}
+
+void DisplayView::UpdateReleaseFence() {
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ EGLSyncKHR sync =
+ eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync != EGL_NO_SYNC_KHR) {
+ // Need to flush in order to get the fence FD.
+ glFlush();
+ base::unique_fd fence(eglDupNativeFenceFDANDROID(display, sync));
+ eglDestroySyncKHR(display, sync);
+ release_fence_ = std::move(fence);
+ } else {
+ ALOGE("Failed to create sync fence");
+ release_fence_ = base::unique_fd();
+ }
+}
+
+void DisplayView::DrawIme() {
+ program_->Use();
+ glBindTexture(GL_TEXTURE_2D, ime_texture_.texture->id());
+
+ mat4 layer_transform = GetLayerTransform(ime_texture_, size_.x(), size_.y());
+
+ mat4 transform = initial_head_matrix_ * translate_ * ime_translate_ * scale_ *
+ layer_transform;
+
+ DrawWithTransform(transform, *program_);
+}
+
+void DisplayView::DrawDimOverlay(const mat4& mvp, const TextureLayer& layer,
+ const vec2& top_left,
+ const vec2& bottom_right) {
+ overlay_program_->Use();
+ glUniformMatrix4fv(
+ glGetUniformLocation(overlay_program_->GetProgram(), "uViewProjection"),
+ 1, 0, mvp.data());
+ glUniform4f(glGetUniformLocation(overlay_program_->GetProgram(), "uCoords"),
+ top_left.x() / size_.x(), top_left.y() / size_.y(),
+ bottom_right.x() / size_.x(), bottom_right.y() / size_.y());
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ mat4 layer_transform = GetLayerTransform(layer, size_.x(), size_.y());
+
+ mat4 transform = initial_head_matrix_ * translate_ * scale_ * layer_transform;
+ DrawWithTransform(transform, *overlay_program_);
+ glDisable(GL_BLEND);
+}
+
+void DisplayView::DrawWithTransform(const mat4& transform,
+ const ShaderProgram& program) {
+ GLint transform_location =
+ glGetUniformLocation(program.GetProgram(), "uTransform");
+ glUniformMatrix4fv(transform_location, 1, 0, transform.data());
+
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, kVertices);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, kTextureVertices);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+}
+
+bool DisplayView::UpdateHitInfo(const vec3& view_location,
+ const vec3& view_direction,
+ vec3* hit_location) {
+ bool is_hit = false;
+ if (has_ime_) {
+ // This will set allow_input_ and hit_location_in_window_coord_.
+ is_hit = IsImeHit(view_location, view_direction, hit_location);
+ } else {
+ is_hit = IsHit(view_location, view_direction, hit_location,
+ &hit_location_in_window_coord_, false);
+ allow_input_ = is_hit;
+ }
+ return is_hit;
+}
+
+bool DisplayView::IsImeHit(const vec3& view_location,
+ const vec3& view_direction, vec3* hit_location) {
+ // First, check if the IME window is hit.
+ bool is_hit = IsHit(view_location, view_direction, hit_location,
+ &hit_location_in_window_coord_, true);
+ if (is_hit) {
+ // If it is, check if the window coordinate is in the IME region;
+ // if so then we are done.
+ if (IsInside(hit_location_in_window_coord_, ime_top_left_,
+ ime_top_left_ + ime_size_)) {
+ allow_input_ = true;
+ return true;
+ }
+ }
+
+ allow_input_ = false;
+ // Check if we have hit the main window.
+ is_hit = IsHit(view_location, view_direction, hit_location,
+ &hit_location_in_window_coord_, false);
+ if (is_hit) {
+ // Only allow input if we are not hitting the region hidden by the IME.
+ // Allowing input here would cause clicks on the main window to actually
+ // be clicks on the IME.
+ if (!IsInside(hit_location_in_window_coord_, ime_top_left_,
+ ime_top_left_ + ime_size_)) {
+ allow_input_ = true;
+ }
+ }
+ return is_hit;
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h
new file mode 100644
index 0000000..0a27781
--- /dev/null
+++ b/services/vr/vr_window_manager/display_view.h
@@ -0,0 +1,107 @@
+#ifndef VR_WINDOW_MANAGER_DISPLAY_VIEW_H_
+#define VR_WINDOW_MANAGER_DISPLAY_VIEW_H_
+
+#include <private/dvr/graphics/mesh.h>
+#include <private/dvr/graphics/shader_program.h>
+
+#include "hwc_callback.h"
+#include "surface_flinger_view.h"
+
+namespace android {
+namespace dvr {
+
+enum class ViewMode {
+ Hidden,
+ VR,
+ App,
+};
+
+class DisplayView {
+ public:
+ DisplayView(uint32_t id, int touchpad_id);
+ ~DisplayView();
+
+ // Calls to these 3 functions must be synchronized.
+ base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
+ bool debug_mode, bool* showing);
+ void AdvanceFrame();
+ void UpdateReleaseFence();
+
+ void OnDrawFrame(SurfaceFlingerView* surface_flinger_view, bool debug_mode);
+ void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
+ const mat4& head_matrix, const vec2& size, float fade_value);
+
+ void Recenter(const mat4& initial);
+
+ bool UpdateHitInfo(const vec3& view_location, const vec3& view_direction,
+ vec3* hit_location);
+
+ void SetPrograms(ShaderProgram* program, ShaderProgram* overlay_program);
+
+ bool visible() const { return current_frame_.visibility != ViewMode::Hidden; }
+ bool allow_input() const { return allow_input_; }
+ const vec2& hit_location() const { return hit_location_in_window_coord_; }
+ uint32_t id() const { return id_; }
+ int touchpad_id() const { return touchpad_id_; }
+
+ private:
+ bool IsHit(const vec3& view_location, const vec3& view_direction,
+ vec3* hit_location, vec2* hit_location_in_window_coord,
+ bool test_ime);
+ bool IsImeHit(const vec3& view_location, const vec3& view_direction,
+ vec3* hit_location);
+ void DrawOverlays(const mat4& perspective, const mat4& eye_matrix,
+ const mat4& head_matrix, float fade_value);
+ void DrawIme();
+ void DrawDimOverlay(const mat4& mvp, const TextureLayer& layer,
+ const vec2& top_left, const vec2& bottom_right);
+ void DrawWithTransform(const mat4& transform, const ShaderProgram& program);
+
+ uint32_t id_;
+ int touchpad_id_;
+
+ uint32_t current_vr_app_;
+
+ ShaderProgram* program_;
+ ShaderProgram* overlay_program_;
+
+ mat4 initial_head_matrix_;
+ mat4 scale_;
+ mat4 translate_;
+ mat4 ime_translate_;
+ vec2 size_;
+
+ std::vector<TextureLayer> textures_;
+ TextureLayer ime_texture_;
+
+ bool allow_input_ = false;
+ vec2 hit_location_in_window_coord_;
+ vec2 ime_top_left_;
+ vec2 ime_size_;
+ bool has_ime_ = false;
+
+ struct PendingFrame {
+ PendingFrame() = default;
+ PendingFrame(std::unique_ptr<HwcCallback::Frame>&& frame,
+ ViewMode visibility)
+ : frame(std::move(frame)), visibility(visibility) {}
+ PendingFrame(PendingFrame&& r)
+ : frame(std::move(r.frame)), visibility(r.visibility) {}
+
+ void operator=(PendingFrame&& r) {
+ frame.reset(r.frame.release());
+ visibility = r.visibility;
+ }
+
+ std::unique_ptr<HwcCallback::Frame> frame;
+ ViewMode visibility = ViewMode::Hidden;
+ };
+ std::deque<PendingFrame> pending_frames_;
+ PendingFrame current_frame_;
+ base::unique_fd release_fence_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // VR_WINDOW_MANAGER_DISPLAY_VIEW_H_
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 05ec64a..b755c60 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -38,7 +38,8 @@
HwcCallback::~HwcCallback() {
}
-base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& frame) {
+base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& display_frame) {
+ auto& frame = display_frame.layers;
std::vector<HwcLayer> hwc_frame(frame.size());
for (size_t i = 0; i < frame.size(); ++i) {
hwc_frame[i] = HwcLayer{
@@ -53,12 +54,13 @@
};
}
- return client_->OnFrame(
- std::make_unique<Frame>(std::move(hwc_frame)));
+ return client_->OnFrame(std::make_unique<Frame>(
+ std::move(hwc_frame), display_frame.display_id, display_frame.removed));
}
-HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers)
- : layers_(std::move(layers)) {}
+HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers, uint32_t display_id,
+ bool removed)
+ : display_id_(display_id), removed_(removed), layers_(std::move(layers)) {}
HwcCallback::FrameStatus HwcCallback::Frame::Finish() {
if (status_ == FrameStatus::kUnfinished)
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index be56856..b8aa51b 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -81,12 +81,16 @@
class Frame {
public:
- Frame(std::vector<HwcLayer>&& layers);
+ Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed);
FrameStatus Finish();
const std::vector<HwcLayer>& layers() const { return layers_; }
+ uint32_t display_id() const { return display_id_; }
+ bool removed() const { return removed_; }
private:
+ uint32_t display_id_;
+ bool removed_;
std::vector<HwcLayer> layers_;
FrameStatus status_ = FrameStatus::kUnfinished;
};
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 03d582c..72a2c26 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -15,12 +15,6 @@
namespace {
-constexpr float kLayerScaleFactor = 3.0f;
-
-constexpr unsigned int kVRAppLayerCount = 2;
-
-constexpr unsigned int kMaximumPendingFrames = 8;
-
const std::string kVertexShader = SHADER0([]() {
layout(location = 0) in vec4 aPosition;
layout(location = 1) in vec4 aTexCoord;
@@ -79,40 +73,6 @@
void main() { fragColor = vec4(0.8, 0.2, 0.2, 1.0); }
});
-const GLfloat kVertices[] = {
- -1, -1, 0,
- 1, -1, 0,
- -1, 1, 0,
- 1, 1, 0,
-};
-
-const GLfloat kTextureVertices[] = {
- 0, 1,
- 1, 1,
- 0, 0,
- 1, 0,
-};
-
-// Returns true if the given point is inside the given rect.
-bool IsInside(const vec2& pt, const vec2& tl, const vec2& br) {
- return pt.x() >= tl.x() && pt.x() <= br.x() &&
- pt.y() >= tl.y() && pt.y() <= br.y();
-}
-
-mat4 GetScalingMatrix(float width, float height) {
- float xscale = 1, yscale = 1;
- float ar = width / height;
- if (ar > 1)
- yscale = 1.0 / ar;
- else
- xscale = ar;
-
- xscale *= kLayerScaleFactor;
- yscale *= kLayerScaleFactor;
-
- return mat4(Eigen::Scaling<float>(xscale, yscale, 1.0));
-}
-
mat4 GetHorizontallyAlignedMatrixFromPose(const Posef& pose) {
vec3 position = pose.GetPosition();
quat view_quaternion = pose.GetRotation();
@@ -134,112 +94,13 @@
return m;
}
-// Helper function that applies the crop transform to the texture layer and
-// positions (and scales) the texture layer in the appropriate location in the
-// display space.
-mat4 GetLayerTransform(const TextureLayer& texture_layer, float display_width,
- float display_height) {
- // Map from vertex coordinates to [0, 1] coordinates:
- // 1) Flip y since in vertex coordinates (-1, -1) is at the bottom left and
- // in texture coordinates (0, 0) is at the top left.
- // 2) Translate by (1, 1) to map vertex coordinates to [0, 2] on x and y.
- // 3) Scale by 1 / 2 to map coordinates to [0, 1] on x and y.
- mat4 unit_space(
- Eigen::AlignedScaling3f(0.5f, 0.5f, 1.0f) *
- Eigen::Translation3f(1.0f, 1.0f, 0.0f) *
- Eigen::AlignedScaling3f(1.0f, -1.0f, 1.0f));
-
- mat4 texture_space(Eigen::AlignedScaling3f(
- texture_layer.texture->width(), texture_layer.texture->height(), 1.0f));
-
- // 1) Translate the layer to crop the left and top edge.
- // 2) Scale the layer such that the cropped right and bottom edges map outside
- // the exture region.
- float crop_width = texture_layer.crop.right - texture_layer.crop.left;
- float crop_height = texture_layer.crop.bottom - texture_layer.crop.top;
- mat4 texture_crop(
- Eigen::AlignedScaling3f(
- texture_layer.texture->width() / crop_width,
- texture_layer.texture->height() / crop_height,
- 1.0f) *
- Eigen::Translation3f(
- -texture_layer.crop.left, -texture_layer.crop.top, 0.0f));
-
- mat4 display_space(
- Eigen::AlignedScaling3f(display_width, display_height, 1.0f));
-
- // 1) Scale the texture to fit the display frame.
- // 2) Translate the texture in the display frame location.
- float display_frame_width = texture_layer.display_frame.right -
- texture_layer.display_frame.left;
- float display_frame_height = texture_layer.display_frame.bottom -
- texture_layer.display_frame.top;
- mat4 display_frame(
- Eigen::Translation3f(
- texture_layer.display_frame.left,
- texture_layer.display_frame.top,
- 0.0f) *
- Eigen::AlignedScaling3f(
- display_frame_width / display_width,
- display_frame_height / display_height,
- 1.0f));
-
- mat4 layer_transform = unit_space.inverse() * display_space.inverse() *
- display_frame * display_space * texture_space.inverse() * texture_crop *
- texture_space * unit_space;
- return layer_transform;
+int GetTouchIdForDisplay(uint32_t display) {
+ return display == 1 ? VirtualTouchpad::PRIMARY : VirtualTouchpad::VIRTUAL;
}
-// Determine if ths frame should be shown or hidden.
-ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
- uint32_t vr_app) {
- auto& layers = frame.layers();
-
- // TODO(achaulk): Figure out how to identify the current VR app for 2D app
- // detection.
-
- size_t index;
- // Skip all layers that we don't know about.
- for (index = 0; index < layers.size(); index++) {
- if (layers[index].type != 0xFFFFFFFF && layers[index].type != 0)
- break;
- }
-
- if (index == layers.size())
- return ViewMode::Hidden;
-
- if (layers[index].type != 1) {
- // We don't have a VR app layer? Abort.
- return ViewMode::Hidden;
- }
-
- // This is the VR app, ignore it.
- index++;
-
- // Now, find a dim layer if it exists.
- // If it does, ignore any layers behind it for visibility determination.
- for (size_t i = index; i < layers.size(); i++) {
- if (layers[i].appid == HwcCallback::HwcLayer::kSurfaceFlingerLayer) {
- index = i + 1;
- }
- }
-
- // If any non-skipped layers exist now then we show, otherwise hide.
- for (size_t i = index; i < layers.size(); i++) {
- if (!layers[i].should_skip_layer())
- return ViewMode::VR;
- }
- return ViewMode::Hidden;
-}
-
-
} // namespace
-ShellView::ShellView() {
- ime_translate_ = mat4(Eigen::Translation3f(0.0f, -0.5f, 0.25f));
- ime_top_left_ = vec2(0, 0);
- ime_size_ = vec2(0, 0);
-}
+ShellView::ShellView() {}
ShellView::~ShellView() {}
@@ -248,8 +109,6 @@
if (ret)
return ret;
- translate_ = Eigen::Translation3f(0, 0, -2.5f);
-
virtual_touchpad_ = VirtualTouchpadClient::Create();
const status_t touchpad_status = virtual_touchpad_->Attach();
if (touchpad_status != OK) {
@@ -286,6 +145,9 @@
controller_mesh_->SetVertices(kNumControllerMeshVertices,
kControllerMeshVertices);
+ for (auto& display : displays_)
+ display->SetPrograms(program_.get(), overlay_program_.get());
+
initialized_ = true;
return 0;
@@ -302,13 +164,13 @@
}
void ShellView::EnableDebug(bool debug) {
- ALOGI("EnableDebug(%d)", (int)debug); // XXX TODO delete
+ ALOGI("EnableDebug(%d)", (int)debug); // XXX TODO delete
QueueTask(debug ? MainThreadTask::EnableDebugMode
: MainThreadTask::DisableDebugMode);
}
void ShellView::VrMode(bool mode) {
- ALOGI("VrMode(%d)", (int)mode); // XXX TODO delete
+ ALOGI("VrMode(%d)", (int)mode); // XXX TODO delete
QueueTask(mode ? MainThreadTask::EnteringVrMode
: MainThreadTask::ExitingVrMode);
}
@@ -320,63 +182,114 @@
result.appendFormat("debug_mode = %s\n\n", debug_mode_ ? "true" : "false");
}
-void ShellView::AdvanceFrame() {
- if (!pending_frames_.empty()) {
- // Check if we should advance the frame.
- auto& frame = pending_frames_.front();
- if (frame.visibility == ViewMode::Hidden ||
- frame.frame->Finish() == HwcCallback::FrameStatus::kFinished) {
- current_frame_ = std::move(frame);
- pending_frames_.pop_front();
- }
- }
-}
-
void ShellView::OnDrawFrame() {
- textures_.clear();
- has_ime_ = false;
+ bool visible = false;
{
- std::unique_lock<std::mutex> l(pending_frame_mutex_);
- AdvanceFrame();
- }
+ std::unique_lock<std::mutex> l(display_frame_mutex_);
- bool visible = current_frame_.visibility != ViewMode::Hidden;
+ // Move any new displays into the list.
+ if (!new_displays_.empty()) {
+ for (auto& display : new_displays_) {
+ display->Recenter(GetHorizontallyAlignedMatrixFromPose(last_pose_));
+ display->SetPrograms(program_.get(), overlay_program_.get());
+ displays_.emplace_back(display.release());
+ }
+ new_displays_.clear();
+ }
+
+ // Remove any old displays from the list now.
+ if (!removed_displays_.empty()) {
+ for (auto& display : removed_displays_) {
+ displays_.erase(std::find_if(
+ displays_.begin(), displays_.end(),
+ [display](auto& ptr) { return display == ptr.get(); }));
+ }
+ removed_displays_.clear();
+ }
+
+ for (auto& display : displays_) {
+ display->AdvanceFrame();
+ visible = visible || display->visible();
+ }
+ }
if (!debug_mode_ && visible != is_visible_) {
- SetVisibility(current_frame_.visibility != ViewMode::Hidden);
+ SetVisibility(visible);
}
- if (!debug_mode_ && !visible)
- return;
-
- ime_texture_ = TextureLayer();
-
- surface_flinger_view_->GetTextures(*current_frame_.frame.get(), &textures_,
- &ime_texture_, debug_mode_,
- current_frame_.visibility == ViewMode::VR);
- has_ime_ = ime_texture_.texture != nullptr;
+ for (auto& display : displays_) {
+ display->OnDrawFrame(surface_flinger_view_.get(), debug_mode_);
+ }
}
-void ShellView::DrawEye(EyeType /* eye */, const mat4& perspective,
+void ShellView::OnEndFrame() {
+ std::unique_lock<std::mutex> l(display_frame_mutex_);
+ for (auto& display : displays_) {
+ display->UpdateReleaseFence();
+ }
+}
+
+DisplayView* ShellView::FindOrCreateDisplay(uint32_t id) {
+ for (auto& display : displays_) {
+ if (display->id() == id) {
+ return display.get();
+ }
+ }
+
+ // It might be pending addition.
+ for (auto& display : new_displays_) {
+ if (display->id() == id) {
+ return display.get();
+ }
+ }
+
+ auto display = new DisplayView(id, GetTouchIdForDisplay(id));
+ new_displays_.emplace_back(display);
+ return display;
+}
+
+base::unique_fd ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
+ std::unique_lock<std::mutex> l(display_frame_mutex_);
+ DisplayView* display = FindOrCreateDisplay(frame->display_id());
+
+ if (frame->removed()) {
+ removed_displays_.push_back(display);
+ return base::unique_fd();
+ }
+
+ bool showing = false;
+
+ base::unique_fd fd(display->OnFrame(std::move(frame), debug_mode_, &showing));
+
+ if (showing)
+ QueueTask(MainThreadTask::Show);
+
+ return fd;
+}
+
+void ShellView::DrawEye(EyeType eye, const mat4& perspective,
const mat4& eye_matrix, const mat4& head_matrix) {
- if (should_recenter_) {
+ if (should_recenter_ && !displays_.empty()) {
// Position the quad horizontally aligned in the direction the user
// is facing, effectively taking out head roll.
- initial_head_matrix_ = GetHorizontallyAlignedMatrixFromPose(last_pose_);
+ displays_[0]->Recenter(GetHorizontallyAlignedMatrixFromPose(last_pose_));
should_recenter_ = false;
}
size_ = vec2(surface_flinger_view_->width(), surface_flinger_view_->height());
- scale_ = GetScalingMatrix(size_.x(), size_.y());
-
- DrawOverlays(perspective, eye_matrix, head_matrix);
// TODO(alexst): Replicate controller rendering from VR Home.
// Current approach in the function below is a quick visualization.
DrawController(perspective, eye_matrix, head_matrix);
- // TODO: Make sure reticle is shown only over visible overlays.
+ for (auto& display : displays_) {
+ if (display->visible()) {
+ display->DrawEye(eye, perspective, eye_matrix, head_matrix, size_,
+ fade_value_);
+ }
+ }
+
DrawReticle(perspective, eye_matrix, head_matrix);
}
@@ -387,7 +300,7 @@
bool ShellView::OnClick(bool down) {
if (down) {
- if (!is_touching_ && allow_input_) {
+ if (!is_touching_ && active_display_ && active_display_->allow_input()) {
is_touching_ = true;
}
} else {
@@ -397,224 +310,6 @@
return true;
}
-base::unique_fd ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
- ViewMode visibility =
- CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
-
- if (visibility == ViewMode::Hidden && debug_mode_)
- visibility = ViewMode::VR;
-
- if (frame->layers().empty())
- current_vr_app_ = 0;
- else
- current_vr_app_ = frame->layers().front().appid;
-
- std::unique_lock<std::mutex> l(pending_frame_mutex_);
-
- pending_frames_.emplace_back(std::move(frame), visibility);
-
- if (pending_frames_.size() > kMaximumPendingFrames) {
- pending_frames_.pop_front();
- }
-
- if (visibility == ViewMode::Hidden &&
- current_frame_.visibility == ViewMode::Hidden) {
- // Consume all frames while hidden.
- while (!pending_frames_.empty())
- AdvanceFrame();
- }
-
- // If we are showing ourselves the main thread is not processing anything,
- // so give it a kick.
- if (visibility != ViewMode::Hidden &&
- current_frame_.visibility == ViewMode::Hidden) {
- QueueTask(MainThreadTask::Show);
- }
-
- return base::unique_fd(dup(release_fence_.get()));
-}
-
-bool ShellView::IsHit(const vec3& view_location, const vec3& view_direction,
- vec3* hit_location, vec2* hit_location_in_window_coord,
- bool test_ime) {
- mat4 m = initial_head_matrix_ * translate_;
- if (test_ime)
- m = m * ime_translate_;
- mat4 inverse = (m * scale_).inverse();
- vec4 transformed_loc =
- inverse * vec4(view_location[0], view_location[1], view_location[2], 1);
- vec4 transformed_dir = inverse * vec4(view_direction[0], view_direction[1],
- view_direction[2], 0);
-
- if (transformed_dir.z() >= 0 || transformed_loc.z() <= 0)
- return false;
-
- float distance = -transformed_loc.z() / transformed_dir.z();
- vec4 transformed_hit_loc = transformed_loc + transformed_dir * distance;
- if (transformed_hit_loc.x() < -1 || transformed_hit_loc.x() > 1)
- return false;
- if (transformed_hit_loc.y() < -1 || transformed_hit_loc.y() > 1)
- return false;
-
- hit_location_in_window_coord->x() =
- (1 + transformed_hit_loc.x()) / 2 * size_.x();
- hit_location_in_window_coord->y() =
- (1 - transformed_hit_loc.y()) / 2 * size_.y();
-
- *hit_location = view_location + view_direction * distance;
- return true;
-}
-
-void ShellView::DrawOverlays(const mat4& perspective, const mat4& eye_matrix,
- const mat4& head_matrix) {
- if (textures_.empty())
- return;
-
- program_->Use();
- mat4 mvp = perspective * eye_matrix * head_matrix;
- GLint view_projection_location =
- glGetUniformLocation(program_->GetProgram(), "uViewProjection");
- glUniformMatrix4fv(view_projection_location, 1, 0, mvp.data());
-
- GLint alpha_location =
- glGetUniformLocation(program_->GetProgram(), "uAlpha");
-
- GLint tex_location = glGetUniformLocation(program_->GetProgram(), "tex");
- glUniform1i(tex_location, 0);
- glActiveTexture(GL_TEXTURE0);
-
- for (const auto& texture_layer : textures_) {
- switch (texture_layer.blending) {
- case HWC2_BLEND_MODE_PREMULTIPLIED:
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- break;
- case HWC2_BLEND_MODE_COVERAGE:
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- break;
- default:
- break;
- }
-
- glUniform1f(alpha_location, fade_value_ * texture_layer.alpha);
-
- glBindTexture(GL_TEXTURE_2D, texture_layer.texture->id());
-
- mat4 layer_transform = GetLayerTransform(texture_layer, size_.x(),
- size_.y());
-
- mat4 transform = initial_head_matrix_ * translate_ * scale_ *
- layer_transform;
- DrawWithTransform(transform, *program_);
-
- glDisable(GL_BLEND);
- }
-
- if (has_ime_) {
- ime_top_left_ = vec2(static_cast<float>(ime_texture_.display_frame.left),
- static_cast<float>(ime_texture_.display_frame.top));
- ime_size_ = vec2(static_cast<float>(ime_texture_.display_frame.right -
- ime_texture_.display_frame.left),
- static_cast<float>(ime_texture_.display_frame.bottom -
- ime_texture_.display_frame.top));
-
- DrawDimOverlay(mvp, textures_[0], ime_top_left_, ime_top_left_ + ime_size_);
-
- DrawIme();
- }
-
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID,
- nullptr);
- if (sync != EGL_NO_SYNC_KHR) {
- // Need to flush in order to get the fence FD.
- glFlush();
- base::unique_fd fence(eglDupNativeFenceFDANDROID(display, sync));
- eglDestroySyncKHR(display, sync);
- UpdateReleaseFence(std::move(fence));
- } else {
- ALOGE("Failed to create sync fence");
- UpdateReleaseFence(base::unique_fd());
- }
-}
-
-void ShellView::DrawIme() {
- program_->Use();
- glBindTexture(GL_TEXTURE_2D, ime_texture_.texture->id());
-
- mat4 layer_transform = GetLayerTransform(ime_texture_, size_.x(), size_.y());
-
- mat4 transform = initial_head_matrix_ * translate_ * ime_translate_ * scale_ *
- layer_transform;
-
- DrawWithTransform(transform, *program_);
-}
-
-void ShellView::DrawDimOverlay(const mat4& mvp, const TextureLayer& layer, const vec2& top_left,
- const vec2& bottom_right) {
- overlay_program_->Use();
- glUniformMatrix4fv(
- glGetUniformLocation(overlay_program_->GetProgram(), "uViewProjection"),
- 1, 0, mvp.data());
- glUniform4f(glGetUniformLocation(overlay_program_->GetProgram(), "uCoords"),
- top_left.x() / size_.x(), top_left.y() / size_.y(),
- bottom_right.x() / size_.x(), bottom_right.y() / size_.y());
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- mat4 layer_transform =
- GetLayerTransform(layer, size_.x(), size_.y());
-
- mat4 transform =
- initial_head_matrix_ * translate_ * scale_ * layer_transform;
- DrawWithTransform(transform, *overlay_program_);
- glDisable(GL_BLEND);
-}
-
-void ShellView::DrawWithTransform(const mat4& transform,
- const ShaderProgram& program) {
- GLint transform_location =
- glGetUniformLocation(program.GetProgram(), "uTransform");
- glUniformMatrix4fv(transform_location, 1, 0, transform.data());
-
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, kVertices);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, kTextureVertices);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-}
-
-bool ShellView::IsImeHit(const vec3& view_location, const vec3& view_direction,
- vec3 *hit_location) {
- // First, check if the IME window is hit.
- bool is_hit = IsHit(view_location, view_direction, hit_location,
- &hit_location_in_window_coord_, true);
- if (is_hit) {
- // If it is, check if the window coordinate is in the IME region;
- // if so then we are done.
- if (IsInside(hit_location_in_window_coord_, ime_top_left_,
- ime_top_left_ + ime_size_)) {
- allow_input_ = true;
- return true;
- }
- }
-
- allow_input_ = false;
- // Check if we have hit the main window.
- is_hit = IsHit(view_location, view_direction, hit_location,
- &hit_location_in_window_coord_, false);
- if (is_hit) {
- // Only allow input if we are not hitting the region hidden by the IME.
- // Allowing input here would cause clicks on the main window to actually
- // be clicks on the IME.
- if (!IsInside(hit_location_in_window_coord_, ime_top_left_,
- ime_top_left_ + ime_size_)) {
- allow_input_ = true;
- }
- }
- return is_hit;
-}
-
void ShellView::DrawReticle(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix) {
reticle_->Hide();
@@ -653,30 +348,47 @@
}
}
- vec3 view_direction = vec3(view_quaternion * vec3(0, 0, -1));
-
vec3 hit_location;
+ active_display_ =
+ FindActiveDisplay(pointer_location, view_quaternion, &hit_location);
- bool is_hit;
- if(has_ime_) {
- // This will set allow_input_ and hit_location_in_window_coord_.
- is_hit = IsImeHit(pointer_location, view_direction, &hit_location);
- } else {
- is_hit = IsHit(pointer_location, view_direction, &hit_location,
- &hit_location_in_window_coord_, false);
- allow_input_ = is_hit;
- }
-
- if (is_hit) {
+ if (active_display_) {
reticle_->ShowAt(
Eigen::Translation3f(hit_location) * view_quaternion.matrix(),
- allow_input_ ? vec3(1, 0, 0) : vec3(0, 0, 0));
+ active_display_->allow_input() ? vec3(1, 0, 0) : vec3(0, 0, 0));
Touch();
}
reticle_->Draw(perspective, eye_matrix, head_matrix);
}
+DisplayView* ShellView::FindActiveDisplay(const vec3& position,
+ const quat& quaternion,
+ vec3* hit_location) {
+ vec3 direction = vec3(quaternion * vec3(0, 0, -1));
+ vec3 temp_hit;
+
+ DisplayView* best_display = nullptr;
+ vec3 best_hit;
+
+ auto is_better = [&best_hit, &position](DisplayView*, const vec3& hit) {
+ return (hit - position).squaredNorm() < (best_hit - position).squaredNorm();
+ };
+
+ for (auto& display : displays_) {
+ if (display->UpdateHitInfo(position, direction, &temp_hit)) {
+ if (!best_display || is_better(display.get(), temp_hit)) {
+ best_display = display.get();
+ best_hit = temp_hit;
+ }
+ }
+ }
+
+ if (best_display)
+ *hit_location = best_hit;
+ return best_display;
+}
+
void ShellView::DrawController(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix) {
if (!shmem_controller_active_)
@@ -712,12 +424,16 @@
return;
}
+ if (!active_display_)
+ return;
+
+ const vec2& hit_location = active_display_->hit_location();
+
// Device is portrait, but in landscape when in VR.
// Rotate touch input appropriately.
const android::status_t status = virtual_touchpad_->Touch(
- VirtualTouchpad::PRIMARY,
- 1.0f - hit_location_in_window_coord_.y() / size_.y(),
- hit_location_in_window_coord_.x() / size_.x(),
+ active_display_->touchpad_id(),
+ 1.0f - hit_location.y() / size_.y(), hit_location.x() / size_.x(),
is_touching_ ? 1.0f : 0.0f);
if (status != OK) {
ALOGE("touch failed: %d", status);
@@ -727,7 +443,7 @@
bool ShellView::OnTouchpadButton(bool down, int button) {
int buttons = touchpad_buttons_;
if (down) {
- if (allow_input_) {
+ if (active_display_ && active_display_->allow_input()) {
buttons |= button;
}
} else {
@@ -742,18 +458,16 @@
return false;
}
+ if (!active_display_)
+ return true;
+
const android::status_t status = virtual_touchpad_->ButtonState(
- VirtualTouchpad::PRIMARY, touchpad_buttons_);
+ active_display_->touchpad_id(), touchpad_buttons_);
if (status != OK) {
ALOGE("touchpad button failed: %d %d", touchpad_buttons_, status);
}
return true;
}
-void ShellView::UpdateReleaseFence(base::unique_fd fence) {
- std::lock_guard<std::mutex> guard(pending_frame_mutex_);
- release_fence_ = std::move(fence);
-}
-
} // namespace dvr
} // namespace android
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 49456c6..c10bd27 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -8,6 +8,7 @@
#include "VirtualTouchpadClient.h"
#include "application.h"
+#include "display_view.h"
#include "reticle.h"
#include "shell_view_binder_interface.h"
#include "surface_flinger_view.h"
@@ -15,12 +16,6 @@
namespace android {
namespace dvr {
-enum class ViewMode {
- Hidden,
- VR,
- App,
-};
-
class ShellView : public Application,
public android::dvr::ShellViewBinderInterface,
public HwcCallback::Client {
@@ -41,91 +36,54 @@
protected:
void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix) override;
+ void OnDrawFrame() override;
+ void OnEndFrame() override;
void OnVisibilityChanged(bool visible) override;
- void DrawOverlays(const mat4& perspective, const mat4& eye_matrix,
- const mat4& head_matrix);
void DrawReticle(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix);
- void DrawIme();
- void DrawDimOverlay(const mat4& mvp, const TextureLayer& layer,
- const vec2& top_left, const vec2& bottom_right);
void DrawController(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix);
- bool IsHit(const vec3& view_location, const vec3& view_direction,
- vec3* hit_location, vec2* hit_location_in_window_coord,
- bool test_ime);
- bool IsImeHit(const vec3& view_location, const vec3& view_direction,
- vec3 *hit_location);
void Touch();
bool OnTouchpadButton(bool down, int button);
- void OnDrawFrame() override;
- void DrawWithTransform(const mat4& transform, const ShaderProgram& program);
-
bool OnClick(bool down);
- void AdvanceFrame();
+ DisplayView* FindActiveDisplay(const vec3& position, const quat& quaternion,
+ vec3* hit_location);
- void UpdateReleaseFence(base::unique_fd fence);
// HwcCallback::Client:
base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
+ DisplayView* FindOrCreateDisplay(uint32_t id);
std::unique_ptr<ShaderProgram> program_;
std::unique_ptr<ShaderProgram> overlay_program_;
std::unique_ptr<ShaderProgram> controller_program_;
- uint32_t current_vr_app_;
-
- // Used to center the scene when the shell becomes visible.
- bool should_recenter_ = true;
- mat4 initial_head_matrix_;
- mat4 scale_;
- mat4 translate_;
- mat4 ime_translate_;
- vec2 size_;
-
std::unique_ptr<SurfaceFlingerView> surface_flinger_view_;
std::unique_ptr<Reticle> reticle_;
sp<VirtualTouchpad> virtual_touchpad_;
- std::vector<TextureLayer> textures_;
- TextureLayer ime_texture_;
-
- bool is_touching_ = false;
- bool allow_input_ = false;
- int touchpad_buttons_ = 0;
- vec2 hit_location_in_window_coord_;
- vec2 ime_top_left_;
- vec2 ime_size_;
- bool has_ime_ = false;
std::unique_ptr<Mesh<vec3, vec3, vec2>> controller_mesh_;
- struct PendingFrame {
- PendingFrame() = default;
- PendingFrame(std::unique_ptr<HwcCallback::Frame>&& frame, ViewMode visibility)
- : frame(std::move(frame)), visibility(visibility) {}
- PendingFrame(PendingFrame&& r)
- : frame(std::move(r.frame)), visibility(r.visibility) {}
+ bool is_touching_ = false;
+ int touchpad_buttons_ = 0;
+ vec2 size_;
- void operator=(PendingFrame&& r) {
- frame.reset(r.frame.release());
- visibility = r.visibility;
- }
+ // Used to center the scene when the shell becomes visible.
+ bool should_recenter_ = true;
- std::unique_ptr<HwcCallback::Frame> frame;
- ViewMode visibility = ViewMode::Hidden;
- };
- std::deque<PendingFrame> pending_frames_;
- std::mutex pending_frame_mutex_;
- PendingFrame current_frame_;
+ std::mutex display_frame_mutex_;
+
+ std::vector<std::unique_ptr<DisplayView>> displays_;
+ std::vector<std::unique_ptr<DisplayView>> new_displays_;
+ std::vector<DisplayView*> removed_displays_;
+ DisplayView* active_display_ = nullptr;
mat4 controller_translate_;
- base::unique_fd release_fence_;
-
ShellView(const ShellView&) = delete;
void operator=(const ShellView&) = delete;
};