Commit 96bd8fdf by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix format properties queries

When querying format properties (in vk::GetFormatProperties), the mandatory feature support table was consulted to check whether a number of texture features are present. If so, the entry from that table was returned. The goal had been to speed up initialization by not issuing device queries if possible. That is, when vk::GetFormatProperties was called on a format, if it supported that select few texture features, the VkFormatProperties entry from the mandatory table would be returned. However, that function found its way to other uses (such as querying buffer format properties, or other image properties beyond the select few). As a result, when the VkFormatProperties from the mandatory table was returned, actual support for these other features was often not tested and assumed false (unless they happened to be mandatory as well). This commit reworks the format feature query functions such that the specific features to be tested are provided when querying the format properties. The mandatory table is consulted as before, and if the entry doesn't contain those features, the device is queried and the results cached. Bug: angleproject:2958 Change-Id: I28d046eb63c3bd5173468aa4cb3e4c63c83e67b1 Reviewed-on: https://chromium-review.googlesource.com/c/1357152Reviewed-by: 's avatarTobin Ehlis <tobine@google.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 81a880aa
......@@ -49,23 +49,16 @@ bool ClipToRenderTarget(const gl::Rectangle &area,
return ClipRectangle(area, renderTargetRect, rectOut);
}
bool HasSrcAndDstBlitProperties(const VkPhysicalDevice &physicalDevice,
bool HasSrcAndDstBlitProperties(RendererVk *renderer,
RenderTargetVk *srcRenderTarget,
RenderTargetVk *dstRenderTarget)
{
VkFormatProperties drawImageProperties;
vk::GetFormatProperties(physicalDevice, srcRenderTarget->getImageFormat().vkTextureFormat,
&drawImageProperties);
VkFormatProperties readImageProperties;
vk::GetFormatProperties(physicalDevice, dstRenderTarget->getImageFormat().vkTextureFormat,
&readImageProperties);
const VkFormat srcFormat = srcRenderTarget->getImageFormat().vkTextureFormat;
const VkFormat dstFormat = dstRenderTarget->getImageFormat().vkTextureFormat;
// Verifies if the draw and read images have the necessary prerequisites for blitting.
return (IsMaskFlagSet<VkFormatFeatureFlags>(drawImageProperties.optimalTilingFeatures,
VK_FORMAT_FEATURE_BLIT_DST_BIT) &&
IsMaskFlagSet<VkFormatFeatureFlags>(readImageProperties.optimalTilingFeatures,
VK_FORMAT_FEATURE_BLIT_SRC_BIT));
return renderer->hasTextureFormatFeatureBits(srcFormat, VK_FORMAT_FEATURE_BLIT_SRC_BIT) &&
renderer->hasTextureFormatFeatureBits(dstFormat, VK_FORMAT_FEATURE_BLIT_DST_BIT);
}
// Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
......@@ -577,8 +570,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
{
RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorAttachment];
ASSERT(drawRenderTarget);
ASSERT(HasSrcAndDstBlitProperties(renderer->getPhysicalDevice(), readRenderTarget,
drawRenderTarget));
ASSERT(HasSrcAndDstBlitProperties(renderer, readRenderTarget, drawRenderTarget));
gl::Rectangle drawRenderTargetRect;
if (!ClipToRenderTarget(drawRect, drawRenderTarget, &drawRenderTargetRect))
......@@ -615,8 +607,7 @@ angle::Result FramebufferVk::blit(const gl::Context *context,
ASSERT(readRenderTargetRect == drawRenderTargetRect);
ASSERT(filter == GL_NEAREST);
if (HasSrcAndDstBlitProperties(renderer->getPhysicalDevice(), readRenderTarget,
drawRenderTarget))
if (HasSrcAndDstBlitProperties(renderer, readRenderTarget, drawRenderTarget))
{
ANGLE_TRY(blitWithCommand(contextVk, readRenderTargetRect, drawRenderTargetRect,
readRenderTarget, drawRenderTarget, filter, false,
......
......@@ -38,6 +38,7 @@ const uint32_t kMockVendorID = 0xba5eba11;
const uint32_t kMockDeviceID = 0xf005ba11;
constexpr char kMockDeviceName[] = "Vulkan Mock Device";
constexpr size_t kInFlightCommandsLimit = 100u;
constexpr VkFormatFeatureFlags kInvalidFormatFeatureFlags = static_cast<VkFormatFeatureFlags>(-1);
} // anonymous namespace
namespace rx
......@@ -314,7 +315,10 @@ RendererVk::RendererVk()
mGpuEventsEnabled(false),
mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
mGpuEventTimestampOrigin(0)
{}
{
VkFormatProperties invalid = {0, 0, kInvalidFormatFeatureFlags};
mFormatProperties.fill(invalid);
}
RendererVk::~RendererVk() {}
......@@ -542,8 +546,7 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
GlslangWrapper::Initialize();
// Initialize the format table.
mFormatTable.initialize(mPhysicalDevice, mPhysicalDeviceProperties, mFeatures,
&mNativeTextureCaps, &mNativeCaps.compressedTextureFormats);
mFormatTable.initialize(this, &mNativeTextureCaps, &mNativeCaps.compressedTextureFormats);
return angle::Result::Continue();
}
......@@ -1365,6 +1368,25 @@ angle::Result RendererVk::getTimestamp(vk::Context *context, uint64_t *timestamp
return angle::Result::Continue();
}
// These functions look at the mandatory format for support, and fallback to querying the device (if
// necessary) to test the availability of the bits.
bool RendererVk::hasLinearTextureFormatFeatureBits(VkFormat format,
const VkFormatFeatureFlags featureBits)
{
return hasFormatFeatureBits<&VkFormatProperties::linearTilingFeatures>(format, featureBits);
}
bool RendererVk::hasTextureFormatFeatureBits(VkFormat format,
const VkFormatFeatureFlags featureBits)
{
return hasFormatFeatureBits<&VkFormatProperties::optimalTilingFeatures>(format, featureBits);
}
bool RendererVk::hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits)
{
return hasFormatFeatureBits<&VkFormatProperties::bufferFeatures>(format, featureBits);
}
angle::Result RendererVk::synchronizeCpuGpuTime(vk::Context *context)
{
ASSERT(mGpuEventsEnabled);
......@@ -1710,6 +1732,29 @@ void RendererVk::flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpu
mGpuEvents.clear();
}
template <VkFormatFeatureFlags VkFormatProperties::*features>
bool RendererVk::hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits)
{
ASSERT(static_cast<uint32_t>(format) < vk::kNumVkFormats);
VkFormatProperties &deviceProperties = mFormatProperties[format];
if (deviceProperties.bufferFeatures == kInvalidFormatFeatureFlags)
{
// If we don't have the actual device features, see if the requested features are mandatory.
// If so, there's no need to query the device.
const VkFormatProperties &mandatoryProperties = vk::GetMandatoryFormatSupport(format);
if (IsMaskFlagSet(mandatoryProperties.*features, featureBits))
{
return true;
}
// Otherwise query the format features and cache it.
vkGetPhysicalDeviceFormatProperties(mPhysicalDevice, format, &deviceProperties);
}
return IsMaskFlagSet(deviceProperties.*features, featureBits);
}
uint32_t GetUniformBufferDescriptorCount()
{
return kUniformBufferDescriptorsPerDescriptorSet;
......
......@@ -183,6 +183,13 @@ class RendererVk : angle::NonCopyable
const vk::PipelineCache &getPipelineCache() const { return mPipelineCache; }
// Query the format properties for select bits (linearTilingFeatures, optimalTilingFeatures and
// bufferFeatures). Looks through mandatory features first, and falls back to querying the
// device (first time only).
bool hasLinearTextureFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
bool hasTextureFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
bool hasBufferFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
private:
// Number of semaphores for external entities to renderer to issue a wait, such as surface's
// image acquire.
......@@ -214,6 +221,9 @@ class RendererVk : angle::NonCopyable
angle::Result checkCompletedGpuEvents(vk::Context *context);
void flushGpuEvents(double nextSyncGpuTimestampS, double nextSyncCpuTimestampS);
template <VkFormatFeatureFlags VkFormatProperties::*features>
bool hasFormatFeatureBits(VkFormat format, const VkFormatFeatureFlags featureBits);
egl::Display *mDisplay;
mutable bool mCapsInitialized;
......@@ -268,6 +278,9 @@ class RendererVk : angle::NonCopyable
egl::BlobCache::Key mPipelineCacheVkBlobKey;
uint32_t mPipelineCacheVkUpdateTimeout;
// A cache of VkFormatProperties as queried from the device over time.
std::array<VkFormatProperties, vk::kNumVkFormats> mFormatProperties;
// mSubmitWaitSemaphores is a list of specifically requested semaphores to be waited on before a
// command buffer submission, for example, semaphores signaled by vkAcquireNextImageKHR.
// After first use, the list is automatically cleared. This is a vector to support concurrent
......
......@@ -854,13 +854,11 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
}
RendererVk *renderer = contextVk->getRenderer();
VkFormatProperties imageProperties;
vk::GetFormatProperties(renderer->getPhysicalDevice(), mImage.getFormat().vkTextureFormat,
&imageProperties);
// Check if the image supports blit. If it does, we can do the mipmap generation on the gpu
// only.
if (IsMaskFlagSet(kBlitFeatureFlags, imageProperties.linearTilingFeatures))
if (renderer->hasTextureFormatFeatureBits(mImage.getFormat().vkTextureFormat,
kBlitFeatureFlags))
{
ANGLE_TRY(ensureImageInitialized(contextVk));
ANGLE_TRY(mImage.generateMipmapsWithBlit(contextVk, mState.getMipmapMaxLevel()));
......
......@@ -41,9 +41,8 @@ namespace rx
namespace vk
{{
void Format::initialize(VkPhysicalDevice physicalDevice,
const angle::Format &angleFormat,
const angle::FeaturesVk &featuresVk)
void Format::initialize(RendererVk *renderer,
const angle::Format &angleFormat)
{{
switch (angleFormat.id)
{{
......@@ -79,7 +78,7 @@ texture_struct_template="{{{texture}, {vk_texture_format}, {texture_initializer}
texture_fallback_template = """{{
static constexpr TextureFormatInitInfo kInfo[] = {{{texture_list}}};
initTextureFallback(physicalDevice, kInfo, ArraySize(kInfo), featuresVk);
initTextureFallback(renderer, kInfo, ArraySize(kInfo));
}}"""
buffer_basic_template = """bufferFormatID = {buffer};
......@@ -93,7 +92,7 @@ buffer_struct_template="""{{{buffer}, {vk_buffer_format}, {vk_buffer_format_is_p
buffer_fallback_template = """{{
static constexpr BufferFormatInitInfo kInfo[] = {{{buffer_list}}};
initBufferFallback(physicalDevice, kInfo, ArraySize(kInfo));
initBufferFallback(renderer, kInfo, ArraySize(kInfo));
}}"""
def is_packed(format_id):
......
......@@ -31,19 +31,20 @@ template_table_autogen_cpp = """// GENERATED FILE - DO NOT EDIT.
using namespace angle;
namespace
{{
constexpr std::array<VkFormatProperties, {num_formats}> kFormatProperties = {{{{
{format_case_data}
}}}};
}} // anonymous namespace
namespace rx
{{
namespace vk
{{
namespace
{{
static_assert({num_formats} == kNumVkFormats, "Update kNumVkFormats");
constexpr std::array<VkFormatProperties, kNumVkFormats> kFormatProperties = {{{{
{format_case_data}
}}}};
}} // anonymous namespace
const VkFormatProperties& GetMandatoryFormatSupport(VkFormat vkFormat)
{{
ASSERT(static_cast<uint64_t>(vkFormat) < sizeof(kFormatProperties));
......@@ -58,7 +59,7 @@ const VkFormatProperties& GetMandatoryFormatSupport(VkFormat vkFormat)
template_format_property = """
/* {vk_format} */
{{{{}}, {optimal_features}, {buffer_features}}}"""
{{0, {optimal_features}, {buffer_features}}}"""
def script_relative(path):
......
......@@ -26,13 +26,12 @@ class TextureCapsMap;
namespace rx
{
class RendererVk;
namespace vk
{
void GetFormatProperties(VkPhysicalDevice physicalDevice,
VkFormat vkFormat,
VkFormatProperties *propertiesOut);
// VkFormat values in range [0, kNumVkFormats) are used as indices in various tables.
constexpr uint32_t kNumVkFormats = 185;
struct TextureFormatInitInfo final
{
......@@ -57,17 +56,10 @@ struct Format final : private angle::NonCopyable
bool valid() const { return internalFormat != 0; }
// This is an auto-generated method in vk_format_table_autogen.cpp.
void initialize(VkPhysicalDevice physicalDevice,
const angle::Format &angleFormat,
const angle::FeaturesVk &featuresVk);
void initTextureFallback(VkPhysicalDevice physicalDevice,
const TextureFormatInitInfo *info,
int numInfo,
const angle::FeaturesVk &featuresVk);
void initBufferFallback(VkPhysicalDevice physicalDevice,
const BufferFormatInitInfo *info,
int numInfo);
void initialize(RendererVk *renderer, const angle::Format &angleFormat);
void initTextureFallback(RendererVk *renderer, const TextureFormatInitInfo *info, int numInfo);
void initBufferFallback(RendererVk *renderer, const BufferFormatInitInfo *info, int numInfo);
const angle::Format &angleFormat() const;
const angle::Format &textureFormat() const;
......@@ -79,11 +71,12 @@ struct Format final : private angle::NonCopyable
VkFormat vkTextureFormat;
angle::FormatID bufferFormatID;
VkFormat vkBufferFormat;
bool vkBufferFormatIsPacked;
InitializeTextureDataFunction textureInitializerFunction;
LoadFunctionMap textureLoadFunctions;
VertexCopyFunction vertexLoadFunction;
bool vertexLoadRequiresConversion;
bool vkBufferFormatIsPacked;
};
bool operator==(const Format &lhs, const Format &rhs);
......@@ -96,9 +89,7 @@ class FormatTable final : angle::NonCopyable
~FormatTable();
// Also initializes the TextureCapsMap and the compressedTextureCaps in the Caps instance.
void initialize(VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceProperties &physicalDeviceProperties,
const angle::FeaturesVk &featuresVk,
void initialize(RendererVk *renderer,
gl::TextureCapsMap *outTextureCapsMap,
std::vector<GLenum> *outCompressedTextureFormats);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment