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 @@
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/browser_thread.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/common/mailbox.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/common/gpu_memory_buffer_impl_android_hardware_buffer.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"
......@@ -152,12 +153,12 @@ MailboxToSurfaceBridge::~MailboxToSurfaceBridge() {
DVLOG(1) << __FUNCTION__;
}
bool MailboxToSurfaceBridge::IsReady() {
return context_provider_ && gl_;
bool MailboxToSurfaceBridge::IsConnected() {
return context_provider_ && gl_ && context_support_;
}
bool MailboxToSurfaceBridge::IsGpuWorkaroundEnabled(int32_t workaround) {
DCHECK(IsReady());
DCHECK(IsConnected());
return context_provider_->GetGpuFeatureInfo().IsWorkaroundEnabled(workaround);
}
......@@ -178,13 +179,19 @@ void MailboxToSurfaceBridge::OnContextAvailable(
}
gl_ = context_provider_->ContextGL();
context_support_ = context_provider_->ContextSupport();
if (!gl_) {
DLOG(ERROR) << "Did not get a GL context";
return;
}
if (!context_support_) {
DLOG(ERROR) << "Did not get a ContextSupport";
return;
}
InitializeRenderer();
DVLOG(1) << __FUNCTION__ << ": Context ready";
if (on_initialized_) {
base::ResetAndReturn(&on_initialized_).Run();
}
......@@ -256,7 +263,7 @@ void MailboxToSurfaceBridge::CreateSurface(
}
void MailboxToSurfaceBridge::ResizeSurface(int width, int height) {
if (!IsReady()) {
if (!IsConnected()) {
// We're not initialized yet, save the requested size for later.
needs_resize_ = true;
resize_width_ = width;
......@@ -271,13 +278,14 @@ void MailboxToSurfaceBridge::ResizeSurface(int width, int height) {
bool MailboxToSurfaceBridge::CopyMailboxToSurfaceAndSwap(
const gpu::MailboxHolder& mailbox) {
if (!IsReady()) {
if (!IsConnected()) {
// 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. TODO(klausw): change the caller to defer this until we are ready.
return false;
}
TRACE_EVENT0("gpu", __FUNCTION__);
if (needs_resize_) {
ResizeSurface(resize_width_, resize_height_);
needs_resize_ = false;
......@@ -290,6 +298,97 @@ bool MailboxToSurfaceBridge::CopyMailboxToSurfaceAndSwap(
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() {
gl_ = nullptr;
context_provider_ = nullptr;
......@@ -370,7 +469,7 @@ void MailboxToSurfaceBridge::InitializeRenderer() {
}
void MailboxToSurfaceBridge::DrawQuad(unsigned int texture_handle) {
DCHECK(IsReady());
DCHECK(IsConnected());
// We're redrawing over the entire viewport, but it's generally more
// efficient on mobile tiling GPUs to clear anyway as a hint that
......
......@@ -6,15 +6,26 @@
#define CHROME_BROWSER_ANDROID_VR_MAILBOX_TO_SURFACE_BRIDGE_H_
#include "base/callback.h"
#include "base/macros.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 {
class ScopedJavaSurface;
class SurfaceTexture;
} // namespace gl
namespace gfx {
struct GpuMemoryBufferHandle;
}
namespace gpu {
class ContextSupport;
struct Mailbox;
struct MailboxHolder;
struct SyncToken;
namespace gles2 {
class GLES2Interface;
}
......@@ -33,7 +44,7 @@ class MailboxToSurfaceBridge {
// Returns true if the GPU process connection is established and ready to use.
// 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"
// is active. Requires initialization to be complete.
......@@ -48,6 +59,40 @@ class MailboxToSurfaceBridge {
// won't get a new frame on the SurfaceTexture.
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:
void OnContextAvailable(std::unique_ptr<gl::ScopedJavaSurface> surface,
scoped_refptr<viz::ContextProvider>);
......@@ -57,6 +102,7 @@ class MailboxToSurfaceBridge {
scoped_refptr<viz::ContextProvider> context_provider_;
gpu::gles2::GLES2Interface* gl_ = nullptr;
gpu::ContextSupport* context_support_ = nullptr;
int surface_handle_ = 0;
base::OnceClosure on_initialized_;
......@@ -68,6 +114,8 @@ class MailboxToSurfaceBridge {
// Must be last.
base::WeakPtrFactory<MailboxToSurfaceBridge> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(MailboxToSurfaceBridge);
};
} // 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