Commit b6ec24ab by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Support format reinterpretation in imageBuffers

This is done by creating multiple buffer views over the buffer based on the format specified by the attached shaders. Bug: angleproject:3573 Change-Id: I0372a988938050cc092d8a0959a59d1c893fc6f4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2536909 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent f98f18f6
......@@ -476,6 +476,7 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor
linkedUniform.staticUse = mMarkStaticUse;
linkedUniform.outerArraySizes = arraySizes;
linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
linkedUniform.imageUnitFormat = variable.imageUnitFormat;
if (variable.hasParentArrayIndex())
{
linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
......
......@@ -1114,7 +1114,7 @@ ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(
vk::GetPipelineStage(stage), &buffer);
}
textureVk->retainBufferView(&mResourceUseList);
textureVk->retainBufferViews(&mResourceUseList);
continue;
}
......@@ -3945,7 +3945,7 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
vk::GetPipelineStage(stage), vk::AliasingMode::Disallowed, &buffer);
}
textureVk->retainBufferView(&mResourceUseList);
textureVk->retainBufferViews(&mResourceUseList);
continue;
}
......
......@@ -1168,6 +1168,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
ContextVk *contextVk)
{
const gl::State &glState = contextVk->getState();
RendererVk *renderer = contextVk->getRenderer();
const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
......@@ -1233,11 +1234,21 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
// Texture buffers use buffer views, so they are especially handled.
if (imageBinding.textureType == gl::TextureType::Buffer)
{
// Handle format reinterpration by looking for a view with the format specified in
// the shader (if any, instead of the format specified to glTexBuffer).
const vk::Format *format = nullptr;
if (imageUniform.imageUnitFormat != GL_NONE)
{
format = &renderer->getFormat(imageUniform.imageUnitFormat);
}
for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
{
GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
TextureVk *textureVk = activeImages[imageUnit];
const vk::BufferView &view = textureVk->getBufferViewAndRecordUse(contextVk);
GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
TextureVk *textureVk = activeImages[imageUnit];
const vk::BufferView *view = nullptr;
ANGLE_TRY(textureVk->getBufferViewAndRecordUse(contextVk, format, &view));
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][mappedImageName];
......@@ -1250,7 +1261,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
writeInfos[arrayElement].pImageInfo = nullptr;
writeInfos[arrayElement].pBufferInfo = nullptr;
writeInfos[arrayElement].pTexelBufferView = view.ptr();
writeInfos[arrayElement].pTexelBufferView = view->ptr();
}
continue;
}
......@@ -1484,7 +1495,8 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
{
GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
TextureVk *textureVk = activeTextures[textureUnit].texture;
const vk::BufferView &view = textureVk->getBufferViewAndRecordUse(contextVk);
const vk::BufferView *view = nullptr;
ANGLE_TRY(textureVk->getBufferViewAndRecordUse(contextVk, nullptr, &view));
const std::string samplerName =
GlslangGetMappedSamplerName(samplerUniform.name);
......@@ -1500,7 +1512,7 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
writeInfos[arrayElement].pImageInfo = nullptr;
writeInfos[arrayElement].pBufferInfo = nullptr;
writeInfos[arrayElement].pTexelBufferView = view.ptr();
writeInfos[arrayElement].pTexelBufferView = view->ptr();
}
continue;
}
......
......@@ -1364,7 +1364,7 @@ void TextureVk::releaseAndDeleteImageAndViews(ContextVk *contextVk)
mImageCreateFlags = 0;
SafeDelete(mImage);
}
mBufferView.release(contextVk->getRenderer());
mBufferViews.release(contextVk->getRenderer());
mRedefinedLevels.reset();
}
......@@ -2242,23 +2242,20 @@ angle::Result TextureVk::syncState(const gl::Context *context,
ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer();
// If this is a texture buffer, create the buffer view. There's nothing else to sync. The
// If this is a texture buffer, release buffer views. There's nothing else to sync. The
// image must already be deleted, and the sampler reset.
if (mState.getBuffer().get() != nullptr)
{
ASSERT(mImage == nullptr);
const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
const vk::BufferHelper &buffer = vk::GetImpl(bufferBinding.get())->getBuffer();
const gl::ImageDesc &desc = mState.getBaseLevelDesc();
const vk::Format &vkFormat = renderer->getFormat(desc.format.info->sizedInternalFormat);
const VkDeviceSize offset = bufferBinding.getOffset();
const VkDeviceSize size = gl::GetBoundBufferAvailableSize(bufferBinding);
mBufferView.release(renderer);
return mBufferView.initView(contextVk, buffer, vkFormat, offset, size);
mBufferViews.release(renderer);
mBufferViews.init(renderer, offset, size);
return angle::Result::Continue;
}
VkImageUsageFlags oldUsageFlags = mImageUsageFlags;
......@@ -2542,13 +2539,26 @@ angle::Result TextureVk::getStorageImageView(ContextVk *contextVk,
imageViewOut);
}
const vk::BufferView &TextureVk::getBufferViewAndRecordUse(ContextVk *contextVk) const
angle::Result TextureVk::getBufferViewAndRecordUse(ContextVk *contextVk,
const vk::Format *imageUniformFormat,
const vk::BufferView **viewOut)
{
RendererVk *renderer = contextVk->getRenderer();
ASSERT(mState.getBuffer().get() != nullptr);
ASSERT(mBufferView.getView().valid());
mBufferView.retain(&contextVk->getResourceUseList());
return mBufferView.getView();
// Use the format specified by glTexBuffer if no format specified by the shader.
if (imageUniformFormat == nullptr)
{
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
imageUniformFormat = &renderer->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
}
// Create a view for the required format.
const vk::BufferHelper &buffer = vk::GetImpl(mState.getBuffer().get())->getBuffer();
retainBufferViews(&contextVk->getResourceUseList());
return mBufferViews.getView(contextVk, buffer, *imageUniformFormat, viewOut);
}
angle::Result TextureVk::initImage(ContextVk *contextVk,
......@@ -2854,7 +2864,7 @@ vk::ImageOrBufferViewSubresourceSerial TextureVk::getImageViewSubresourceSerial(
vk::ImageOrBufferViewSubresourceSerial TextureVk::getBufferViewSerial() const
{
return mBufferView.getSerial();
return mBufferViews.getSerial();
}
angle::Result TextureVk::refreshImageViews(ContextVk *contextVk)
......
......@@ -202,9 +202,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
getImageViews().retain(resourceUseList);
}
void retainBufferView(vk::ResourceUseList *resourceUseList)
void retainBufferViews(vk::ResourceUseList *resourceUseList)
{
mBufferView.retain(resourceUseList);
mBufferViews.retain(resourceUseList);
}
void releaseOwnershipOfImage(const gl::Context *context);
......@@ -231,7 +231,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
return mSampler.get();
}
const vk::BufferView &getBufferViewAndRecordUse(ContextVk *contextVk) const;
angle::Result getBufferViewAndRecordUse(ContextVk *contextVk,
const vk::Format *imageUniformFormat,
const vk::BufferView **viewOut);
// Normally, initialize the image with enabled mipmap level counts.
angle::Result ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels);
......@@ -497,9 +499,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
// - index N: views for mMultisampledImages[N]
gl::RenderToTextureImageMap<vk::ImageViewHelper> mMultisampledImageViews;
// Texture buffers create a uniform texel buffer view instead. |BufferViewHelper| contains the
// single view corresponding to the attached buffer range.
vk::BufferViewHelper mBufferView;
// Texture buffers create texel buffer views instead. |BufferViewHelper| contains the views
// corresponding to the attached buffer range.
vk::BufferViewHelper mBufferViews;
// Render targets stored as array of vector of vectors
//
......
......@@ -6732,18 +6732,25 @@ ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial(
}
// BufferViewHelper implementation.
BufferViewHelper::BufferViewHelper() {}
BufferViewHelper::BufferViewHelper() : mOffset(0), mSize(0) {}
BufferViewHelper::BufferViewHelper(BufferViewHelper &&other) : Resource(std::move(other))
{
std::swap(mView, other.mView);
std::swap(mOffset, other.mOffset);
std::swap(mSize, other.mSize);
std::swap(mViews, other.mViews);
std::swap(mViewSerial, other.mViewSerial);
}
BufferViewHelper::~BufferViewHelper() {}
void BufferViewHelper::init(RendererVk *renderer)
void BufferViewHelper::init(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
{
ASSERT(mViews.empty());
mOffset = offset;
mSize = size;
if (!mViewSerial.valid())
{
mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
......@@ -6752,51 +6759,84 @@ void BufferViewHelper::init(RendererVk *renderer)
void BufferViewHelper::release(RendererVk *renderer)
{
if (mView.valid())
std::vector<GarbageObject> garbage;
for (auto &formatAndView : mViews)
{
std::vector<GarbageObject> garbage;
garbage.emplace_back(GetGarbage(&mView));
BufferView &view = formatAndView.second;
ASSERT(view.valid());
garbage.emplace_back(GetGarbage(&view));
}
if (!garbage.empty())
{
renderer->collectGarbage(std::move(mUse), std::move(garbage));
// Ensure the resource use is always valid.
mUse.init();
}
mViews.clear();
mOffset = 0;
mSize = 0;
// Update image view serial.
mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
}
void BufferViewHelper::destroy(VkDevice device)
{
mView.destroy(device);
for (auto &formatAndView : mViews)
{
BufferView &view = formatAndView.second;
view.destroy(device);
}
mViews.clear();
mOffset = 0;
mSize = 0;
mViewSerial = kInvalidImageOrBufferViewSerial;
}
angle::Result BufferViewHelper::initView(ContextVk *contextVk,
const BufferHelper &buffer,
const Format &format,
VkDeviceSize offset,
VkDeviceSize size)
angle::Result BufferViewHelper::getView(ContextVk *contextVk,
const BufferHelper &buffer,
const Format &format,
const BufferView **viewOut)
{
ASSERT(format.valid());
ASSERT(!mView.valid());
auto iter = mViews.find(format.vkBufferFormat);
if (iter != mViews.end())
{
*viewOut = &iter->second;
return angle::Result::Continue;
}
// If the size is not a multiple of pixelBytes, remove the extra bytes. The last element cannot
// be read anyway, and this is a requirement of Vulkan (for size to be a multiple of format
// texel block size).
const angle::Format &bufferFormat = format.actualBufferFormat(false);
const GLuint pixelBytes = bufferFormat.pixelBytes;
size -= size % pixelBytes;
VkDeviceSize size = mSize - mSize % pixelBytes;
VkBufferViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
viewCreateInfo.buffer = buffer.getBuffer().getHandle();
viewCreateInfo.format = format.vkBufferFormat;
viewCreateInfo.offset = offset;
viewCreateInfo.offset = mOffset;
viewCreateInfo.range = size;
ANGLE_VK_TRY(contextVk, mView.init(contextVk->getDevice(), viewCreateInfo));
BufferView view;
ANGLE_VK_TRY(contextVk, view.init(contextVk->getDevice(), viewCreateInfo));
// Cache the view
auto insertIter = mViews.insert({format.vkBufferFormat, std::move(view)});
*viewOut = &insertIter.first->second;
ASSERT(insertIter.second);
return angle::Result::Continue;
}
......
......@@ -2162,23 +2162,29 @@ class BufferViewHelper final : public Resource
BufferViewHelper(BufferViewHelper &&other);
~BufferViewHelper() override;
void init(RendererVk *renderer);
void init(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size);
void release(RendererVk *renderer);
void destroy(VkDevice device);
const BufferView &getView() const { return mView; }
angle::Result initView(ContextVk *contextVk,
const BufferHelper &buffer,
const Format &format,
VkDeviceSize offset,
VkDeviceSize size);
angle::Result getView(ContextVk *contextVk,
const BufferHelper &buffer,
const Format &format,
const BufferView **viewOut);
// Return unique Serial for a bufferView.
ImageOrBufferViewSubresourceSerial getSerial() const;
private:
BufferView mView;
// To support format reinterpretation, additional views for formats other than the one specified
// to glTexBuffer may need to be created. On draw/dispatch, the format layout qualifier of the
// imageBuffer is used (if provided) to create a potentially different view of the buffer.
angle::HashMap<VkFormat, BufferView> mViews;
// View properties:
//
// Offset and size specified to glTexBufferRange
VkDeviceSize mOffset;
VkDeviceSize mSize;
// Serial for the buffer view. An ImageOrBufferViewSerial is used for texture buffers so that
// they fit together with the other texture types.
......
......@@ -186,9 +186,6 @@
// Cannot create 2D (array) view of 3D texture.
3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL
// 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
////
......
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