| // Copyright 2020 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_semaphore.h" |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "build/build_config.h" |
| #include "components/viz/common/gpu/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 defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) |
| 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 defined(OS_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 defined(OS_FUCHSIA) |
| if (handle.vk_handle_type() != |
| VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_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( |
| viz::VulkanContextProvider* context_provider) { |
| auto* implementation = context_provider->GetVulkanImplementation(); |
| VkDevice device = context_provider->GetDeviceQueue()->GetVulkanDevice(); |
| |
| VkSemaphore semaphore = implementation->CreateExternalSemaphore(device); |
| if (semaphore == VK_NULL_HANDLE) |
| return {}; |
| |
| auto handle = implementation->GetSemaphoreHandle(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( |
| viz::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>, |
| viz::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) { |
| auto* current_gl = gl::g_current_gl_context_tls->Get(); |
| auto* api = current_gl->Driver ? current_gl->Api : nullptr; |
| // 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 (api) |
| 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_; |
| } |
| |
| } // namespace gpu |