blob: 58f60deabe23a9eaba2494fdba5de4170498a7f4 [file] [log] [blame]
// Copyright 2019 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 "gpu/command_buffer/service/external_vk_image_gl_representation.h"
#include <utility>
#include <vector>
#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_implementation.h"
#define GL_LAYOUT_GENERAL_EXT 0x958D
#define GL_LAYOUT_COLOR_ATTACHMENT_EXT 0x958E
#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F
#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590
#define GL_LAYOUT_SHADER_READ_ONLY_EXT 0x9591
#define GL_LAYOUT_TRANSFER_SRC_EXT 0x9592
#define GL_LAYOUT_TRANSFER_DST_EXT 0x9593
#define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530
#define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531
#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586
namespace gpu {
namespace {
GLenum ToGLImageLayout(VkImageLayout layout) {
switch (layout) {
case VK_IMAGE_LAYOUT_UNDEFINED:
return GL_NONE;
case VK_IMAGE_LAYOUT_GENERAL:
return GL_LAYOUT_GENERAL_EXT;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
return GL_LAYOUT_COLOR_ATTACHMENT_EXT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
return GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
return GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
return GL_LAYOUT_SHADER_READ_ONLY_EXT;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
return GL_LAYOUT_TRANSFER_SRC_EXT;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
return GL_LAYOUT_TRANSFER_DST_EXT;
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR:
return GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT;
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR:
return GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT;
default:
NOTREACHED() << "Invalid image layout " << layout;
return GL_NONE;
}
}
} // namespace
ExternalVkImageGLRepresentationShared::ExternalVkImageGLRepresentationShared(
SharedImageBacking* backing,
GLuint texture_service_id)
: backing_(static_cast<ExternalVkImageBacking*>(backing)),
texture_service_id_(texture_service_id) {}
bool ExternalVkImageGLRepresentationShared::BeginAccess(GLenum mode) {
// There should not be multiple accesses in progress on the same
// representation.
if (current_access_mode_) {
LOG(ERROR) << "BeginAccess called on ExternalVkImageGLRepresentation before"
<< " the previous access ended.";
return false;
}
DCHECK(mode == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM ||
mode == GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
const bool readonly = (mode == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
if (!readonly && backing_impl()->format() == viz::ResourceFormat::BGRA_8888) {
NOTIMPLEMENTED()
<< "BeginAccess write on a BGRA_8888 backing is not supported.";
return false;
}
std::vector<SemaphoreHandle> handles;
if (!backing_impl()->BeginAccess(readonly, &handles, true /* is_gl */))
return false;
for (auto& handle : handles) {
GLuint gl_semaphore = ImportVkSemaphoreIntoGL(std::move(handle));
if (gl_semaphore) {
GrVkImageInfo info;
auto result = backing_impl()->backend_texture().getVkImageInfo(&info);
DCHECK(result);
GLenum src_layout = ToGLImageLayout(info.fImageLayout);
api()->glWaitSemaphoreEXTFn(gl_semaphore, 0, nullptr, 1,
&texture_service_id_, &src_layout);
api()->glDeleteSemaphoresEXTFn(1, &gl_semaphore);
}
}
current_access_mode_ = mode;
return true;
}
void ExternalVkImageGLRepresentationShared::EndAccess() {
if (!current_access_mode_) {
// TODO(crbug.com/933452): We should be able to handle this failure more
// gracefully rather than shutting down the whole process.
LOG(ERROR) << "EndAccess called on ExternalVkImageGLRepresentation before "
<< "BeginAccess";
return;
}
DCHECK(current_access_mode_ == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM ||
current_access_mode_ ==
GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
const bool readonly =
(current_access_mode_ == GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
current_access_mode_ = 0;
VkSemaphore semaphore = VK_NULL_HANDLE;
SemaphoreHandle semaphore_handle;
GLuint gl_semaphore = 0;
if (backing_impl()->need_sychronization()) {
semaphore =
vk_implementation()->CreateExternalSemaphore(backing_impl()->device());
if (semaphore == VK_NULL_HANDLE) {
// TODO(crbug.com/933452): We should be able to handle this failure more
// gracefully rather than shutting down the whole process.
LOG(FATAL) << "Unable to create a VkSemaphore in "
<< "ExternalVkImageGLRepresentation for synchronization with "
<< "Vulkan";
return;
}
semaphore_handle =
vk_implementation()->GetSemaphoreHandle(vk_device(), semaphore);
vkDestroySemaphore(backing_impl()->device(), semaphore, nullptr);
if (!semaphore_handle.is_valid()) {
LOG(FATAL) << "Unable to export VkSemaphore into GL in "
<< "ExternalVkImageGLRepresentation for synchronization with "
<< "Vulkan";
return;
}
SemaphoreHandle dup_semaphore_handle = semaphore_handle.Duplicate();
gl_semaphore = ImportVkSemaphoreIntoGL(std::move(dup_semaphore_handle));
if (!gl_semaphore) {
// TODO(crbug.com/933452): We should be able to semaphore_handle this
// failure more gracefully rather than shutting down the whole process.
LOG(FATAL) << "Unable to export VkSemaphore into GL in "
<< "ExternalVkImageGLRepresentation for synchronization with "
<< "Vulkan";
return;
}
}
GrVkImageInfo info;
auto result = backing_impl()->backend_texture().getVkImageInfo(&info);
DCHECK(result);
GLenum dst_layout = ToGLImageLayout(info.fImageLayout);
if (backing_impl()->need_sychronization()) {
api()->glSignalSemaphoreEXTFn(gl_semaphore, 0, nullptr, 1,
&texture_service_id_, &dst_layout);
api()->glDeleteSemaphoresEXTFn(1, &gl_semaphore);
}
backing_impl()->EndAccess(readonly, std::move(semaphore_handle),
true /* is_gl */);
}
GLuint ExternalVkImageGLRepresentationShared::ImportVkSemaphoreIntoGL(
SemaphoreHandle handle) {
if (!handle.is_valid())
return 0;
#if defined(OS_FUCHSIA)
NOTIMPLEMENTED_LOG_ONCE();
return 0;
#elif defined(OS_LINUX)
if (handle.vk_handle_type() !=
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
DLOG(ERROR) << "Importing semaphore handle of unexpected type:"
<< handle.vk_handle_type();
return 0;
}
base::ScopedFD fd = handle.TakeHandle();
gl::GLApi* api = gl::g_current_gl_context;
GLuint gl_semaphore;
api->glGenSemaphoresEXTFn(1, &gl_semaphore);
api->glImportSemaphoreFdEXTFn(gl_semaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT,
fd.release());
return gl_semaphore;
#else // !defined(OS_FUCHSIA) && !defined(OS_LINUX)
#error Unsupported OS
#endif
}
ExternalVkImageGLRepresentation::ExternalVkImageGLRepresentation(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
gles2::Texture* texture,
GLuint texture_service_id)
: SharedImageRepresentationGLTexture(manager, backing, tracker),
texture_(texture),
representation_shared_(backing, texture_service_id) {}
ExternalVkImageGLRepresentation::~ExternalVkImageGLRepresentation() {}
gles2::Texture* ExternalVkImageGLRepresentation::GetTexture() {
return texture_;
}
bool ExternalVkImageGLRepresentation::BeginAccess(GLenum mode) {
return representation_shared_.BeginAccess(mode);
}
void ExternalVkImageGLRepresentation::EndAccess() {
representation_shared_.EndAccess();
}
ExternalVkImageGLPassthroughRepresentation::
ExternalVkImageGLPassthroughRepresentation(SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
GLuint texture_service_id)
: SharedImageRepresentationGLTexturePassthrough(manager, backing, tracker),
representation_shared_(backing, texture_service_id) {}
ExternalVkImageGLPassthroughRepresentation::
~ExternalVkImageGLPassthroughRepresentation() {}
const scoped_refptr<gles2::TexturePassthrough>&
ExternalVkImageGLPassthroughRepresentation::GetTexturePassthrough() {
return representation_shared_.backing_impl()->GetTexturePassthrough();
}
bool ExternalVkImageGLPassthroughRepresentation::BeginAccess(GLenum mode) {
return representation_shared_.BeginAccess(mode);
}
void ExternalVkImageGLPassthroughRepresentation::EndAccess() {
representation_shared_.EndAccess();
}
} // namespace gpu