blob: 38be1616e542bd991afe54fc342d7d500c0d4541 [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.
//
// vk_format_utils:
// Helper for Vulkan format code.
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/load_functions_table.h"
#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
namespace rx
{
namespace
{
constexpr VkFormatFeatureFlags kNecessaryBitsFullSupportDepthStencil =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
constexpr VkFormatFeatureFlags kNecessaryBitsFullSupportColor =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
bool HasFormatFeatureBits(const VkFormatFeatureFlags featureBits,
const VkFormatProperties &formatProperties)
{
return IsMaskFlagSet(formatProperties.optimalTilingFeatures, featureBits);
}
void FillTextureFormatCaps(const VkFormatProperties &formatProperties,
gl::TextureCaps *outTextureCaps)
{
outTextureCaps->texturable =
HasFormatFeatureBits(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT, formatProperties);
outTextureCaps->filterable =
HasFormatFeatureBits(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT, formatProperties);
outTextureCaps->textureAttachment =
HasFormatFeatureBits(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, formatProperties) ||
HasFormatFeatureBits(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT, formatProperties);
outTextureCaps->renderbuffer = outTextureCaps->textureAttachment;
}
bool HasFullTextureFormatSupport(VkPhysicalDevice physicalDevice, VkFormat vkFormat)
{
VkFormatProperties formatProperties;
vk::GetFormatProperties(physicalDevice, vkFormat, &formatProperties);
constexpr uint32_t kBitsColor =
(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
constexpr uint32_t kBitsDepth = (VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
return HasFormatFeatureBits(kBitsColor, formatProperties) ||
HasFormatFeatureBits(kBitsDepth, formatProperties);
}
bool HasFullBufferFormatSupport(VkPhysicalDevice physicalDevice, VkFormat vkFormat)
{
VkFormatProperties formatProperties;
vk::GetFormatProperties(physicalDevice, vkFormat, &formatProperties);
return formatProperties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
}
using SupportTest = bool (*)(VkPhysicalDevice physicalDevice, VkFormat vkFormat);
template <class FormatInitInfo>
int FindSupportedFormat(VkPhysicalDevice physicalDevice,
const FormatInitInfo *info,
int numInfo,
SupportTest hasSupport)
{
ASSERT(numInfo > 1);
const int last = numInfo - 1;
for (int i = 0; i < last; ++i)
{
ASSERT(info[i].format != angle::FormatID::NONE);
if (hasSupport(physicalDevice, info[i].vkFormat))
return i;
}
// List must contain a supported item. We failed on all the others so the last one must be it.
ASSERT(info[last].format != angle::FormatID::NONE);
ASSERT(hasSupport(physicalDevice, info[last].vkFormat));
return last;
}
} // anonymous namespace
namespace vk
{
void GetFormatProperties(VkPhysicalDevice physicalDevice,
VkFormat vkFormat,
VkFormatProperties *propertiesOut)
{
// Try filling out the info from our hard coded format data, if we can't find the
// information we need, we'll make the call to Vulkan.
const VkFormatProperties &formatProperties = vk::GetMandatoryFormatSupport(vkFormat);
// Once we filled what we could with the mandatory texture caps, we verify if
// all the bits we need to satify all our checks are present, and if so we can
// skip the device call.
if (!IsMaskFlagSet(formatProperties.optimalTilingFeatures, kNecessaryBitsFullSupportColor) &&
!IsMaskFlagSet(formatProperties.optimalTilingFeatures,
kNecessaryBitsFullSupportDepthStencil))
{
vkGetPhysicalDeviceFormatProperties(physicalDevice, vkFormat, propertiesOut);
}
else
{
*propertiesOut = formatProperties;
}
}
// Format implementation.
Format::Format()
: angleFormatID(angle::FormatID::NONE),
internalFormat(GL_NONE),
textureFormatID(angle::FormatID::NONE),
vkTextureFormat(VK_FORMAT_UNDEFINED),
bufferFormatID(angle::FormatID::NONE),
vkBufferFormat(VK_FORMAT_UNDEFINED),
textureInitializerFunction(nullptr),
textureLoadFunctions()
{
}
void Format::initTextureFallback(VkPhysicalDevice physicalDevice,
const TextureFormatInitInfo *info,
int numInfo)
{
int i = FindSupportedFormat(physicalDevice, info, numInfo, HasFullTextureFormatSupport);
textureFormatID = info[i].format;
vkTextureFormat = info[i].vkFormat;
textureInitializerFunction = info[i].initializer;
}
void Format::initBufferFallback(VkPhysicalDevice physicalDevice,
const BufferFormatInitInfo *info,
int numInfo)
{
int i = FindSupportedFormat(physicalDevice, info, numInfo, HasFullBufferFormatSupport);
bufferFormatID = info[i].format;
vkBufferFormat = info[i].vkFormat;
vertexLoadFunction = info[i].vertexLoadFunction;
vertexLoadRequiresConversion = info[i].vertexLoadRequiresConversion;
}
const angle::Format &Format::textureFormat() const
{
return angle::Format::Get(textureFormatID);
}
const angle::Format &Format::bufferFormat() const
{
return angle::Format::Get(bufferFormatID);
}
const angle::Format &Format::angleFormat() const
{
return angle::Format::Get(angleFormatID);
}
bool operator==(const Format &lhs, const Format &rhs)
{
return &lhs == &rhs;
}
bool operator!=(const Format &lhs, const Format &rhs)
{
return &lhs != &rhs;
}
// FormatTable implementation.
FormatTable::FormatTable()
{
}
FormatTable::~FormatTable()
{
}
void FormatTable::initialize(VkPhysicalDevice physicalDevice,
gl::TextureCapsMap *outTextureCapsMap,
std::vector<GLenum> *outCompressedTextureFormats)
{
for (size_t formatIndex = 0; formatIndex < angle::kNumANGLEFormats; ++formatIndex)
{
const auto formatID = static_cast<angle::FormatID>(formatIndex);
const angle::Format &angleFormat = angle::Format::Get(formatID);
mFormatData[formatIndex].initialize(physicalDevice, angleFormat);
const GLenum internalFormat = mFormatData[formatIndex].internalFormat;
mFormatData[formatIndex].textureLoadFunctions =
GetLoadFunctionsMap(internalFormat, mFormatData[formatIndex].textureFormatID);
mFormatData[formatIndex].angleFormatID = formatID;
if (!mFormatData[formatIndex].valid())
{
continue;
}
const VkFormat vkFormat = mFormatData[formatIndex].vkTextureFormat;
// Try filling out the info from our hard coded format data, if we can't find the
// information we need, we'll make the call to Vulkan.
VkFormatProperties formatProperties;
GetFormatProperties(physicalDevice, vkFormat, &formatProperties);
gl::TextureCaps textureCaps;
FillTextureFormatCaps(formatProperties, &textureCaps);
outTextureCapsMap->set(formatID, textureCaps);
if (angleFormat.isBlock)
{
outCompressedTextureFormats->push_back(internalFormat);
}
}
}
const Format &FormatTable::operator[](GLenum internalFormat) const
{
angle::FormatID formatID = angle::Format::InternalFormatToID(internalFormat);
return mFormatData[static_cast<size_t>(formatID)];
}
const Format &FormatTable::operator[](angle::FormatID formatID) const
{
return mFormatData[static_cast<size_t>(formatID)];
}
} // namespace vk
} // namespace rx