Chromium Code Reviews| Index: chrome/browser/android/vr_shell/vr_shell_command_buffer_gl.cc |
| diff --git a/chrome/browser/android/vr_shell/vr_shell_command_buffer_gl.cc b/chrome/browser/android/vr_shell/vr_shell_command_buffer_gl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4b1e1d54919420b166c7f544099fe9de4e0e70b5 |
| --- /dev/null |
| +++ b/chrome/browser/android/vr_shell/vr_shell_command_buffer_gl.cc |
| @@ -0,0 +1,146 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/android/vr_shell/vr_shell_command_buffer_gl.h" |
| + |
| +#include "base/memory/ptr_util.h" |
| +#include "chrome/browser/android/vr_shell/vr_shell_gpu_renderer.h" |
| +#include "content/public/browser/android/compositor.h" |
| +#include "gpu/command_buffer/client/gles2_interface.h" |
| +#include "gpu/command_buffer/common/mailbox.h" |
| +#include "gpu/command_buffer/common/sync_token.h" |
| +#include "gpu/ipc/client/gpu_channel_host.h" |
| +#include "gpu/ipc/common/gpu_surface_tracker.h" |
| +#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h" |
| +#include "ui/gl/android/surface_texture.h" |
| + |
| +#include <android/native_window_jni.h> |
| + |
| +namespace vr_shell { |
| + |
| +VrShellCommandBufferGl::VrShellCommandBufferGl() : weak_ptr_factory_(this) {} |
| + |
| +VrShellCommandBufferGl::~VrShellCommandBufferGl() {} |
| + |
| +void VrShellCommandBufferGl::OnGpuChannelEstablished( |
| + scoped_refptr<gpu::GpuChannelHost> gpu_channel_host) { |
| + // Estimate the size of a large 16:9 surface used for offscreen rendering. |
| + const size_t full_screen_texture_size_in_bytes = 4800 * 2700 * 4; |
| + |
| + // TODO(klausw): investigate appropriate settings here. This is poorly |
| + // documented. |
| + gpu::SharedMemoryLimits limits; |
|
bajones
2017/03/07 00:48:07
Looks like this could probably use gpu::SharedMemo
klausw
2017/03/07 02:55:55
Done.
|
| + limits.command_buffer_size = 64 * 1024; |
| + limits.start_transfer_buffer_size = 64 * 1024; |
| + limits.min_transfer_buffer_size = 64 * 1024; |
| + limits.max_transfer_buffer_size = full_screen_texture_size_in_bytes; |
| + limits.mapped_memory_reclaim_limit = full_screen_texture_size_in_bytes; |
| + |
| + // Our attributes must be compatible with the shared offscreen |
| + // surface used by virtualized contexts, otherwise mailbox |
| + // synchronization doesn't work properly - it assumes a shared |
| + // underlying GL context. TODO(klausw): is there a more official |
| + // way to get default-compatible settings? |
| + gpu::gles2::ContextCreationAttribHelper attributes; |
| + attributes.alpha_size = -1; |
| + attributes.red_size = 8; |
| + attributes.green_size = 8; |
| + attributes.blue_size = 8; |
| + attributes.stencil_size = 0; |
| + attributes.depth_size = 0; |
| + attributes.samples = 0; |
| + attributes.sample_buffers = 0; |
| + attributes.bind_generates_resource = false; |
| + |
| + bool automatic_flushes = false; |
| + bool support_locking = false; |
| + constexpr ui::ContextProviderCommandBuffer* shared_context_provider = nullptr; |
| + context_provider_command_buffer_ = |
| + make_scoped_refptr(new ui::ContextProviderCommandBuffer( |
| + std::move(gpu_channel_host), gpu::GPU_STREAM_DEFAULT, |
| + gpu::GpuStreamPriority::NORMAL, surface_handle_, |
| + GURL("chrome://gpu/MusContextFactory"), automatic_flushes, |
|
bajones
2017/03/07 00:48:07
I believe we want to use a different URL here? May
klausw
2017/03/07 02:55:55
Done, using chrome://gpu/WebVRContextFactory
|
| + support_locking, limits, attributes, shared_context_provider, |
| + ui::command_buffer_metrics::MUS_CLIENT_CONTEXT)); |
|
bajones
2017/03/07 00:48:07
I doubt Mus wants our command buffer metrics mixed
klausw
2017/03/07 02:55:55
Done.
|
| + |
| + if (!context_provider_command_buffer_->BindToCurrentThread()) { |
| + LOG(ERROR) << __FUNCTION__ << ";;; failed to init ContextProvider"; |
| + return; |
| + } |
| + |
| + gl_ = context_provider_command_buffer_->ContextGL(); |
| + |
| + copy_renderer_ = base::MakeUnique<GpuRenderer>(gl_); |
| +} |
| + |
| +std::unique_ptr<gl::ScopedJavaSurface> VrShellCommandBufferGl::CreateSurface( |
| + scoped_refptr<gl::SurfaceTexture> surface_texture) { |
| + ANativeWindow* window = surface_texture->CreateSurface(); |
| + gpu::GpuSurfaceTracker* tracker = gpu::GpuSurfaceTracker::Get(); |
| + ANativeWindow_acquire(window); |
| + // Skip ANativeWindow_setBuffersGeometry, the default size appears to work. |
| + surface_handle_ = tracker->AddSurfaceForNativeWidget(window); |
| + |
| + auto surface = base::MakeUnique<gl::ScopedJavaSurface>(surface_texture.get()); |
| + tracker->RegisterViewSurface(surface_handle_, surface->j_surface().obj()); |
| + // TODO(klausw): When should this be released? Does registering it |
| + // keep it alive? |
| + ANativeWindow_release(window); |
| + |
| + gpu::GpuChannelEstablishFactory* factory = |
| + content::Compositor::GetGpuChannelFactory(); |
| + |
| + factory->EstablishGpuChannel( |
| + base::Bind(&VrShellCommandBufferGl::OnGpuChannelEstablished, |
| + weak_ptr_factory_.GetWeakPtr())); |
| + |
| + return surface; |
| +} |
| + |
| +void VrShellCommandBufferGl::ResizeSurface(int width, int height) { |
| + if (!gl_) { |
| + LOG(ERROR) << "Cannot resize, not initialized"; |
| + return; |
| + } |
| + gl_->ResizeCHROMIUM(width, height, 1.f, false); |
| + gl_->Viewport(0, 0, width, height); |
| +} |
| + |
| +bool VrShellCommandBufferGl::CopyFrameToSurface(int frame_index, |
| + const gpu::Mailbox& mailbox, |
| + gpu::SyncToken& sync_token, |
| + bool discard) { |
| + TRACE_EVENT1("gpu", "VrShellCommandBufferGl::CopyFrameToSurface", "frame", |
| + frame_index); |
| + if (!gl_) { |
| + // We may not have a context yet, i.e. due to surface initialization |
| + // being incomplete. This is not an error, but we obviously can't draw |
| + // yet. |
| + return false; |
| + } |
| + |
| + { |
| + TRACE_EVENT0("gpu", "VrShellCommandBufferGl::WaitSyncToken"); |
| + gl_->WaitSyncTokenCHROMIUM(sync_token.GetData()); |
| + } |
| + |
| + GLuint vrSourceTexture = |
| + gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); |
| + |
| + if (discard) { |
| + // We've consumed the texture, but the caller requested that we |
| + // don't draw it because the previous one hasn't been consumed |
| + // yet. (Swapping twice on a Surfacewithout consuming one in |
| + // between from the SurfaceTexture can lose frames.) This should |
| + // be rare, it's a waste of resources and can cause jerky |
| + // animation due to the lost frames. |
| + return false; |
| + } else { |
| + copy_renderer_->DrawQuad(gl_, vrSourceTexture); |
| + gl_->SwapBuffers(); |
| + return true; |
| + } |
| +} |
| + |
| +} // namespace vr_shell |