Commit 2ffff6d0 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Support image buffers

This change does not support reinterpreted formats yet. Additionally, despite lack of support for RGB32 formats, EXT_texture_buffer is exposed by this extension. Those formats don't support the STORAGE_TEXEL_BUFFER feature on any known hardware. Bug: angleproject:3573 Change-Id: I85f45eb23f6a0aa533488bb98d9f226d59af4d76 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2534395 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 2eb85a5b
......@@ -185,6 +185,46 @@ TextureType SamplerTypeToTextureType(GLenum samplerType)
}
}
TextureType ImageTypeToTextureType(GLenum imageType)
{
switch (imageType)
{
case GL_IMAGE_2D:
case GL_INT_IMAGE_2D:
case GL_UNSIGNED_INT_IMAGE_2D:
return TextureType::_2D;
case GL_IMAGE_CUBE:
case GL_INT_IMAGE_CUBE:
case GL_UNSIGNED_INT_IMAGE_CUBE:
return TextureType::CubeMap;
case GL_IMAGE_CUBE_MAP_ARRAY:
case GL_INT_IMAGE_CUBE_MAP_ARRAY:
case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
return TextureType::CubeMapArray;
case GL_IMAGE_2D_ARRAY:
case GL_INT_IMAGE_2D_ARRAY:
case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
return TextureType::_2DArray;
case GL_IMAGE_3D:
case GL_INT_IMAGE_3D:
case GL_UNSIGNED_INT_IMAGE_3D:
return TextureType::_3D;
case GL_IMAGE_BUFFER:
case GL_INT_IMAGE_BUFFER:
case GL_UNSIGNED_INT_IMAGE_BUFFER:
return TextureType::Buffer;
default:
UNREACHABLE();
return TextureType::InvalidEnum;
}
}
bool IsMultisampled(TextureType type)
{
switch (type)
......
......@@ -219,6 +219,7 @@ template <typename T>
using ShaderMap = angle::PackedEnumMap<ShaderType, T>;
TextureType SamplerTypeToTextureType(GLenum samplerType);
TextureType ImageTypeToTextureType(GLenum imageType);
bool IsMultisampled(gl::TextureType type);
bool IsArrayTextureType(gl::TextureType type);
......
......@@ -1063,8 +1063,11 @@ ProgramAliasedBindings::const_iterator ProgramAliasedBindings::end() const
}
// ImageBinding implementation.
ImageBinding::ImageBinding(size_t count) : boundImageUnits(count, 0) {}
ImageBinding::ImageBinding(GLuint imageUnit, size_t count)
ImageBinding::ImageBinding(size_t count, TextureType textureTypeIn)
: textureType(textureTypeIn), boundImageUnits(count, 0)
{}
ImageBinding::ImageBinding(GLuint imageUnit, size_t count, TextureType textureTypeIn)
: textureType(textureTypeIn)
{
for (size_t index = 0; index < count; ++index)
{
......@@ -3723,15 +3726,18 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
// cannot load values into a uniform defined as an image. if declare without a
// binding qualifier, any uniform image variable (include all elements of
// unbound image array) shoud be bound to unit zero.
auto &imageUniform = mState.mExecutable->getUniforms()[imageIndex];
auto &imageUniform = mState.mExecutable->getUniforms()[imageIndex];
TextureType textureType = ImageTypeToTextureType(imageUniform.type);
if (imageUniform.binding == -1)
{
imageBindings.emplace_back(ImageBinding(imageUniform.getBasicTypeElementCount()));
imageBindings.emplace_back(
ImageBinding(imageUniform.getBasicTypeElementCount(), textureType));
}
else
{
imageBindings.emplace_back(ImageBinding(imageUniform.binding + arrayOffset,
imageUniform.getBasicTypeElementCount()));
imageUniform.getBasicTypeElementCount(),
textureType));
}
GLuint arraySize = imageUniform.isArray() ? imageUniform.arraySizes[0] : 1u;
......@@ -5308,6 +5314,7 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
for (const auto &imageBinding : mState.getImageBindings())
{
stream.writeInt(imageBinding.boundImageUnits.size());
stream.writeInt(static_cast<unsigned int>(imageBinding.textureType));
for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
{
stream.writeInt(imageBinding.boundImageUnits[i]);
......@@ -5558,8 +5565,9 @@ angle::Result Program::deserialize(const Context *context,
size_t imageBindingCount = stream.readInt<size_t>();
for (size_t imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
{
size_t elementCount = stream.readInt<size_t>();
ImageBinding imageBinding(elementCount);
size_t elementCount = stream.readInt<size_t>();
TextureType textureType = static_cast<TextureType>(stream.readInt<unsigned int>());
ImageBinding imageBinding(elementCount, textureType);
for (size_t elementIndex = 0; elementIndex < elementCount; ++elementIndex)
{
imageBinding.boundImageUnits[elementIndex] = stream.readInt<unsigned int>();
......
......@@ -45,11 +45,14 @@ struct SamplerBinding
struct ImageBinding
{
ImageBinding(size_t count);
ImageBinding(GLuint imageUnit, size_t count);
ImageBinding(size_t count, TextureType textureTypeIn);
ImageBinding(GLuint imageUnit, size_t count, TextureType textureTypeIn);
ImageBinding(const ImageBinding &other);
~ImageBinding();
// Necessary for distinguishing between textures with images and texture buffers.
TextureType textureType;
// List of all textures bound.
// Cropped by the amount of unused elements reported by the driver.
std::vector<GLuint> boundImageUnits;
......
......@@ -316,7 +316,8 @@ angle::Result BufferVk::setDataWithMemoryType(const gl::Context *context,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled)
{
......
......@@ -3906,40 +3906,71 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
continue;
}
TextureVk *textureVk = vk::GetImpl(texture);
vk::ImageHelper *image = &textureVk->getImage();
TextureVk *textureVk = vk::GetImpl(texture);
mActiveImages[imageUnitIndex] = textureVk;
if (alreadyProcessed.find(image) != alreadyProcessed.end())
{
continue;
}
alreadyProcessed.insert(image);
// The image should be flushed and ready to use at this point. There may still be
// lingering staged updates in its staging buffer for unused texture mip levels or
// layers. Therefore we can't verify it has no staged updates right here.
vk::ImageLayout imageLayout;
gl::ShaderBitSet shaderBits = activeImageShaderBits[imageUnitIndex];
if (shaderBits.any())
gl::ShaderBitSet shaderStages = activeImageShaderBits[imageUnitIndex];
// TODO: PPOs don't initialize mActiveImageShaderBits. http://anglebug.com/5358
// Once that is fixed, the following if should be replaced with an assertion:
//
// ASSERT(shaderStages.any());
if (shaderStages.none())
{
gl::ShaderType shader = static_cast<gl::ShaderType>(gl::ScanForward(shaderBits.bits()));
shaderBits.reset(shader);
// This is accessed by multiple shaders
if (shaderBits.any())
if (executable->isCompute())
{
imageLayout = vk::ImageLayout::AllGraphicsShadersWrite;
shaderStages.set(gl::ShaderType::Compute);
}
else
{
imageLayout = kShaderWriteImageLayouts[shader];
shaderStages.set();
shaderStages.reset(gl::ShaderType::Compute);
}
}
else
// Special handling of texture buffers. They have a buffer attached instead of an image.
if (texture->getType() == gl::TextureType::Buffer)
{
BufferVk *bufferVk = vk::GetImpl(textureVk->getBuffer().get());
vk::BufferHelper &buffer = bufferVk->getBuffer();
// TODO: accept multiple stages in bufferWrite. http://anglebug.com/3573
for (gl::ShaderType stage : shaderStages)
{
commandBufferHelper->bufferWrite(
&mResourceUseList, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
vk::GetPipelineStage(stage), vk::AliasingMode::Disallowed, &buffer);
}
textureVk->retainBufferView(&mResourceUseList);
continue;
}
vk::ImageHelper *image = &textureVk->getImage();
if (alreadyProcessed.find(image) != alreadyProcessed.end())
{
continue;
}
alreadyProcessed.insert(image);
vk::ImageLayout imageLayout;
gl::ShaderType shader = static_cast<gl::ShaderType>(gl::ScanForward(shaderStages.bits()));
shaderStages.reset(shader);
// This is accessed by multiple shaders
if (shaderStages.any())
{
imageLayout = vk::ImageLayout::AllGraphicsShadersWrite;
}
else
{
imageLayout = kShaderWriteImageLayouts[shader];
}
VkImageAspectFlags aspectFlags = image->getAspectFlags();
uint32_t layerStart = 0;
......
......@@ -508,8 +508,11 @@ void ProgramExecutableVk::addImageDescriptorSetDesc(const gl::ProgramExecutable
GetImageNameWithoutIndices(&imageName);
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][imageName];
VkShaderStageFlags activeStages = gl_vk::kShaderStageMap[shaderType];
descOut->update(info.binding, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, arraySize, activeStages,
nullptr);
const VkDescriptorType descType = imageBinding.textureType == gl::TextureType::Buffer
? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
: VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
descOut->update(info.binding, descType, arraySize, activeStages, nullptr);
}
}
}
......@@ -1205,7 +1208,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
std::string mappedImageName;
if (!useOldRewriteStructSamplers)
{
mappedImageName = GlslangGetMappedSamplerName(imageUniform.mappedName);
mappedImageName = GlslangGetMappedSamplerName(imageUniform.name);
}
else
{
......@@ -1225,8 +1228,34 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
mappedImageNameToArrayOffset[mappedImageName] += arraySize;
}
VkWriteDescriptorSet *writeInfos = contextVk->allocWriteDescriptorSets(arraySize);
// Texture buffers use buffer views, so they are especially handled.
if (imageBinding.textureType == gl::TextureType::Buffer)
{
for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
{
GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
TextureVk *textureVk = activeImages[imageUnit];
const vk::BufferView &view = textureVk->getBufferViewAndRecordUse(contextVk);
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][mappedImageName];
writeInfos[arrayElement].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfos[arrayElement].pNext = nullptr;
writeInfos[arrayElement].dstSet = descriptorSet;
writeInfos[arrayElement].dstBinding = info.binding;
writeInfos[arrayElement].dstArrayElement = arrayOffset + arrayElement;
writeInfos[arrayElement].descriptorCount = 1;
writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
writeInfos[arrayElement].pImageInfo = nullptr;
writeInfos[arrayElement].pBufferInfo = nullptr;
writeInfos[arrayElement].pTexelBufferView = view.ptr();
}
continue;
}
VkDescriptorImageInfo *imageInfos = contextVk->allocDescriptorImageInfos(arraySize);
VkWriteDescriptorSet *writeInfos = contextVk->allocWriteDescriptorSets(arraySize);
for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
{
GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
......
......@@ -33,7 +33,7 @@ namespace rx
// pipeline stage. Additionally, transform feedback buffers are bound from binding 2 and up.
// - Set 2 contains all textures (including texture buffers).
// - Set 3 contains all other shader resources, such as uniform and storage blocks, atomic counter
// buffers and images.
// buffers, images and image buffers.
// ANGLE driver uniforms set index (binding is always 0):
enum DescriptorSetIndex : uint32_t
......
......@@ -157,11 +157,57 @@ bool GetTextureSRGBOverrideSupport(const RendererVk *rendererVk,
bool HasTextureBufferSupport(const RendererVk *rendererVk)
{
// Only three formats don't have mandatory UNIFORM_TEXEL_BUFFER support in Vulkan.
const std::array<GLenum, 3> &optionalFormats = {
GL_RGB32F,
GL_RGB32I,
GL_RGB32UI,
// The following formats don't have mandatory UNIFORM_TEXEL_BUFFER support in Vulkan.
//
// VK_FORMAT_R32G32B32_UINT
// VK_FORMAT_R32G32B32_SINT
// VK_FORMAT_R32G32B32_SFLOAT
//
// Additionally, the following formats don't have mandatory STORAGE_TEXEL_BUFFER support:
//
// VK_FORMAT_R8_UINT
// VK_FORMAT_R8_SINT
// VK_FORMAT_R8_UNORM
// VK_FORMAT_R8G8_UINT
// VK_FORMAT_R8G8_SINT
// VK_FORMAT_R8G8_UNORM
// VK_FORMAT_R16_UINT
// VK_FORMAT_R16_SINT
// VK_FORMAT_R16_SFLOAT
// VK_FORMAT_R16G16_UINT
// VK_FORMAT_R16G16_SINT
// VK_FORMAT_R16G16_SFLOAT
// VK_FORMAT_R32G32B32_UINT
// VK_FORMAT_R32G32B32_SINT
// VK_FORMAT_R32G32B32_SFLOAT
//
// The formats that have mandatory support for both features (and don't need to be checked) are:
//
// VK_FORMAT_R8G8B8A8_UINT
// VK_FORMAT_R8G8B8A8_SINT
// VK_FORMAT_R8G8B8A8_UNORM
// VK_FORMAT_R16G16B16A16_UINT
// VK_FORMAT_R16G16B16A16_SINT
// VK_FORMAT_R16G16B16A16_SFLOAT
// VK_FORMAT_R32_UINT
// VK_FORMAT_R32_SINT
// VK_FORMAT_R32_SFLOAT
// VK_FORMAT_R32G32_UINT
// VK_FORMAT_R32G32_SINT
// VK_FORMAT_R32G32_SFLOAT
// VK_FORMAT_R32G32B32A32_UINT
// VK_FORMAT_R32G32B32A32_SINT
// VK_FORMAT_R32G32B32A32_SFLOAT
//
// TODO: RGB32 formats currently don't have STORAGE_TEXEL_BUFFER support on any known platform.
// Despite this limitation, we expose EXT_texture_buffer. http://anglebug.com/3573
const std::array<GLenum, 12> &optionalFormats = {
GL_R8, GL_R8I, GL_R8UI, GL_RG8, GL_RG8I, GL_RG8UI,
GL_R16F, GL_R16I, GL_R16UI, GL_RG16F, GL_RG16I, GL_RG16UI,
// GL_RGB32F,
// GL_RGB32I,
// GL_RGB32UI,
};
for (GLenum formatGL : optionalFormats)
......@@ -169,7 +215,8 @@ bool HasTextureBufferSupport(const RendererVk *rendererVk)
const vk::Format &formatVk = rendererVk->getFormat(formatGL);
if (!rendererVk->hasBufferFormatFeatureBits(formatVk.vkBufferFormat,
VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT))
VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT |
VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT))
{
return false;
}
......@@ -773,8 +820,9 @@ void RendererVk::ensureCapsInitialized() const
// Enable GL_EXT_texture_buffer and OES variant. Nearly all formats required for this extension
// are also required to have the UNIFORM_TEXEL_BUFFER feature bit in Vulkan, except for
// R32G32B32_SFLOAT/UINT/SINT which are optional. This extension is exposed only if those
// formats support the necessary feature bit.
// R32G32B32_SFLOAT/UINT/SINT which are optional. For many formats, the STORAGE_TEXEL_BUFFER
// feature is optional though. This extension is exposed only if the formats specified in
// EXT_texture_buffer support the necessary feature bits.
if (vk::HasTextureBufferSupport(this))
{
mNativeExtensions.textureBufferOES = true;
......
......@@ -186,8 +186,8 @@
// Cannot create 2D (array) view of 3D texture.
3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL
// Storage texel buffer support (part of EXT_texture_buffer)
3573 VULKAN : dEQP-GLES31.functional.image_load_store.buffer.* = SKIP
// Format reinterpretation support for storage texel buffers missing
3573 VULKAN : dEQP-GLES31.functional.image_load_store.buffer.format_reinterpret.* = FAIL
////
//// Android (i.e. Pixel*) Vulkan expectations
......
......@@ -32,13 +32,7 @@
// GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET not set.
3605 VULKAN : KHR-GLES31.core.texture_gather.* = FAIL
// Storage texel buffer support (part of EXT_texture_buffer)
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_buffer_load = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_cpu_writes = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_framebuffer_readback = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_transform_feedback = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_image_store = SKIP
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_operations_ssbo_writes = SKIP
// No known implementation supports STORAGE_TEXEL_BUFFER support for RGB32 formats
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_texture_buffer_range = SKIP
// Dispatch indirect:
......
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