910e62b5创建于 1月15日历史提交
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/gl_angle_util_vulkan.h"

#include "third_party/angle/include/EGL/egl.h"
#include "third_party/angle/include/EGL/eglext.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_egl.h"

namespace gl {
namespace {
EGLDeviceEXT GetEGLDeviceFromANGLE() {
  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
  if (egl_display == EGL_NO_DISPLAY) {
    LOG(ERROR) << "Failed to retrieve EGLDisplay";
    return nullptr;
  }

  if (!gl::g_driver_egl.client_ext.b_EGL_EXT_device_query) {
    LOG(ERROR) << "EGL_EXT_device_query not supported";
    return nullptr;
  }

  intptr_t egl_device = 0;
  if (!eglQueryDisplayAttribEXT(egl_display, EGL_DEVICE_EXT, &egl_device)) {
    LOG(ERROR) << "eglQueryDisplayAttribEXT failed";
    return nullptr;
  }

  if (!egl_device) {
    LOG(ERROR) << "Failed to retrieve EGLDeviceEXT";
    return nullptr;
  }
  return reinterpret_cast<EGLDeviceEXT>(egl_device);
}

gfx::ExtensionSet ToExtensionSet(intptr_t extensions) {
  const char* const* extensions_ptr =
      reinterpret_cast<const char* const*>(extensions);
  gfx::ExtensionSet extension_set;
  // SAFETY: required from OpenGL C style API.
  for (const char* const* p = extensions_ptr; *p != nullptr;
       UNSAFE_BUFFERS(++p)) {
    extension_set.insert(*p);
  }
  return extension_set;
}

}  // namespace

VkInstance QueryVkInstanceFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return VK_NULL_HANDLE;

  intptr_t instance = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_INSTANCE_ANGLE,
                               &instance)) {
    LOG(ERROR) << "Failed to retrieve VkInstance";
    return VK_NULL_HANDLE;
  }

  return reinterpret_cast<VkInstance>(instance);
}

GL_EXPORT uint32_t QueryVkVersionFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return 0;

  intptr_t version = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_VERSION_ANGLE,
                               &version)) {
    LOG(ERROR) << "Failed to retrieve vulkan version";
    return 0;
  }

  return static_cast<uint32_t>(version);
}

VkPhysicalDevice QueryVkPhysicalDeviceFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return VK_NULL_HANDLE;

  intptr_t physical_device = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_PHYSICAL_DEVICE_ANGLE,
                               &physical_device)) {
    LOG(ERROR) << "Failed to retrieve VkPhysicalDevice";
    return VK_NULL_HANDLE;
  }

  return reinterpret_cast<VkPhysicalDevice>(physical_device);
}

VkDevice QueryVkDeviceFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return VK_NULL_HANDLE;

  intptr_t device = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_DEVICE_ANGLE, &device)) {
    LOG(ERROR) << "Failed to retrieve VkDevice";
    return VK_NULL_HANDLE;
  }

  return reinterpret_cast<VkDevice>(device);
}

VkQueue QueryVkQueueFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return VK_NULL_HANDLE;

  intptr_t queue = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_QUEUE_ANGLE, &queue)) {
    LOG(ERROR) << "Failed to retrieve VkQueue";
    return VK_NULL_HANDLE;
  }

  return reinterpret_cast<VkQueue>(queue);
}

GL_EXPORT void* QueryDisplayFromANGLE() {
  return gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
}

void LockVkQueueInANGLE(void* display) {
  DCHECK(display != EGL_NO_DISPLAY);
  eglLockVulkanQueueANGLE(display);
}

void UnlockVkQueueInANGLE(void* display) {
  DCHECK(display != EGL_NO_DISPLAY);
  eglUnlockVulkanQueueANGLE(display);
}

int QueryVkQueueFramiliyIndexFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return -1;

  intptr_t index = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_QUEUE_FAMILIY_INDEX_ANGLE,
                               &index)) {
    LOG(ERROR) << "Failed to retrieve queue familiy index";
    return -1;
  }

  return index;
}

gfx::ExtensionSet QueryVkDeviceExtensionsFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return {};

  intptr_t extensions = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_DEVICE_EXTENSIONS_ANGLE,
                               &extensions)) {
    LOG(ERROR) << "Failed to retrieve vulkan enabled device extensions";
    return {};
  }

  return ToExtensionSet(extensions);
}

gfx::ExtensionSet QueryVkInstanceExtensionsFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return {};

  intptr_t extensions = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_INSTANCE_EXTENSIONS_ANGLE,
                               &extensions)) {
    LOG(ERROR) << "Failed to retrieve vulkan enabled instance extensions";
    return {};
  }

  return ToExtensionSet(extensions);
}

const VkPhysicalDeviceFeatures2KHR* QueryVkEnabledDeviceFeaturesFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return nullptr;

  intptr_t features = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_FEATURES_ANGLE,
                               &features)) {
    LOG(ERROR) << "Failed to retrieve vulkan enabled device features";
    return nullptr;
  }

  return reinterpret_cast<const VkPhysicalDeviceFeatures2KHR*>(features);
}

PFN_vkGetInstanceProcAddr QueryVkGetInstanceProcAddrFromANGLE() {
  EGLDeviceEXT egl_device = GetEGLDeviceFromANGLE();
  if (!egl_device)
    return nullptr;

  intptr_t proc = 0;
  if (!eglQueryDeviceAttribEXT(egl_device, EGL_VULKAN_GET_INSTANCE_PROC_ADDR,
                               &proc)) {
    LOG(ERROR) << "Failed to retrieve vkGetInstanceProcAddr";
    return nullptr;
  }

  return reinterpret_cast<PFN_vkGetInstanceProcAddr>(proc);
}

}  // namespace gl