Commit 3db61e79 authored by Klaus Weidner's avatar Klaus Weidner Committed by Commit Bot

Add mailbox_to_surface_bridge GpuMemoryBuffer APIs

This supports using GpuMemoryBuffer to share images between a native
GL context and a command buffer context in the GPU process.

BUG=761436

Change-Id: Iae0668e055fa1ed181bc8ff640cc290c15bb4906
Reviewed-on: https://chromium-review.googlesource.com/986663
Commit-Queue: Klaus Weidner <klausw@chromium.org>
Reviewed-by: default avatarIan Vollick <vollick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#546995}
parent 8255d029
...@@ -14,11 +14,12 @@ ...@@ -14,11 +14,12 @@
#include "content/public/browser/android/compositor.h" #include "content/public/browser/android/compositor.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "gpu/GLES2/gl2extchromium.h" #include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/mailbox_holder.h" #include "gpu/command_buffer/common/mailbox_holder.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/ipc/client/gpu_channel_host.h" #include "gpu/ipc/client/gpu_channel_host.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h"
#include "gpu/ipc/common/gpu_surface_tracker.h" #include "gpu/ipc/common/gpu_surface_tracker.h"
#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h" #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
#include "ui/gl/android/surface_texture.h" #include "ui/gl/android/surface_texture.h"
...@@ -152,12 +153,12 @@ MailboxToSurfaceBridge::~MailboxToSurfaceBridge() { ...@@ -152,12 +153,12 @@ MailboxToSurfaceBridge::~MailboxToSurfaceBridge() {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
} }
bool MailboxToSurfaceBridge::IsReady() { bool MailboxToSurfaceBridge::IsConnected() {
return context_provider_ && gl_; return context_provider_ && gl_ && context_support_;
} }
bool MailboxToSurfaceBridge::IsGpuWorkaroundEnabled(int32_t workaround) { bool MailboxToSurfaceBridge::IsGpuWorkaroundEnabled(int32_t workaround) {
DCHECK(IsReady()); DCHECK(IsConnected());
return context_provider_->GetGpuFeatureInfo().IsWorkaroundEnabled(workaround); return context_provider_->GetGpuFeatureInfo().IsWorkaroundEnabled(workaround);
} }
...@@ -178,13 +179,19 @@ void MailboxToSurfaceBridge::OnContextAvailable( ...@@ -178,13 +179,19 @@ void MailboxToSurfaceBridge::OnContextAvailable(
} }
gl_ = context_provider_->ContextGL(); gl_ = context_provider_->ContextGL();
context_support_ = context_provider_->ContextSupport();
if (!gl_) { if (!gl_) {
DLOG(ERROR) << "Did not get a GL context"; DLOG(ERROR) << "Did not get a GL context";
return; return;
} }
if (!context_support_) {
DLOG(ERROR) << "Did not get a ContextSupport";
return;
}
InitializeRenderer(); InitializeRenderer();
DVLOG(1) << __FUNCTION__ << ": Context ready";
if (on_initialized_) { if (on_initialized_) {
base::ResetAndReturn(&on_initialized_).Run(); base::ResetAndReturn(&on_initialized_).Run();
} }
...@@ -256,7 +263,7 @@ void MailboxToSurfaceBridge::CreateSurface( ...@@ -256,7 +263,7 @@ void MailboxToSurfaceBridge::CreateSurface(
} }
void MailboxToSurfaceBridge::ResizeSurface(int width, int height) { void MailboxToSurfaceBridge::ResizeSurface(int width, int height) {
if (!IsReady()) { if (!IsConnected()) {
// We're not initialized yet, save the requested size for later. // We're not initialized yet, save the requested size for later.
needs_resize_ = true; needs_resize_ = true;
resize_width_ = width; resize_width_ = width;
...@@ -271,13 +278,14 @@ void MailboxToSurfaceBridge::ResizeSurface(int width, int height) { ...@@ -271,13 +278,14 @@ void MailboxToSurfaceBridge::ResizeSurface(int width, int height) {
bool MailboxToSurfaceBridge::CopyMailboxToSurfaceAndSwap( bool MailboxToSurfaceBridge::CopyMailboxToSurfaceAndSwap(
const gpu::MailboxHolder& mailbox) { const gpu::MailboxHolder& mailbox) {
if (!IsReady()) { if (!IsConnected()) {
// We may not have a context yet, i.e. due to surface initialization // 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 // being incomplete. This is not an error, but we obviously can't draw
// yet. TODO(klausw): change the caller to defer this until we are ready. // yet. TODO(klausw): change the caller to defer this until we are ready.
return false; return false;
} }
TRACE_EVENT0("gpu", __FUNCTION__);
if (needs_resize_) { if (needs_resize_) {
ResizeSurface(resize_width_, resize_height_); ResizeSurface(resize_width_, resize_height_);
needs_resize_ = false; needs_resize_ = false;
...@@ -290,6 +298,97 @@ bool MailboxToSurfaceBridge::CopyMailboxToSurfaceAndSwap( ...@@ -290,6 +298,97 @@ bool MailboxToSurfaceBridge::CopyMailboxToSurfaceAndSwap(
return true; return true;
} }
void MailboxToSurfaceBridge::GenSyncToken(gpu::SyncToken* out_sync_token) {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
gl_->GenSyncTokenCHROMIUM(out_sync_token->GetData());
}
void MailboxToSurfaceBridge::WaitForClientGpuFence(gfx::GpuFence* gpu_fence) {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
GLuint id = gl_->CreateClientGpuFenceCHROMIUM(gpu_fence->AsClientGpuFence());
gl_->WaitGpuFenceCHROMIUM(id);
gl_->DestroyGpuFenceCHROMIUM(id);
}
void MailboxToSurfaceBridge::CreateGpuFence(
const gpu::SyncToken& sync_token,
base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)> callback) {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
GLuint id = gl_->CreateGpuFenceCHROMIUM();
context_support_->GetGpuFence(id, std::move(callback));
gl_->DestroyGpuFenceCHROMIUM(id);
}
void MailboxToSurfaceBridge::GenerateMailbox(gpu::Mailbox& out_mailbox) {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
gl_->GenMailboxCHROMIUM(out_mailbox.name);
}
uint32_t MailboxToSurfaceBridge::CreateMailboxTexture(
const gpu::Mailbox& mailbox) {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
GLuint tex = 0;
gl_->GenTextures(1, &tex);
gl_->BindTexture(GL_TEXTURE_2D, tex);
gl_->ProduceTextureDirectCHROMIUM(tex, mailbox.name);
return tex;
}
void MailboxToSurfaceBridge::DestroyMailboxTexture(const gpu::Mailbox& mailbox,
uint32_t texture_id) {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
// Associating with texture ID 0 unbinds the previous binding without
// creating a new one.
gl_->ProduceTextureDirectCHROMIUM(0, mailbox.name);
GLuint tex = texture_id;
gl_->DeleteTextures(1, &tex);
}
uint32_t MailboxToSurfaceBridge::BindSharedBufferImage(
const gfx::GpuMemoryBufferHandle& handle,
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
uint32_t texture_id) {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
auto buffer = gpu::GpuMemoryBufferImplAndroidHardwareBuffer::CreateFromHandle(
handle, size, format, usage,
gpu::GpuMemoryBufferImpl::DestructionCallback());
auto img = gl_->CreateImageCHROMIUM(buffer->AsClientBuffer(), size.width(),
size.height(), GL_RGBA);
gl_->BindTexture(GL_TEXTURE_2D, texture_id);
gl_->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, img);
gl_->BindTexture(GL_TEXTURE_2D, 0);
return img;
}
void MailboxToSurfaceBridge::UnbindSharedBuffer(GLuint image_id,
GLuint texture_id) {
TRACE_EVENT0("gpu", __FUNCTION__);
DCHECK(IsConnected());
gl_->BindTexture(GL_TEXTURE_2D, texture_id);
gl_->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id);
gl_->BindTexture(GL_TEXTURE_2D, 0);
gl_->DestroyImageCHROMIUM(image_id);
}
void MailboxToSurfaceBridge::DestroyContext() { void MailboxToSurfaceBridge::DestroyContext() {
gl_ = nullptr; gl_ = nullptr;
context_provider_ = nullptr; context_provider_ = nullptr;
...@@ -370,7 +469,7 @@ void MailboxToSurfaceBridge::InitializeRenderer() { ...@@ -370,7 +469,7 @@ void MailboxToSurfaceBridge::InitializeRenderer() {
} }
void MailboxToSurfaceBridge::DrawQuad(unsigned int texture_handle) { void MailboxToSurfaceBridge::DrawQuad(unsigned int texture_handle) {
DCHECK(IsReady()); DCHECK(IsConnected());
// We're redrawing over the entire viewport, but it's generally more // We're redrawing over the entire viewport, but it's generally more
// efficient on mobile tiling GPUs to clear anyway as a hint that // efficient on mobile tiling GPUs to clear anyway as a hint that
......
...@@ -6,15 +6,26 @@ ...@@ -6,15 +6,26 @@
#define CHROME_BROWSER_ANDROID_VR_MAILBOX_TO_SURFACE_BRIDGE_H_ #define CHROME_BROWSER_ANDROID_VR_MAILBOX_TO_SURFACE_BRIDGE_H_
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/gpu_fence.h"
namespace gl { namespace gl {
class ScopedJavaSurface; class ScopedJavaSurface;
class SurfaceTexture; class SurfaceTexture;
} // namespace gl } // namespace gl
namespace gfx {
struct GpuMemoryBufferHandle;
}
namespace gpu { namespace gpu {
class ContextSupport;
struct Mailbox;
struct MailboxHolder; struct MailboxHolder;
struct SyncToken;
namespace gles2 { namespace gles2 {
class GLES2Interface; class GLES2Interface;
} }
...@@ -33,7 +44,7 @@ class MailboxToSurfaceBridge { ...@@ -33,7 +44,7 @@ class MailboxToSurfaceBridge {
// Returns true if the GPU process connection is established and ready to use. // Returns true if the GPU process connection is established and ready to use.
// Equivalent to waiting for on_initialized to be called. // Equivalent to waiting for on_initialized to be called.
bool IsReady(); bool IsConnected();
// Checks if a workaround from "gpu/config/gpu_driver_bug_workaround_type.h" // Checks if a workaround from "gpu/config/gpu_driver_bug_workaround_type.h"
// is active. Requires initialization to be complete. // is active. Requires initialization to be complete.
...@@ -48,6 +59,40 @@ class MailboxToSurfaceBridge { ...@@ -48,6 +59,40 @@ class MailboxToSurfaceBridge {
// won't get a new frame on the SurfaceTexture. // won't get a new frame on the SurfaceTexture.
bool CopyMailboxToSurfaceAndSwap(const gpu::MailboxHolder& mailbox); bool CopyMailboxToSurfaceAndSwap(const gpu::MailboxHolder& mailbox);
void GenSyncToken(gpu::SyncToken* out_sync_token);
// Copies a GpuFence from the local context to the GPU process,
// and issues a server wait for it.
void WaitForClientGpuFence(gfx::GpuFence*);
// Creates a GpuFence in the GPU process after the supplied sync_token
// completes, and copies it for use in the local context. This is
// asynchronous, the callback receives the GpuFence once it's available.
void CreateGpuFence(
const gpu::SyncToken& sync_token,
base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)> callback);
void GenerateMailbox(gpu::Mailbox& out_mailbox);
// Creates a texture and binds it to the mailbox. Returns its
// texture ID in the command buffer context. (Don't use that
// in the local GL context, it's not valid there.)
uint32_t CreateMailboxTexture(const gpu::Mailbox& mailbox);
// Unbinds the texture from the mailbox and destroys it.
void DestroyMailboxTexture(const gpu::Mailbox& mailbox, uint32_t texture_id);
// Creates a GLImage from the handle's GpuMemoryBuffer and binds it to
// the supplied texture_id in the GPU process. Returns the image ID in the
// command buffer context.
uint32_t BindSharedBufferImage(const gfx::GpuMemoryBufferHandle&,
const gfx::Size& size,
gfx::BufferFormat format,
gfx::BufferUsage usage,
uint32_t texture_id);
void UnbindSharedBuffer(uint32_t image_id, uint32_t texture_id);
private: private:
void OnContextAvailable(std::unique_ptr<gl::ScopedJavaSurface> surface, void OnContextAvailable(std::unique_ptr<gl::ScopedJavaSurface> surface,
scoped_refptr<viz::ContextProvider>); scoped_refptr<viz::ContextProvider>);
...@@ -57,6 +102,7 @@ class MailboxToSurfaceBridge { ...@@ -57,6 +102,7 @@ class MailboxToSurfaceBridge {
scoped_refptr<viz::ContextProvider> context_provider_; scoped_refptr<viz::ContextProvider> context_provider_;
gpu::gles2::GLES2Interface* gl_ = nullptr; gpu::gles2::GLES2Interface* gl_ = nullptr;
gpu::ContextSupport* context_support_ = nullptr;
int surface_handle_ = 0; int surface_handle_ = 0;
base::OnceClosure on_initialized_; base::OnceClosure on_initialized_;
...@@ -68,6 +114,8 @@ class MailboxToSurfaceBridge { ...@@ -68,6 +114,8 @@ class MailboxToSurfaceBridge {
// Must be last. // Must be last.
base::WeakPtrFactory<MailboxToSurfaceBridge> weak_ptr_factory_; base::WeakPtrFactory<MailboxToSurfaceBridge> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(MailboxToSurfaceBridge);
}; };
} // namespace vr } // namespace vr
......
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