blob: e46de306e74a7a66018f385ceaddd6163a366567 [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_COLOR_ATTACHMENT_EXT 0x958E
#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586
namespace gpu {
ExternalVkImageGlRepresentation::ExternalVkImageGlRepresentation(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
gles2::Texture* texture,
GLuint texture_service_id)
: SharedImageRepresentationGLTexture(manager, backing, tracker),
texture_(texture),
texture_service_id_(texture_service_id) {}
ExternalVkImageGlRepresentation::~ExternalVkImageGlRepresentation() {}
gles2::Texture* ExternalVkImageGlRepresentation::GetTexture() {
return texture_;
}
bool ExternalVkImageGlRepresentation::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);
std::vector<SemaphoreHandle> handles;
if (!backing_impl()->BeginAccess(readonly, &handles))
return false;
for (auto& handle : handles) {
GLuint gl_semaphore = ImportVkSemaphoreIntoGL(std::move(handle));
if (gl_semaphore) {
GLenum src_layout = GL_LAYOUT_COLOR_ATTACHMENT_EXT;
api()->glWaitSemaphoreEXTFn(gl_semaphore, 0, nullptr, 1,
&texture_service_id_, &src_layout);
api()->glDeleteSemaphoresEXTFn(1, &gl_semaphore);
}
}
current_access_mode_ = mode;
return true;
}
void ExternalVkImageGlRepresentation::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_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;
}
SemaphoreHandle 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();
GLuint 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;
}
GLenum dst_layout = GL_LAYOUT_COLOR_ATTACHMENT_EXT;
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));
}
GLuint ExternalVkImageGlRepresentation::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
}
} // namespace gpu