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

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

Issue 2729523002: Re-land^2 WebVR compositor bypass via BrowserMain context + mailbox (Closed)
Patch Set: Created 3 years, 10 months 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
Index: chrome/browser/android/vr_shell/vr_shell_gl.cc
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index b7e699248d55de307307762a6a2856de73e20b19..41c83b445673c2d7ec18772da9627b22b29b0aa2 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -30,6 +30,8 @@
#include "ui/gl/gl_surface.h"
#include "ui/gl/init/gl_factory.h"
+#include "gpu/ipc/common/gpu_surface_tracker.h"
+
namespace vr_shell {
namespace {
@@ -83,9 +85,11 @@ static constexpr int kViewportListHeadlockedOffset = 2;
// 2-3 frames.
static constexpr unsigned kPoseRingBufferSize = 8;
+#if 0
// Magic numbers used to mark valid pose index values encoded in frame
// data. Must match the magic numbers used in blink's VRDisplay.cpp.
static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}};
+#endif
float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) {
float xdiff = (vec1.x - vec2.x);
@@ -235,22 +239,35 @@ void VrShellGl::InitializeGl(gfx::AcceleratedWidget window) {
return;
}
- unsigned int textures[2];
- glGenTextures(2, textures);
+ unsigned int textures[3];
+ glGenTextures(3, textures);
ui_texture_id_ = textures[0];
content_texture_id_ = textures[1];
+ webvr_texture_id_ = textures[2];
ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_);
content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_);
+ webvr_surface_texture_ = gl::SurfaceTexture::Create(webvr_texture_id_);
CreateUiSurface();
CreateContentSurface();
+ CreateWebVRSurface();
ui_surface_texture_->SetFrameAvailableCallback(base::Bind(
&VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr()));
content_surface_texture_->SetFrameAvailableCallback(base::Bind(
&VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr()));
- content_surface_texture_->SetDefaultBufferSize(
- content_tex_physical_size_.width, content_tex_physical_size_.height);
+ webvr_surface_texture_->SetFrameAvailableCallback(base::Bind(
+ &VrShellGl::OnWebVRFrameAvailable, weak_ptr_factory_.GetWeakPtr()));
ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width,
ui_tex_physical_size_.height);
+ content_surface_texture_->SetDefaultBufferSize(
+ content_tex_physical_size_.width, content_tex_physical_size_.height);
+ VLOG(1) << __FUNCTION__ << ";;; content_tex_physical_size=" <<
+ content_tex_physical_size_.width << "x" <<
+ content_tex_physical_size_.height;
+ VLOG(1) << __FUNCTION__ << ";;; render_size_primary=" <<
+ render_size_primary_.width << "x" << render_size_primary_.height;
+ webvr_surface_texture_->SetDefaultBufferSize(
+ //content_tex_physical_size_.width, content_tex_physical_size_.height);
+ 2560, 1440); // FIXME!
InitializeRenderer();
vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this)));
@@ -275,16 +292,78 @@ void VrShellGl::CreateUiSurface() {
ui_surface_->j_surface().obj()));
}
+void VrShellGl::CreateWebVRSurface() {
+ ANativeWindow* window = webvr_surface_texture_->CreateSurface();
+ gpu::GpuSurfaceTracker* tracker = gpu::GpuSurfaceTracker::Get();
+ ANativeWindow_acquire(window);
+ // setBuffersGeometry seems optional, it uses the SurfaceTexture's
+ // default size by default?
+ // ANativeWindow_setBuffersGeometry(
+ // window, 2048, 1024, WINDOW_FORMAT_RGBA_8888); // FIXME!
+ webvr_surface_handle_ = tracker->AddSurfaceForNativeWidget(window);
+ VLOG(1) << __FUNCTION__ << ";;;: webvr_surface_handle_=" <<
+ webvr_surface_handle_;
+
+ webvr_surface_ =
+ base::MakeUnique<gl::ScopedJavaSurface>(webvr_surface_texture_.get());
+ tracker->RegisterViewSurface(
+ webvr_surface_handle_, webvr_surface_->j_surface().obj());
+ // When should this be released? Does registering it keep it alive?
+ ANativeWindow_release(window);
+
+ main_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VrShell::WebVRSurfaceChanged, weak_vr_shell_,
+ webvr_surface_handle_));
+}
+
void VrShellGl::OnUIFrameAvailable() {
+ VLOG(1) << __FUNCTION__ << ";;; UI UpdateTexImage start";
ui_surface_texture_->UpdateTexImage();
+ VLOG(1) << __FUNCTION__ << ";;; UI UpdateTexImage end";
}
void VrShellGl::OnContentFrameAvailable() {
+ VLOG(1) << __FUNCTION__ << ";;; Content UpdateTexImage start";
content_surface_texture_->UpdateTexImage();
received_frame_ = true;
+ VLOG(1) << __FUNCTION__ << ";;; Content UpdateTexImage end";
}
+void VrShellGl::OnWebVRFrameAvailable() {
+ VLOG(1) << __FUNCTION__ << ";;; pending count=" << pending_frames_.size();
+ // A "while" loop here is a bad idea. It's legal to call
+ // UpdateTexImage repeatedly even if no frames are available, but
+ // that does *not* wait for a new frame, it just reuses the most
+ // recent one. That would mess up the count.
+ if (pending_frames_.empty()) {
+ VLOG(1) << __FUNCTION__ << ";;; no pending frames? Please retry! premature_received_frames " << premature_received_frames_ << " => " << (premature_received_frames_ + 1);
+ ++premature_received_frames_;
+ return;
+ }
+
+ VLOG(1) << __FUNCTION__ << ";;; requested_frames " << requested_frames_ << " => " << (requested_frames_ - 1);
+ --requested_frames_;
+ VLOG(1) << __FUNCTION__ << ";;; WebVR UpdateTexImage start";
+ webvr_surface_texture_->UpdateTexImage();
+ int frame_index = pending_frames_.front();
+ pending_frames_.pop();
+ VLOG(1) << __FUNCTION__ << ";;; WebVR UpdateTexImage end, got frame=" << frame_index;
+ DrawFrame(frame_index);
+ main_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VrShell::WebVRFrameCompleted, weak_vr_shell_,
+ frame_index));
+
+ if (pending_frames_.empty() && requested_frames_ > 0) {
+ // Heuristic got confused? TODO(klausw): do proper SubmitFrame callback?
+ VLOG(1) << __FUNCTION__ << ";;; Resetting requested_frames " << requested_frames_ << " => " << 0;
+ requested_frames_ = 0;
+ }
+}
+
+#if 0
bool VrShellGl::GetPixelEncodedFrameIndex(uint16_t* frame_index) {
+ //*frame_index = 1;
+ //return true;
TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedFrameIndex");
if (!received_frame_) {
if (last_frame_index_ == (uint16_t)-1)
@@ -321,6 +400,7 @@ bool VrShellGl::GetPixelEncodedFrameIndex(uint16_t* frame_index) {
<< static_cast<int>(pixels[2]);
return false;
}
+#endif
void VrShellGl::GvrInit(gvr_context* gvr_api) {
gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api);
@@ -344,12 +424,6 @@ void VrShellGl::GvrInit(gvr_context* gvr_api) {
}
void VrShellGl::InitializeRenderer() {
- // 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();
webvr_head_pose_.assign(kPoseRingBufferSize,
gvr_api_->GetHeadSpaceFromStartSpaceRotation(
@@ -630,7 +704,7 @@ void VrShellGl::SendGesture(InputTarget input_target,
base::Bind(target, weak_vr_shell_, base::Passed(std::move(event))));
}
-void VrShellGl::DrawFrame() {
+void VrShellGl::DrawFrame(int frame_index) {
TRACE_EVENT0("gpu", "VrShellGl::DrawFrame");
// Reset the viewport list to just the pair of viewports for the
@@ -638,7 +712,9 @@ void VrShellGl::DrawFrame() {
// DrawVrShell if needed.
buffer_viewport_list_->SetToRecommendedBufferViewports();
+ TRACE_EVENT_BEGIN0("gpu", "VrShellGl::AcquireFrame");
gvr::Frame frame = swap_chain_->AcquireFrame();
+ TRACE_EVENT_END0("gpu", "VrShellGl::AcquireFrame");
if (!frame.is_valid()) {
return;
}
@@ -647,7 +723,6 @@ void VrShellGl::DrawFrame() {
DrawWebVr();
}
- uint16_t frame_index;
gvr::Mat4f head_pose;
// When using async reprojection, we need to know which pose was used in
@@ -657,8 +732,7 @@ void VrShellGl::DrawFrame() {
// distortion rendering since that doesn't need a pose, and reading back
// pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop
// doing this once we have working no-compositor rendering for WebVR.
- if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled() &&
- GetPixelEncodedFrameIndex(&frame_index)) {
+ if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled()) {
static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize),
"kPoseRingBufferSize must be a power of 2");
head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize];
@@ -671,6 +745,7 @@ void VrShellGl::DrawFrame() {
"than half of frame_index_ range.");
while (!pending_bounds_.empty()) {
uint16_t index = pending_bounds_.front().first;
+ VLOG(1) << __FUNCTION__ << ";;; new bounds, index=" << index;
// If index is less than the frame_index it's possible we've wrapped, so
// we extend the range and 'un-wrap' to account for this.
if (index < frame_index)
@@ -713,7 +788,9 @@ void VrShellGl::DrawFrame() {
UpdateController(GetForwardVector(head_pose));
- DrawVrShell(head_pose, frame);
+ // Drawing VrShell causes GL error 0x501 GL_INVALID_VALUE while in
+ // WebVR mode. FIXME.
+ if (!web_vr_mode_) DrawVrShell(head_pose, frame);
frame.Unbind();
frame.Submit(*buffer_viewport_list_, head_pose);
@@ -725,6 +802,20 @@ void VrShellGl::DrawFrame() {
}
}
+void VrShellGl::ScheduleWebVRFrame(int frame_index) {
+ VLOG(1) << __FUNCTION__ << ";;; schedule frame=" << frame_index;
+ pending_frames_.emplace(frame_index);
+}
+
+void VrShellGl::DropWebVRFrame(int frame_index) {
+ VLOG(1) << __FUNCTION__ << ";;; drop frame=" << frame_index;
+ if (requested_frames_ > 0) {
+ VLOG(1) << __FUNCTION__ << ";;; requested_frames " << requested_frames_ <<
+ " => " << (requested_frames_ - 1);
+ --requested_frames_;
+ }
+}
+
void VrShellGl::DrawVrShell(const gvr::Mat4f& head_pose, gvr::Frame& frame) {
TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell");
std::vector<const ContentRectangle*> head_locked_elements;
@@ -1029,6 +1120,11 @@ void VrShellGl::SetWebVrMode(bool enabled) {
void VrShellGl::UpdateWebVRTextureBounds(int16_t frame_index,
const gvr::Rectf& left_bounds,
const gvr::Rectf& right_bounds) {
+ VLOG(1) << __FUNCTION__ << ";;; frame_index=" << frame_index <<
+ " left=" << left_bounds.left << "," << left_bounds.bottom <<
+ "," << left_bounds.right << "," << left_bounds.top <<
+ " right=" << right_bounds.left << "," << right_bounds.bottom <<
+ "," << right_bounds.right << "," << right_bounds.top;
if (frame_index < 0) {
webvr_left_viewport_->SetSourceUv(left_bounds);
webvr_right_viewport_->SetSourceUv(right_bounds);
@@ -1068,6 +1164,14 @@ base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() {
}
void VrShellGl::OnVSync() {
+ while (premature_received_frames_ > 0) {
+ VLOG(1) << __FUNCTION__ << ";;; Retrying premature received frame " <<
+ premature_received_frames_ << " => " <<
+ (premature_received_frames_ - 1);
+ --premature_received_frames_;
+ OnWebVRFrameAvailable();
+ }
+
base::TimeTicks now = base::TimeTicks::Now();
base::TimeTicks target;
@@ -1081,13 +1185,24 @@ void VrShellGl::OnVSync() {
target - now);
base::TimeDelta time = intervals * vsync_interval_;
+ // Send a small rate of vsyncs even while backlogged to avoid
+ // locking up when the rAF loop doesn't submit a frame.
+ static int skip_counter = 0;
if (!callback_.is_null()) {
- SendVSync(time, base::ResetAndReturn(&callback_));
+ if (requested_frames_ < 1 || (++skip_counter % 30) == 0) {
+ VLOG(1) << __FUNCTION__ << ";;; vsync B, interval=" << vsync_interval_;
+ SendVSync(time, base::ResetAndReturn(&callback_));
+ } else {
+ VLOG(1) << __FUNCTION__ << ";;; Skip vsync B, already have frame requested";
+ return;
+ }
} else {
pending_vsync_ = true;
pending_time_ = time;
}
- DrawFrame();
+ if (!web_vr_mode_) {
+ DrawFrame(-1);
+ }
}
void VrShellGl::OnRequest(device::mojom::VRVSyncProviderRequest request) {
@@ -1107,6 +1222,7 @@ void VrShellGl::GetVSync(const GetVSyncCallback& callback) {
return;
}
pending_vsync_ = false;
+ VLOG(1) << __FUNCTION__ << ";;; vsync A, pending time=" << pending_time_;
SendVSync(pending_time_, callback);
}
@@ -1116,6 +1232,7 @@ void VrShellGl::UpdateVSyncInterval(int64_t timebase_nanos,
vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000);
vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds);
vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this)));
+ VLOG(1) << __FUNCTION__ << ";;; vsync_interval=" << vsync_interval_;
OnVSync();
}
@@ -1132,7 +1249,12 @@ void VrShellGl::SendVSync(base::TimeDelta time,
const GetVSyncCallback& callback) {
TRACE_EVENT0("input", "VrShellGl::SendVSync");
+ VLOG(1) << __FUNCTION__ << ";;; requested_frames " << requested_frames_ <<
+ " => " << (requested_frames_ + 1);
+ ++requested_frames_;
+
uint8_t frame_index = frame_index_++;
+ VLOG(1) << __FUNCTION__ << ";;; vsync for frame=" << (int)frame_index;
gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow();
target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos;

Powered by Google App Engine
This is Rietveld 408576698