| // Copyright 2020 The Chromium Authors | |
| // 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_semaphore.h" | |
| #include "base/functional/bind.h" | |
| #include "base/logging.h" | |
| #include "build/build_config.h" | |
| #include "gpu/command_buffer/service/vulkan_context_provider.h" | |
| #include "gpu/vulkan/vulkan_device_queue.h" | |
| #include "gpu/vulkan/vulkan_function_pointers.h" | |
| #include "gpu/vulkan/vulkan_implementation.h" | |
| #include "gpu/vulkan/vulkan_util.h" | |
| #include "ui/gl/gl_bindings.h" | |
| #define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586 | |
| #define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT 0x9587 | |
| #define GL_HANDLE_TYPE_ZIRCON_VMO_ANGLE 0x93AE | |
| #define GL_HANDLE_TYPE_ZIRCON_EVENT_ANGLE 0x93AF | |
| namespace gpu { | |
| namespace { | |
| GLuint ImportSemaphoreHandleToGLSemaphore(SemaphoreHandle handle) { | |
| if (!handle.is_valid()) | |
| return 0; | |
| #if BUILDFLAG(IS_POSIX) | |
| 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; | |
| #elif BUILDFLAG(IS_WIN) | |
| if (handle.vk_handle_type() != | |
| VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) { | |
| DLOG(ERROR) << "Importing semaphore handle of unexpected type:" | |
| << handle.vk_handle_type(); | |
| return 0; | |
| } | |
| auto win32_handle = handle.TakeHandle(); | |
| gl::GLApi* api = gl::g_current_gl_context; | |
| GLuint gl_semaphore; | |
| api->glGenSemaphoresEXTFn(1, &gl_semaphore); | |
| api->glImportSemaphoreWin32HandleEXTFn( | |
| gl_semaphore, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, win32_handle.Take()); | |
| return gl_semaphore; | |
| #elif BUILDFLAG(IS_FUCHSIA) | |
| if (handle.vk_handle_type() != | |
| VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_ZIRCON_EVENT_BIT_FUCHSIA) { | |
| DLOG(ERROR) << "Importing semaphore handle of unexpected type:" | |
| << handle.vk_handle_type(); | |
| return 0; | |
| } | |
| zx::event event = handle.TakeHandle(); | |
| gl::GLApi* api = gl::g_current_gl_context; | |
| GLuint gl_semaphore; | |
| api->glGenSemaphoresEXTFn(1, &gl_semaphore); | |
| api->glImportSemaphoreZirconHandleANGLEFn( | |
| gl_semaphore, GL_HANDLE_TYPE_ZIRCON_EVENT_ANGLE, event.release()); | |
| return gl_semaphore; | |
| #else | |
| #error Unsupported OS | |
| #endif | |
| } | |
| } // namespace | |
| // static | |
| ExternalSemaphore ExternalSemaphore::Create( | |
| VulkanContextProvider* context_provider) { | |
| VkDevice device = context_provider->GetDeviceQueue()->GetVulkanDevice(); | |
| VkSemaphore semaphore = CreateVkOpaqueExternalSemaphore(device); | |
| if (semaphore == VK_NULL_HANDLE) | |
| return {}; | |
| auto handle = ExportVkOpaqueExternalSemaphore(device, semaphore); | |
| if (!handle.is_valid()) { | |
| vkDestroySemaphore(device, semaphore, /*pAllocator=*/nullptr); | |
| return {}; | |
| } | |
| return ExternalSemaphore(base::PassKey<ExternalSemaphore>(), context_provider, | |
| semaphore, std::move(handle)); | |
| } | |
| // static | |
| ExternalSemaphore ExternalSemaphore::CreateFromHandle( | |
| VulkanContextProvider* context_provider, | |
| SemaphoreHandle handle) { | |
| if (!handle.is_valid()) | |
| return {}; | |
| auto* implementation = context_provider->GetVulkanImplementation(); | |
| VkDevice device = context_provider->GetDeviceQueue()->GetVulkanDevice(); | |
| VkSemaphore semaphore = | |
| implementation->ImportSemaphoreHandle(device, handle.Duplicate()); | |
| if (semaphore == VK_NULL_HANDLE) | |
| return {}; | |
| return ExternalSemaphore(base::PassKey<ExternalSemaphore>(), context_provider, | |
| semaphore, std::move(handle)); | |
| } | |
| ExternalSemaphore::ExternalSemaphore() = default; | |
| ExternalSemaphore::ExternalSemaphore(ExternalSemaphore&& other) { | |
| *this = std::move(other); | |
| } | |
| ExternalSemaphore::ExternalSemaphore(base::PassKey<ExternalSemaphore>, | |
| VulkanContextProvider* context_provider, | |
| VkSemaphore semaphore, | |
| SemaphoreHandle handle) | |
| : context_provider_(context_provider), | |
| semaphore_(semaphore), | |
| handle_(std::move(handle)) {} | |
| ExternalSemaphore::~ExternalSemaphore() { | |
| Reset(); | |
| } | |
| ExternalSemaphore& ExternalSemaphore::operator=(ExternalSemaphore&& other) { | |
| Reset(); | |
| std::swap(context_provider_, other.context_provider_); | |
| std::swap(semaphore_, other.semaphore_); | |
| std::swap(handle_, other.handle_); | |
| std::swap(gl_semaphore_, other.gl_semaphore_); | |
| return *this; | |
| } | |
| void ExternalSemaphore::Reset() { | |
| if (semaphore_ != VK_NULL_HANDLE) { | |
| DCHECK(context_provider_); | |
| VkDevice device = context_provider_->GetDeviceQueue()->GetVulkanDevice(); | |
| vkDestroySemaphore(device, semaphore_, /*pAllocator=*/nullptr); | |
| } | |
| if (gl_semaphore_ != 0) { | |
| // We assume there is always one GL context current. If there isn't a | |
| // GL context current, we assume the last GL context is destroyed, in that | |
| // case, we will skip glDeleteSemaphoresEXT(). | |
| if (gl::g_current_gl_driver) { | |
| gl::GLApi* const api = gl::g_current_gl_context; | |
| api->glDeleteSemaphoresEXTFn(1, &gl_semaphore_); | |
| } | |
| } | |
| context_provider_ = nullptr; | |
| semaphore_ = VK_NULL_HANDLE; | |
| gl_semaphore_ = 0; | |
| handle_ = {}; | |
| } | |
| unsigned int ExternalSemaphore::GetGLSemaphore() { | |
| DCHECK(handle_.is_valid()); | |
| if (gl_semaphore_ == 0) { | |
| gl_semaphore_ = ImportSemaphoreHandleToGLSemaphore(handle_.Duplicate()); | |
| } | |
| return gl_semaphore_; | |
| } | |
| VkSemaphore ExternalSemaphore::GetVkSemaphore() { | |
| DCHECK(handle_.is_valid()); | |
| if (semaphore_ == VK_NULL_HANDLE) { | |
| auto* implementation = context_provider_->GetVulkanImplementation(); | |
| VkDevice device = context_provider_->GetDeviceQueue()->GetVulkanDevice(); | |
| semaphore_ = | |
| implementation->ImportSemaphoreHandle(device, handle_.Duplicate()); | |
| } | |
| return semaphore_; | |
| } | |
| SemaphoreHandle ExternalSemaphore::TakeSemaphoreHandle() { | |
| SemaphoreHandle handle = std::move(handle_); | |
| DCHECK(!handle_.is_valid()); | |
| Reset(); | |
| return handle; | |
| } | |
| } // namespace gpu |