Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(618)

Unified Diff: chrome/browser/android/vr_shell/vr_shell.cc

Issue 2508703002: WebVR: Use content CVC size for compositor rendering (Closed)
Patch Set: Rebase, use more appropriate crbug/655722 for TODOS Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/android/vr_shell/vr_shell.h ('k') | chrome/browser/android/vr_shell/vr_shell_delegate.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/android/vr_shell/vr_shell.cc
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
index 5e4189a97aa92570b67b4a403b9e7e21ff6fb0e0..48a19ba7428bd18e1c01cffffc3b08cfa2120c9f 100644
--- a/chrome/browser/android/vr_shell/vr_shell.cc
+++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -73,9 +73,24 @@ static constexpr float kReticleOffset = 0.99f;
// adjust according to content quad placement.
static constexpr float kReticleDistanceMultiplier = 1.5f;
+// GVR buffer indices for use with viewport->SetSourceBufferIndex
+// or frame.BindBuffer. We use one for world content (with reprojection)
+// including main VrShell and WebVR content plus world-space UI.
+// The headlocked buffer is for UI that should not use reprojection.
static constexpr int kFramePrimaryBuffer = 0;
static constexpr int kFrameHeadlockedBuffer = 1;
+// Pixel dimensions and field of view for the head-locked content. This
+// is currently sized to fit the WebVR "insecure transport" warnings,
+// adjust it as needed if there is additional content.
+static constexpr gvr::Sizei kHeadlockedBufferDimensions = {1024, 1024};
+static constexpr gvr::Rectf kHeadlockedBufferFov = {20.f, 20.f, 20.f, 20.f};
+
+// The GVR viewport list has two entries (left eye and right eye) for each
+// GVR buffer.
+static constexpr int kViewportListPrimaryOffset = 0;
+static constexpr int kViewportListHeadlockedOffset = 2;
+
vr_shell::VrShell* g_instance;
static const char kVrShellUIURL[] = "chrome://vr-shell-ui";
@@ -222,13 +237,10 @@ void VrShell::GvrInit(JNIEnv* env,
gvr_api_ =
gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(native_gvr_api));
-
- if (delegate_) {
- main_thread_task_runner_->PostTask(
- FROM_HERE, base::Bind(&device::GvrDeviceProvider::OnGvrDelegateReady,
- delegate_->GetDeviceProvider(),
- weak_ptr_factory_.GetWeakPtr()));
- }
+ // TODO(klausw,crbug.com/655722): should report OnGvrDelegateReady here once
+ // we switch to using a WebVR render surface. We currently need to wait for
+ // the compositor window's size to be known first. See also
+ // ContentSurfaceChanged.
controller_.reset(
new VrController(reinterpret_cast<gvr_context*>(native_gvr_api)));
content_input_manager_ = new VrInputManager(main_contents_);
@@ -261,30 +273,53 @@ void VrShell::InitializeGl(JNIEnv* env,
content_texture_id_ = content_texture_handle;
ui_texture_id_ = ui_texture_handle;
+ // While WebVR is going through the compositor path, it shares
+ // the same texture ID. This will change once it gets its own
+ // surface, but store it separately to avoid future confusion.
+ // TODO(klausw,crbug.com/655722): remove this.
+ webvr_texture_id_ = content_texture_id_;
+
gvr_api_->InitializeGl();
std::vector<gvr::BufferSpec> specs;
+ // For kFramePrimaryBuffer (primary VrShell and WebVR content)
specs.push_back(gvr_api_->CreateBufferSpec());
- render_size_ = specs[0].GetSize();
+ render_size_primary_ = specs[kFramePrimaryBuffer].GetSize();
+ render_size_primary_vrshell_ = render_size_primary_;
- // For WebVR content
+ // For kFrameHeadlockedBuffer (for WebVR insecure content warning).
+ // Set this up at fixed resolution, the (smaller) FOV gets set below.
specs.push_back(gvr_api_->CreateBufferSpec());
+ specs.back().SetSize(kHeadlockedBufferDimensions);
+ render_size_headlocked_ = specs[kFrameHeadlockedBuffer].GetSize();
swap_chain_.reset(new gvr::SwapChain(gvr_api_->CreateSwapChain(specs)));
vr_shell_renderer_.reset(new VrShellRenderer());
+
+ // Allocate a buffer viewport for use in UI drawing. This isn't
+ // initialized at this point, it'll be set from other viewport list
+ // entries as needed.
+ buffer_viewport_.reset(
+ new gvr::BufferViewport(gvr_api_->CreateBufferViewport()));
+
+ // Set up main content viewports. The list has two elements, 0=left
+ // eye and 1=right eye.
buffer_viewport_list_.reset(
new gvr::BufferViewportList(gvr_api_->CreateEmptyBufferViewportList()));
buffer_viewport_list_->SetToRecommendedBufferViewports();
- buffer_viewport_.reset(
- new gvr::BufferViewport(gvr_api_->CreateBufferViewport()));
-
+ // Set up head-locked UI viewports, these will be elements 2=left eye
+ // and 3=right eye. For now, use a hardcoded 20-degree-from-center FOV
+ // frustum to reduce rendering cost for this overlay. This fits the
+ // current content, but will need to be adjusted once there's more dynamic
+ // head-locked content that could be larger.
headlocked_left_viewport_.reset(
new gvr::BufferViewport(gvr_api_->CreateBufferViewport()));
buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE,
headlocked_left_viewport_.get());
headlocked_left_viewport_->SetSourceBufferIndex(kFrameHeadlockedBuffer);
headlocked_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE);
+ headlocked_left_viewport_->SetSourceFov(kHeadlockedBufferFov);
headlocked_right_viewport_.reset(
new gvr::BufferViewport(gvr_api_->CreateBufferViewport()));
@@ -292,7 +327,10 @@ void VrShell::InitializeGl(JNIEnv* env,
headlocked_right_viewport_.get());
headlocked_right_viewport_->SetSourceBufferIndex(kFrameHeadlockedBuffer);
headlocked_right_viewport_->SetReprojection(GVR_REPROJECTION_NONE);
+ headlocked_right_viewport_->SetSourceFov(kHeadlockedBufferFov);
+ // Save copies of the first two viewport items for use by WebVR, it
+ // sets its own UV bounds.
webvr_left_viewport_.reset(
new gvr::BufferViewport(gvr_api_->CreateBufferViewport()));
buffer_viewport_list_->GetBufferViewport(GVR_LEFT_EYE,
@@ -506,8 +544,24 @@ uint32_t GetPixelEncodedPoseIndex() {
}
void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) {
+ // Reset the viewport list to just the pair of viewports for the
+ // primary buffer each frame. Head-locked viewports get added by
+ // DrawVrShell if needed.
buffer_viewport_list_->SetToRecommendedBufferViewports();
+ if (html_interface_->GetMode() == UiInterface::Mode::WEB_VR) {
+ // If needed, resize the primary buffer for use with WebVR.
+ if (render_size_primary_ != render_size_primary_webvr_) {
+ render_size_primary_ = render_size_primary_webvr_;
+ swap_chain_->ResizeBuffer(kFramePrimaryBuffer, render_size_primary_);
+ }
+ } else {
+ if (render_size_primary_ != render_size_primary_vrshell_) {
+ render_size_primary_ = render_size_primary_vrshell_;
+ swap_chain_->ResizeBuffer(kFramePrimaryBuffer, render_size_primary_);
+ }
+ }
+
gvr::Frame frame = swap_chain_->AcquireFrame();
gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow();
target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos;
@@ -544,8 +598,8 @@ void VrShell::DrawFrame(JNIEnv* env, const JavaParamRef<jobject>& obj) {
// buffering in the compositor and SurfaceTexture, we read the pose number
// from a corner pixel. There's no point in doing this for legacy
// distortion rendering since that doesn't need a pose, and reading back
- // pixels is an expensive operation. TODO(klausw): stop doing this once we
- // have working no-compositor rendering for WebVR.
+ // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop
+ // doing this once we have working no-compositor rendering for WebVR.
if (gvr_api_->GetAsyncReprojectionEnabled()) {
uint32_t webvr_pose_frame = GetPixelEncodedPoseIndex();
// If we don't get a valid frame ID back we shouldn't attempt to reproject
@@ -582,39 +636,69 @@ void VrShell::DrawVrShell(const gvr::Mat4f& head_pose,
}
}
- bool not_web_vr = html_interface_->GetMode() != UiInterface::Mode::WEB_VR;
+ if (html_interface_->GetMode() == UiInterface::Mode::WEB_VR) {
+ // WebVR is incompatible with 3D world compositing since the
+ // depth buffer was already populated with unknown scaling - the
+ // WebVR app has full control over zNear/zFar. Just leave the
+ // existing content in place in the primary buffer without
+ // clearing. Currently, there aren't any world elements in WebVR
+ // mode, this will need further testing if those get added
+ // later.
+ } else {
+ // Non-WebVR mode, enable depth testing and clear the primary buffers.
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
- glEnable(GL_CULL_FACE);
- glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_TRUE);
-
- if (not_web_vr) {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
- DrawUiView(&head_pose, world_elements);
+ if (!world_elements.empty()) {
+ DrawUiView(&head_pose, world_elements, render_size_primary_,
+ kViewportListPrimaryOffset);
+ }
if (!head_locked_elements.empty()) {
- // Switch to head-locked viewports.
- size_t last_viewport = buffer_viewport_list_->GetSize();
- buffer_viewport_list_->SetBufferViewport(last_viewport++,
+ // Add head-locked viewports. The list gets reset to just
+ // the recommended viewports (for the primary buffer) each frame.
+ buffer_viewport_list_->SetBufferViewport(
+ kViewportListHeadlockedOffset + GVR_LEFT_EYE,
*headlocked_left_viewport_);
- buffer_viewport_list_->SetBufferViewport(last_viewport++,
+ buffer_viewport_list_->SetBufferViewport(
+ kViewportListHeadlockedOffset + GVR_RIGHT_EYE,
*headlocked_right_viewport_);
// Bind the headlocked framebuffer.
frame.BindBuffer(kFrameHeadlockedBuffer);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- DrawUiView(nullptr, head_locked_elements);
+ DrawUiView(nullptr, head_locked_elements, render_size_headlocked_,
+ kViewportListHeadlockedOffset);
}
}
+void VrShell::SetWebVRRenderSurfaceSize(int width, int height) {
+ render_size_primary_webvr_.width = width;
+ render_size_primary_webvr_.height = height;
+ // TODO(klausw,crbug.com/655722): set the WebVR render surface size here once
+ // we have that.
+}
+
+gvr::Sizei VrShell::GetWebVRCompositorSurfaceSize() {
+ // This is a stopgap while we're using the WebVR compositor rendering path.
+ // TODO(klausw,crbug.com/655722): Remove this method and member once we're
+ // using a separate WebVR render surface.
+ return content_tex_pixels_for_webvr_;
+}
+
+
void VrShell::DrawUiView(const gvr::Mat4f* head_pose,
- const std::vector<const ContentRectangle*>& elements) {
+ const std::vector<const ContentRectangle*>& elements,
+ const gvr::Sizei& render_size, int viewport_offset) {
for (auto eye : {GVR_LEFT_EYE, GVR_RIGHT_EYE}) {
- buffer_viewport_list_->GetBufferViewport(eye, buffer_viewport_.get());
+ buffer_viewport_list_->GetBufferViewport(
+ eye + viewport_offset, buffer_viewport_.get());
gvr::Mat4f view_matrix = gvr_api_->GetEyeFromHeadMatrix(eye);
if (head_pose != nullptr) {
@@ -622,7 +706,7 @@ void VrShell::DrawUiView(const gvr::Mat4f* head_pose,
}
gvr::Recti pixel_rect =
- CalculatePixelSpaceRect(render_size_, buffer_viewport_->GetSourceUv());
+ CalculatePixelSpaceRect(render_size, buffer_viewport_->GetSourceUv());
glViewport(pixel_rect.left, pixel_rect.bottom,
pixel_rect.right - pixel_rect.left,
pixel_rect.top - pixel_rect.bottom);
@@ -747,11 +831,13 @@ void VrShell::DrawWebVr() {
glDisable(GL_BLEND);
glDisable(GL_POLYGON_OFFSET_FILL);
- glViewport(0, 0, render_size_.width, render_size_.height);
- vr_shell_renderer_->GetWebVrRenderer()->Draw(content_texture_id_);
+ glViewport(0, 0, render_size_primary_.width, render_size_primary_.height);
+ vr_shell_renderer_->GetWebVrRenderer()->Draw(webvr_texture_id_);
- buffer_viewport_list_->SetBufferViewport(0, *webvr_left_viewport_);
- buffer_viewport_list_->SetBufferViewport(1, *webvr_right_viewport_);
+ buffer_viewport_list_->SetBufferViewport(GVR_LEFT_EYE,
+ *webvr_left_viewport_);
+ buffer_viewport_list_->SetBufferViewport(GVR_RIGHT_EYE,
+ *webvr_right_viewport_);
}
void VrShell::OnTriggerEvent(JNIEnv* env, const JavaParamRef<jobject>& obj) {
@@ -830,11 +916,28 @@ void VrShell::ContentSurfaceChanged(JNIEnv* env,
jint width,
jint height,
const JavaParamRef<jobject>& surface) {
+ // If we have a delegate, must trigger "ready" callback one time only.
+ // Do so the first time we got a nonzero size. (This assumes it doesn't
+ // change, but once we get resize ability we'll no longer need this hack.)
+ // TODO(klausw,crbug.com/655722): remove when we have surface support.
+ bool delegate_not_ready = delegate_ && !content_tex_pixels_for_webvr_.width;
+
content_compositor_->SurfaceChanged((int)width, (int)height, surface);
+ content_tex_pixels_for_webvr_.width = width;
+ content_tex_pixels_for_webvr_.height = height;
float scale_factor = display::Screen::GetScreen()
->GetPrimaryDisplay().device_scale_factor();
content_tex_width_ = width / scale_factor;
content_tex_height_ = height / scale_factor;
+
+ // TODO(klausw,crbug.com/655722): move this back to GvrInit once we have
+ // our own WebVR surface.
+ if (delegate_ && delegate_not_ready) {
+ main_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&device::GvrDeviceProvider::OnGvrDelegateReady,
+ delegate_->GetDeviceProvider(),
+ weak_ptr_factory_.GetWeakPtr()));
+ }
}
void VrShell::UiSurfaceChanged(JNIEnv* env,
« no previous file with comments | « chrome/browser/android/vr_shell/vr_shell.h ('k') | chrome/browser/android/vr_shell/vr_shell_delegate.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698