Commit e42561bd authored by Klaus Weidner's avatar Klaus Weidner Committed by Commit Bot

Add ClientWaitWithTimeout to GLFenceEGL, use for WebVR

Currently, GLFenceEGL's ClientWait always uses EGL_FOREVER_KHR. This change
adds a way to specify a timeout so that a thread can yield to do other work
while waiting.

This is being used in the critical path for WebVR rendering, and even a 1ms
delay noticeably cuts into the 16ms frame time budget. The workaround was to
repeatedly poll checking for completion, but that needs a very aggressive
timeout to avoid unnecessary delay. Using a timeout is more efficient.

Bug: 726026
Change-Id: I4c4292f31cf472e538cfdf18a835d48226d6ac58
Reviewed-on: https://chromium-review.googlesource.com/572663Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Commit-Queue: Klaus Weidner <klausw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#487159}
parent 1b9c3c76
......@@ -79,11 +79,10 @@ static constexpr unsigned kWebVRSlidingAverageSize = 5;
// controller movement as a gesture.
static constexpr float kMinAppButtonGestureAngleRad = 0.25;
// Interval for checking for the WebVR rendering GL fence. Ideally we'd want to
// wait for completion with a short timeout, but GLFenceEGL doesn't currently
// support that, see TODO(klausw,crbug.com/726026).
static constexpr base::TimeDelta kWebVRFenceCheckInterval =
base::TimeDelta::FromMicroseconds(250);
// Timeout for checking for the WebVR rendering GL fence. If the timeout is
// reached, yield to let other tasks execute before rechecking.
static constexpr base::TimeDelta kWebVRFenceCheckTimeout =
base::TimeDelta::FromMicroseconds(2000);
// Provides the direction the head is looking towards as a 3x1 unit vector.
gfx::Vector3dF GetForwardVector(const gfx::Transform& head_pose) {
......@@ -877,13 +876,12 @@ void VrShellGl::DrawFrame(int16_t frame_index) {
if (ShouldDrawWebVr() && surfaceless_rendering_) {
// Continue with submit once a GL fence signals that current drawing
// operations have completed.
std::unique_ptr<gl::GLFence> fence = base::MakeUnique<gl::GLFenceEGL>();
task_runner_->PostDelayedTask(
std::unique_ptr<gl::GLFenceEGL> fence = base::MakeUnique<gl::GLFenceEGL>();
task_runner_->PostTask(
FROM_HERE,
base::Bind(&VrShellGl::DrawFrameSubmitWhenReady,
weak_ptr_factory_.GetWeakPtr(), frame_index, frame.release(),
render_info_primary_.head_pose, base::Passed(&fence)),
kWebVRFenceCheckInterval);
render_info_primary_.head_pose, base::Passed(&fence)));
} else {
// Continue with submit immediately.
DrawFrameSubmitWhenReady(frame_index, frame.release(),
......@@ -916,18 +914,21 @@ void VrShellGl::UpdateEyeInfos(const gfx::Transform& head_pose,
}
}
void VrShellGl::DrawFrameSubmitWhenReady(int16_t frame_index,
gvr_frame* frame_ptr,
const gfx::Transform& head_pose,
std::unique_ptr<gl::GLFence> fence) {
if (fence && !fence->HasCompleted()) {
task_runner_->PostDelayedTask(
FROM_HERE,
base::Bind(&VrShellGl::DrawFrameSubmitWhenReady,
weak_ptr_factory_.GetWeakPtr(), frame_index, frame_ptr,
head_pose, base::Passed(&fence)),
kWebVRFenceCheckInterval);
return;
void VrShellGl::DrawFrameSubmitWhenReady(
int16_t frame_index,
gvr_frame* frame_ptr,
const gfx::Transform& head_pose,
std::unique_ptr<gl::GLFenceEGL> fence) {
if (fence) {
fence->ClientWaitWithTimeoutNanos(kWebVRFenceCheckTimeout.InMicroseconds() *
1000);
if (!fence->HasCompleted()) {
task_runner_->PostTask(
FROM_HERE, base::Bind(&VrShellGl::DrawFrameSubmitWhenReady,
weak_ptr_factory_.GetWeakPtr(), frame_index,
frame_ptr, head_pose, base::Passed(&fence)));
return;
}
}
TRACE_EVENT1("gpu", "VrShellGl::DrawFrameSubmitWhenReady", "frame",
......
......@@ -35,7 +35,7 @@ class WebMouseEvent;
namespace gl {
class GLContext;
class GLFence;
class GLFenceEGL;
class GLSurface;
class ScopedJavaSurface;
class SurfaceTexture;
......@@ -121,7 +121,7 @@ class VrShellGl : public device::mojom::VRPresentationProvider,
void DrawFrameSubmitWhenReady(int16_t frame_index,
gvr_frame* frame_ptr,
const gfx::Transform& head_pose,
std::unique_ptr<gl::GLFence> fence);
std::unique_ptr<gl::GLFenceEGL> fence);
bool ShouldDrawWebVr();
void DrawWebVr();
bool WebVrPoseByteIsValid(int pose_index_byte);
......
......@@ -41,15 +41,19 @@ bool GLFenceEGL::HasCompleted() {
}
void GLFenceEGL::ClientWait() {
EGLint flags = 0;
EGLTimeKHR time = EGL_FOREVER_KHR;
EGLint result = eglClientWaitSyncKHR(display_, sync_, flags, time);
EGLint result = ClientWaitWithTimeoutNanos(EGL_FOREVER_KHR);
DCHECK(g_ignore_egl_sync_failures || EGL_TIMEOUT_EXPIRED_KHR != result);
}
EGLint GLFenceEGL::ClientWaitWithTimeoutNanos(EGLTimeKHR timeout) {
EGLint flags = 0;
EGLint result = eglClientWaitSyncKHR(display_, sync_, flags, timeout);
if (result == EGL_FALSE) {
LOG(ERROR) << "Failed to wait for EGLSync. error:"
<< ui::GetLastEGLErrorString();
CHECK(g_ignore_egl_sync_failures);
}
return result;
}
void GLFenceEGL::ServerWait() {
......
......@@ -24,6 +24,9 @@ class GL_EXPORT GLFenceEGL : public GLFence {
void ClientWait() override;
void ServerWait() override;
// EGL-specific wait-with-timeout implementation:
EGLint ClientWaitWithTimeoutNanos(EGLTimeKHR timeout);
private:
EGLSyncKHR sync_;
EGLDisplay display_;
......
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