blob: 9b1f7cdc53f1580cd01dc1d9a6504164101ec7a5 [file] [log] [blame] [edit]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/webxr/mailbox_to_surface_bridge_impl.h"
#include <memory>
#include <string>
#include <utility>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/system/sys_info.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/common/gpu/context_provider.h"
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "gpu/ipc/common/gpu_surface_tracker.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/gpu_memory_buffer_handle.h"
#include "ui/gl/android/surface_texture.h"
namespace webxr {
MailboxToSurfaceBridgeImpl::MailboxToSurfaceBridgeImpl() {
DVLOG(1) << __func__;
}
MailboxToSurfaceBridgeImpl::~MailboxToSurfaceBridgeImpl() {
DVLOG(1) << __func__;
}
bool MailboxToSurfaceBridgeImpl::IsConnected() {
return context_provider_ && gl_ && context_support_;
}
void MailboxToSurfaceBridgeImpl::OnContextAvailableOnUiThread(
scoped_refptr<viz::ContextProvider> provider) {
DVLOG(1) << __func__;
// Must save a reference to the viz::ContextProvider to keep it alive,
// otherwise the GL context created from it becomes invalid on its
// destruction.
context_provider_ = std::move(provider);
DCHECK(on_context_bound_);
gl_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&MailboxToSurfaceBridgeImpl::BindContextProviderToCurrentThread,
base::Unretained(this)));
}
void MailboxToSurfaceBridgeImpl::BindContextProviderToCurrentThread() {
auto result = context_provider_->BindToCurrentSequence();
if (result != gpu::ContextResult::kSuccess) {
DLOG(ERROR) << "Failed to init viz::ContextProvider";
return;
}
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;
}
DVLOG(1) << __func__ << ": Context ready";
if (on_context_bound_) {
std::move(on_context_bound_).Run();
}
}
void MailboxToSurfaceBridgeImpl::CreateAndBindContextProvider(
base::OnceClosure on_bound_callback) {
gl_thread_task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
on_context_bound_ = std::move(on_bound_callback);
// The callback to run in this thread. It is necessary to keep |surface| alive
// until the context becomes available. So pass it on to the callback, so that
// it stays alive, and is destroyed on the same thread once done.
auto callback =
base::BindOnce(&MailboxToSurfaceBridgeImpl::OnContextAvailableOnUiThread,
weak_ptr_factory_.GetWeakPtr());
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(
[](content::Compositor::ContextProviderCallback callback) {
content::Compositor::CreateContextProvider(
gpu::SharedMemoryLimits::ForMailboxContext(),
std::move(callback));
},
std::move(callback)));
}
void MailboxToSurfaceBridgeImpl::GenSyncToken(gpu::SyncToken* out_sync_token) {
TRACE_EVENT0("gpu", "GenSyncToken");
DCHECK(IsConnected());
gl_->GenSyncTokenCHROMIUM(out_sync_token->GetData());
}
void MailboxToSurfaceBridgeImpl::WaitSyncToken(
const gpu::SyncToken& sync_token) {
TRACE_EVENT0("gpu", "WaitSyncToken");
DCHECK(IsConnected());
gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
}
void MailboxToSurfaceBridgeImpl::WaitForClientGpuFence(
gfx::GpuFence& gpu_fence) {
TRACE_EVENT0("gpu", "WaitForClientGpuFence");
DCHECK(IsConnected());
GLuint id = gl_->CreateClientGpuFenceCHROMIUM(gpu_fence.AsClientGpuFence());
gl_->WaitGpuFenceCHROMIUM(id);
gl_->DestroyGpuFenceCHROMIUM(id);
}
void MailboxToSurfaceBridgeImpl::CreateGpuFence(
const gpu::SyncToken& sync_token,
base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)> callback) {
TRACE_EVENT0("gpu", "CreateGpuFence");
DCHECK(IsConnected());
gl_->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
GLuint id = gl_->CreateGpuFenceCHROMIUM();
context_support_->GetGpuFence(id, std::move(callback));
gl_->DestroyGpuFenceCHROMIUM(id);
}
scoped_refptr<gpu::ClientSharedImage>
MailboxToSurfaceBridgeImpl::CreateSharedImage(
gfx::GpuMemoryBufferHandle buffer_handle,
gfx::BufferFormat buffer_format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
gpu::SharedImageUsageSet usage,
gpu::SyncToken& sync_token) {
TRACE_EVENT0("gpu", "CreateSharedImage");
DCHECK(IsConnected());
auto* sii = context_provider_->SharedImageInterface();
DCHECK(sii);
CHECK_EQ(buffer_format, gfx::BufferFormat::RGBA_8888);
auto client_shared_image = sii->CreateSharedImage(
{viz::SinglePlaneFormat::kRGBA_8888, size, color_space, usage,
"WebXrMailboxToSurfaceBridge"},
std::move(buffer_handle));
CHECK(client_shared_image);
sync_token = sii->GenVerifiedSyncToken();
DCHECK(client_shared_image->GetTextureTarget() == GL_TEXTURE_2D);
return client_shared_image;
}
void MailboxToSurfaceBridgeImpl::DestroySharedImage(
const gpu::SyncToken& sync_token,
scoped_refptr<gpu::ClientSharedImage> shared_image) {
TRACE_EVENT0("gpu", "CreateSharedImage");
DCHECK(IsConnected());
DCHECK(shared_image);
auto* sii = context_provider_->SharedImageInterface();
DCHECK(sii);
sii->DestroySharedImage(sync_token, std::move(shared_image));
}
std::unique_ptr<device::MailboxToSurfaceBridge>
MailboxToSurfaceBridgeFactoryImpl::Create() const {
return std::make_unique<MailboxToSurfaceBridgeImpl>();
}
} // namespace webxr