blob: fab2c523ed7da2b34164cae42011d4dcad035d22 [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DeviceVk.cpp:
// Implements the class methods for DeviceVk.
//
#include "libANGLE/renderer/vulkan/DeviceVk.h"
#include <stdint.h>
#include "common/debug.h"
#include "common/vulkan/vulkan_icd.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
namespace rx
{
namespace
{
DeviceVk *gDevice = nullptr;
class ANGLE_NO_DISCARD ScopedEnv : public angle::vk::ScopedVkLoaderEnvironment
{
public:
ScopedEnv()
: angle::vk::ScopedVkLoaderEnvironment(
gDevice ? gDevice->getRenderer()->getEnableValidationLayers() : false,
gDevice ? gDevice->getRenderer()->getEnabledICD() : angle::vk::ICD::Default)
{
if (!gDevice)
{
WARN() << "No DeviceVk instance.";
}
}
};
} // namespace
DeviceVk::DeviceVk() = default;
DeviceVk::~DeviceVk()
{
if (gDevice == this)
{
gDevice = nullptr;
}
}
egl::Error DeviceVk::initialize()
{
return egl::NoError();
}
egl::Error DeviceVk::getAttribute(const egl::Display *display, EGLint attribute, void **outValue)
{
RendererVk *renderer =
static_cast<rx::DisplayVk *>(display->getImplementation())->getRenderer();
ASSERT(mRenderer == nullptr || mRenderer == renderer);
mRenderer = renderer;
switch (attribute)
{
case EGL_VULKAN_VERSION_ANGLE:
{
auto version = static_cast<intptr_t>(mRenderer->getApiVersion());
*outValue = reinterpret_cast<void *>(version);
return egl::NoError();
}
case EGL_VULKAN_INSTANCE_ANGLE:
{
*outValue = mRenderer->getInstance();
return egl::NoError();
}
case EGL_VULKAN_DEVICE_ANGLE:
{
*outValue = mRenderer->getDevice();
return egl::NoError();
}
case EGL_VULKAN_PHYSICAL_DEVICE_ANGLE:
{
*outValue = mRenderer->getPhysicalDevice();
return egl::NoError();
}
case EGL_VULKAN_QUEUE_ANGLE:
{
// egl::ContextPriority::Medium is the default context priority.
*outValue = mRenderer->getQueue(egl::ContextPriority::Medium);
return egl::NoError();
}
case EGL_VULKAN_QUEUE_FAMILIY_INDEX_ANGLE:
{
intptr_t index = static_cast<intptr_t>(mRenderer->getQueueFamilyIndex());
*outValue = reinterpret_cast<void *>(index);
return egl::NoError();
}
case EGL_VULKAN_DEVICE_EXTENSIONS_ANGLE:
{
char **extensions = const_cast<char **>(mRenderer->getEnabledDeviceExtensions().data());
*outValue = reinterpret_cast<void *>(extensions);
return egl::NoError();
}
case EGL_VULKAN_INSTANCE_EXTENSIONS_ANGLE:
{
char **extensions =
const_cast<char **>(mRenderer->getEnabledInstanceExtensions().data());
*outValue = reinterpret_cast<void *>(extensions);
return egl::NoError();
}
case EGL_VULKAN_FEATURES_ANGLE:
{
const auto *features = &mRenderer->getEnabledFeatures();
*outValue = const_cast<void *>(reinterpret_cast<const void *>(features));
return egl::NoError();
}
case EGL_VULKAN_GET_INSTANCE_PROC_ADDR:
{
*outValue = reinterpret_cast<void *>(DeviceVk::WrappedGetInstanceProcAddr);
ASSERT(!gDevice || gDevice == this);
gDevice = this;
return egl::NoError();
}
default:
return egl::EglBadAccess();
}
}
EGLint DeviceVk::getType()
{
return EGL_VULKAN_DEVICE_ANGLE;
}
void DeviceVk::generateExtensions(egl::DeviceExtensions *outExtensions) const
{
outExtensions->deviceVulkan = true;
}
// static
VKAPI_ATTR VkResult VKAPI_CALL
DeviceVk::WrappedCreateInstance(const VkInstanceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkInstance *pInstance)
{
ScopedEnv scopedEnv;
return vkCreateInstance(pCreateInfo, pAllocator, pInstance);
}
// static
VKAPI_ATTR VkResult VKAPI_CALL
DeviceVk::WrappedEnumerateInstanceExtensionProperties(const char *pLayerName,
uint32_t *pPropertyCount,
VkExtensionProperties *pProperties)
{
ScopedEnv scopedEnv;
return vkEnumerateInstanceExtensionProperties(pLayerName, pPropertyCount, pProperties);
}
// static
VKAPI_ATTR VkResult VKAPI_CALL
DeviceVk::WrappedEnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
VkLayerProperties *pProperties)
{
ScopedEnv scopedEnv;
return vkEnumerateInstanceLayerProperties(pPropertyCount, pProperties);
}
// static
VKAPI_ATTR VkResult VKAPI_CALL DeviceVk::WrappedEnumerateInstanceVersion(uint32_t *pApiVersion)
{
ScopedEnv scopedEnv;
return vkEnumerateInstanceVersion(pApiVersion);
}
// static
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL DeviceVk::WrappedGetInstanceProcAddr(VkInstance instance,
const char *pName)
{
if (!pName || pName[0] != 'v' || pName[1] != 'k')
{
return nullptr;
}
if (instance != VK_NULL_HANDLE)
{
return vkGetInstanceProcAddr(instance, pName);
}
if (!strcmp(pName, "vkCreateInstance"))
{
return reinterpret_cast<PFN_vkVoidFunction>(DeviceVk::WrappedCreateInstance);
}
if (!strcmp(pName, "vkEnumerateInstanceExtensionProperties"))
{
return reinterpret_cast<PFN_vkVoidFunction>(
DeviceVk::WrappedEnumerateInstanceExtensionProperties);
}
if (!strcmp(pName, "vkEnumerateInstanceLayerProperties"))
{
return reinterpret_cast<PFN_vkVoidFunction>(
DeviceVk::WrappedEnumerateInstanceLayerProperties);
}
if (!strcmp(pName, "vkEnumerateInstanceVersion"))
{
if (!vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion"))
{
// Vulkan 1.0 doesn't have vkEnumerateInstanceVersion.
return nullptr;
}
return reinterpret_cast<PFN_vkVoidFunction>(DeviceVk::WrappedEnumerateInstanceVersion);
}
if (!strcmp(pName, "vkGetInstanceProcAddr"))
{
return reinterpret_cast<PFN_vkVoidFunction>(DeviceVk::WrappedGetInstanceProcAddr);
}
return vkGetInstanceProcAddr(instance, pName);
}
} // namespace rx