blob: 51f093c6cf898d4572242b581997876359ae7086 [file] [log] [blame]
//
// Copyright 2021 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.
//
// DisplayVkLinux.cpp:
// Implements the class methods for DisplayVkLinux.
//
#include "libANGLE/renderer/vulkan/linux/DisplayVkLinux.h"
#include "common/linux/dma_buf_utils.h"
#include "libANGLE/renderer/vulkan/linux/DeviceVkLinux.h"
#include "libANGLE/renderer/vulkan/linux/DmaBufImageSiblingVkLinux.h"
#include "libANGLE/renderer/vulkan/vk_renderer.h"
namespace rx
{
DisplayVkLinux::DisplayVkLinux(const egl::DisplayState &state)
: DisplayVk(state), mDrmFormatsInitialized(false)
{}
DeviceImpl *DisplayVkLinux::createDevice()
{
return new DeviceVkLinux(this);
}
ExternalImageSiblingImpl *DisplayVkLinux::createExternalImageSibling(
const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
{
switch (target)
{
case EGL_LINUX_DMA_BUF_EXT:
ASSERT(context == nullptr);
ASSERT(buffer == nullptr);
return new DmaBufImageSiblingVkLinux(attribs);
default:
return DisplayVk::createExternalImageSibling(context, target, buffer, attribs);
}
}
// Returns the list of DRM modifiers that a VkFormat supports
std::vector<VkDrmFormatModifierPropertiesEXT> DisplayVkLinux::GetDrmModifiers(
const DisplayVk *displayVk,
VkFormat vkFormat)
{
vk::Renderer *renderer = displayVk->getRenderer();
// Query list of drm format modifiers compatible with VkFormat.
VkDrmFormatModifierPropertiesListEXT formatModifierPropertiesList = {};
formatModifierPropertiesList.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
formatModifierPropertiesList.drmFormatModifierCount = 0;
VkFormatProperties2 formatProperties = {};
formatProperties.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
formatProperties.pNext = &formatModifierPropertiesList;
vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
&formatProperties);
std::vector<VkDrmFormatModifierPropertiesEXT> formatModifierProperties(
formatModifierPropertiesList.drmFormatModifierCount);
formatModifierPropertiesList.pDrmFormatModifierProperties = formatModifierProperties.data();
vkGetPhysicalDeviceFormatProperties2(renderer->getPhysicalDevice(), vkFormat,
&formatProperties);
return formatModifierProperties;
}
// Returns true if that VkFormat has at least on format modifier in its properties
bool DisplayVkLinux::SupportsDrmModifiers(VkPhysicalDevice device, VkFormat vkFormat)
{
// Query list of drm format modifiers compatible with VkFormat.
VkDrmFormatModifierPropertiesListEXT formatModifierPropertiesList = {};
formatModifierPropertiesList.sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT;
formatModifierPropertiesList.drmFormatModifierCount = 0;
VkFormatProperties2 formatProperties = {};
formatProperties.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
formatProperties.pNext = &formatModifierPropertiesList;
vkGetPhysicalDeviceFormatProperties2(device, vkFormat, &formatProperties);
// If there is at least one DRM format modifier, it is supported
return formatModifierPropertiesList.drmFormatModifierCount > 0;
}
// Returns a list of VkFormats supporting at least one DRM format modifier
std::vector<VkFormat> DisplayVkLinux::GetVkFormatsWithDrmModifiers(const vk::Renderer *renderer)
{
std::vector<VkFormat> vkFormats;
for (size_t formatIndex = 1; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
{
const vk::Format &format = renderer->getFormat(angle::FormatID(formatIndex));
VkFormat vkFormat =
format.getActualImageVkFormat(renderer, rx::vk::ImageAccess::Renderable);
if (vkFormat != VK_FORMAT_UNDEFINED &&
SupportsDrmModifiers(renderer->getPhysicalDevice(), vkFormat))
{
vkFormats.push_back(vkFormat);
}
}
return vkFormats;
}
// Returns a list of supported DRM formats
std::vector<EGLint> DisplayVkLinux::GetDrmFormats(const vk::Renderer *renderer)
{
std::unordered_set<EGLint> drmFormatsSet;
for (VkFormat vkFormat : GetVkFormatsWithDrmModifiers(renderer))
{
std::vector<EGLint> drmFormats = angle::VkFormatToDrmFourCCFormat(vkFormat);
for (EGLint drmFormat : drmFormats)
{
drmFormatsSet.insert(drmFormat);
}
}
std::vector<EGLint> drmFormats;
std::copy(std::begin(drmFormatsSet), std::end(drmFormatsSet), std::back_inserter(drmFormats));
return drmFormats;
}
bool DisplayVkLinux::supportsDmaBufFormat(EGLint format) const
{
return std::find(std::begin(mDrmFormats), std::end(mDrmFormats), format) !=
std::end(mDrmFormats);
}
egl::Error DisplayVkLinux::queryDmaBufFormats(EGLint maxFormats,
EGLint *formats,
EGLint *numFormats)
{
if (!mDrmFormatsInitialized)
{
mDrmFormats = GetDrmFormats(getRenderer());
mDrmFormatsInitialized = true;
}
EGLint formatsSize = static_cast<EGLint>(mDrmFormats.size());
*numFormats = formatsSize;
if (maxFormats > 0)
{
// Do not copy data beyond the limits of the vector
maxFormats = std::min(maxFormats, formatsSize);
std::memcpy(formats, mDrmFormats.data(), maxFormats * sizeof(EGLint));
}
return egl::NoError();
}
// Queries DRM format modifiers associated to `drmFormat`.
// When `maxModifiers` is zero, it will only return the number of modifiers associated to
// `drmFormat` using the out parameter `numModifiers`. When `maxModifiers` is greater than zero, it
// will put that number of DRM format modifiers into the out parameter `modifiers`.
egl::Error DisplayVkLinux::queryDmaBufModifiers(EGLint drmFormat,
EGLint maxModifiers,
EGLuint64KHR *modifiers,
EGLBoolean *externalOnly,
EGLint *numModifiers)
{
// A DRM format may correspond to multiple Vulkan formats
std::vector<VkFormat> vkFormats = angle::DrmFourCCFormatToVkFormats(drmFormat);
std::vector<EGLuint64KHR> drmModifiers;
// Collect DRM format modifiers common to all those Vulkan formats
for (size_t i = 0; i < vkFormats.size(); ++i)
{
VkFormat vkFmt = vkFormats[i];
std::vector<VkDrmFormatModifierPropertiesEXT> vkDrmMods = GetDrmModifiers(this, vkFmt);
std::vector<EGLuint64KHR> drmMods(vkDrmMods.size());
std::transform(std::begin(vkDrmMods), std::end(vkDrmMods), std::begin(drmMods),
[](VkDrmFormatModifierPropertiesEXT props) {
return static_cast<EGLuint64KHR>(props.drmFormatModifier);
});
std::sort(std::begin(drmMods), std::end(drmMods));
if (i == 0)
{
// Just take the modifiers for the first format
drmModifiers = drmMods;
}
else
{
// Intersect the modifiers of all the other associated Vulkan formats
std::vector<EGLuint64KHR> prevMods = drmModifiers;
drmModifiers.clear();
std::set_intersection(std::begin(drmMods), std::end(drmMods), std::begin(prevMods),
std::end(prevMods), std::back_inserter(drmModifiers));
}
}
EGLint drmModifiersSize = static_cast<EGLint>(drmModifiers.size());
*numModifiers = drmModifiersSize;
if (maxModifiers > 0)
{
maxModifiers = std::min(maxModifiers, drmModifiersSize);
std::memcpy(modifiers, drmModifiers.data(), maxModifiers * sizeof(drmModifiers[0]));
}
return egl::NoError();
}
} // namespace rx