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 ...@@ -476,6 +476,7 @@ class FlattenUniformVisitor : public sh::VariableNameVisitor
linkedUniform.staticUse = mMarkStaticUse; linkedUniform.staticUse = mMarkStaticUse;
linkedUniform.outerArraySizes = arraySizes; linkedUniform.outerArraySizes = arraySizes;
linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse; linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
linkedUniform.imageUnitFormat = variable.imageUnitFormat;
if (variable.hasParentArrayIndex()) if (variable.hasParentArrayIndex())
{ {
linkedUniform.setParentArrayIndex(variable.parentArrayIndex()); linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
......
...@@ -1114,7 +1114,7 @@ ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl( ...@@ -1114,7 +1114,7 @@ ANGLE_INLINE angle::Result ContextVk::handleDirtyTexturesImpl(
vk::GetPipelineStage(stage), &buffer); vk::GetPipelineStage(stage), &buffer);
} }
textureVk->retainBufferView(&mResourceUseList); textureVk->retainBufferViews(&mResourceUseList);
continue; continue;
} }
...@@ -3945,7 +3945,7 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context, ...@@ -3945,7 +3945,7 @@ angle::Result ContextVk::updateActiveImages(const gl::Context *context,
vk::GetPipelineStage(stage), vk::AliasingMode::Disallowed, &buffer); vk::GetPipelineStage(stage), vk::AliasingMode::Disallowed, &buffer);
} }
textureVk->retainBufferView(&mResourceUseList); textureVk->retainBufferViews(&mResourceUseList);
continue; continue;
} }
......
...@@ -1168,6 +1168,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1168,6 +1168,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
ContextVk *contextVk) ContextVk *contextVk)
{ {
const gl::State &glState = contextVk->getState(); const gl::State &glState = contextVk->getState();
RendererVk *renderer = contextVk->getRenderer();
const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings(); const std::vector<gl::ImageBinding> &imageBindings = executable.getImageBindings();
const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms(); const std::vector<gl::LinkedUniform> &uniforms = executable.getUniforms();
...@@ -1233,11 +1234,21 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1233,11 +1234,21 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
// Texture buffers use buffer views, so they are especially handled. // Texture buffers use buffer views, so they are especially handled.
if (imageBinding.textureType == gl::TextureType::Buffer) 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) for (uint32_t arrayElement = 0; arrayElement < arraySize; ++arrayElement)
{ {
GLuint imageUnit = imageBinding.boundImageUnits[arrayElement]; GLuint imageUnit = imageBinding.boundImageUnits[arrayElement];
TextureVk *textureVk = activeImages[imageUnit]; TextureVk *textureVk = activeImages[imageUnit];
const vk::BufferView &view = textureVk->getBufferViewAndRecordUse(contextVk);
const vk::BufferView *view = nullptr;
ANGLE_TRY(textureVk->getBufferViewAndRecordUse(contextVk, format, &view));
ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][mappedImageName]; ShaderInterfaceVariableInfo &info = mVariableInfoMap[shaderType][mappedImageName];
...@@ -1250,7 +1261,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet( ...@@ -1250,7 +1261,7 @@ angle::Result ProgramExecutableVk::updateImagesDescriptorSet(
writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; writeInfos[arrayElement].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
writeInfos[arrayElement].pImageInfo = nullptr; writeInfos[arrayElement].pImageInfo = nullptr;
writeInfos[arrayElement].pBufferInfo = nullptr; writeInfos[arrayElement].pBufferInfo = nullptr;
writeInfos[arrayElement].pTexelBufferView = view.ptr(); writeInfos[arrayElement].pTexelBufferView = view->ptr();
} }
continue; continue;
} }
...@@ -1484,7 +1495,8 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex ...@@ -1484,7 +1495,8 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
{ {
GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement]; GLuint textureUnit = samplerBinding.boundTextureUnits[arrayElement];
TextureVk *textureVk = activeTextures[textureUnit].texture; 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 = const std::string samplerName =
GlslangGetMappedSamplerName(samplerUniform.name); GlslangGetMappedSamplerName(samplerUniform.name);
...@@ -1500,7 +1512,7 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex ...@@ -1500,7 +1512,7 @@ angle::Result ProgramExecutableVk::updateTexturesDescriptorSet(ContextVk *contex
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
writeInfos[arrayElement].pImageInfo = nullptr; writeInfos[arrayElement].pImageInfo = nullptr;
writeInfos[arrayElement].pBufferInfo = nullptr; writeInfos[arrayElement].pBufferInfo = nullptr;
writeInfos[arrayElement].pTexelBufferView = view.ptr(); writeInfos[arrayElement].pTexelBufferView = view->ptr();
} }
continue; continue;
} }
......
...@@ -1364,7 +1364,7 @@ void TextureVk::releaseAndDeleteImageAndViews(ContextVk *contextVk) ...@@ -1364,7 +1364,7 @@ void TextureVk::releaseAndDeleteImageAndViews(ContextVk *contextVk)
mImageCreateFlags = 0; mImageCreateFlags = 0;
SafeDelete(mImage); SafeDelete(mImage);
} }
mBufferView.release(contextVk->getRenderer()); mBufferViews.release(contextVk->getRenderer());
mRedefinedLevels.reset(); mRedefinedLevels.reset();
} }
...@@ -2242,23 +2242,20 @@ angle::Result TextureVk::syncState(const gl::Context *context, ...@@ -2242,23 +2242,20 @@ angle::Result TextureVk::syncState(const gl::Context *context,
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer(); 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. // image must already be deleted, and the sampler reset.
if (mState.getBuffer().get() != nullptr) if (mState.getBuffer().get() != nullptr)
{ {
ASSERT(mImage == nullptr); ASSERT(mImage == nullptr);
const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer(); 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 offset = bufferBinding.getOffset();
const VkDeviceSize size = gl::GetBoundBufferAvailableSize(bufferBinding); const VkDeviceSize size = gl::GetBoundBufferAvailableSize(bufferBinding);
mBufferView.release(renderer); mBufferViews.release(renderer);
return mBufferView.initView(contextVk, buffer, vkFormat, offset, size); mBufferViews.init(renderer, offset, size);
return angle::Result::Continue;
} }
VkImageUsageFlags oldUsageFlags = mImageUsageFlags; VkImageUsageFlags oldUsageFlags = mImageUsageFlags;
...@@ -2542,13 +2539,26 @@ angle::Result TextureVk::getStorageImageView(ContextVk *contextVk, ...@@ -2542,13 +2539,26 @@ angle::Result TextureVk::getStorageImageView(ContextVk *contextVk,
imageViewOut); 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(mState.getBuffer().get() != nullptr);
ASSERT(mBufferView.getView().valid());
mBufferView.retain(&contextVk->getResourceUseList()); // Use the format specified by glTexBuffer if no format specified by the shader.
return mBufferView.getView(); 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, angle::Result TextureVk::initImage(ContextVk *contextVk,
...@@ -2854,7 +2864,7 @@ vk::ImageOrBufferViewSubresourceSerial TextureVk::getImageViewSubresourceSerial( ...@@ -2854,7 +2864,7 @@ vk::ImageOrBufferViewSubresourceSerial TextureVk::getImageViewSubresourceSerial(
vk::ImageOrBufferViewSubresourceSerial TextureVk::getBufferViewSerial() const vk::ImageOrBufferViewSubresourceSerial TextureVk::getBufferViewSerial() const
{ {
return mBufferView.getSerial(); return mBufferViews.getSerial();
} }
angle::Result TextureVk::refreshImageViews(ContextVk *contextVk) angle::Result TextureVk::refreshImageViews(ContextVk *contextVk)
......
...@@ -202,9 +202,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -202,9 +202,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
getImageViews().retain(resourceUseList); 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); void releaseOwnershipOfImage(const gl::Context *context);
...@@ -231,7 +231,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -231,7 +231,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
return mSampler.get(); 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. // Normally, initialize the image with enabled mipmap level counts.
angle::Result ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels); angle::Result ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels);
...@@ -497,9 +499,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -497,9 +499,9 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
// - index N: views for mMultisampledImages[N] // - index N: views for mMultisampledImages[N]
gl::RenderToTextureImageMap<vk::ImageViewHelper> mMultisampledImageViews; gl::RenderToTextureImageMap<vk::ImageViewHelper> mMultisampledImageViews;
// Texture buffers create a uniform texel buffer view instead. |BufferViewHelper| contains the // Texture buffers create texel buffer views instead. |BufferViewHelper| contains the views
// single view corresponding to the attached buffer range. // corresponding to the attached buffer range.
vk::BufferViewHelper mBufferView; vk::BufferViewHelper mBufferViews;
// Render targets stored as array of vector of vectors // Render targets stored as array of vector of vectors
// //
......
...@@ -6732,18 +6732,25 @@ ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial( ...@@ -6732,18 +6732,25 @@ ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial(
} }
// BufferViewHelper implementation. // BufferViewHelper implementation.
BufferViewHelper::BufferViewHelper() {} BufferViewHelper::BufferViewHelper() : mOffset(0), mSize(0) {}
BufferViewHelper::BufferViewHelper(BufferViewHelper &&other) : Resource(std::move(other)) 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); std::swap(mViewSerial, other.mViewSerial);
} }
BufferViewHelper::~BufferViewHelper() {} 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()) if (!mViewSerial.valid())
{ {
mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial(); mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
...@@ -6752,51 +6759,84 @@ void BufferViewHelper::init(RendererVk *renderer) ...@@ -6752,51 +6759,84 @@ void BufferViewHelper::init(RendererVk *renderer)
void BufferViewHelper::release(RendererVk *renderer) void BufferViewHelper::release(RendererVk *renderer)
{ {
if (mView.valid()) std::vector<GarbageObject> garbage;
for (auto &formatAndView : mViews)
{ {
std::vector<GarbageObject> garbage; BufferView &view = formatAndView.second;
garbage.emplace_back(GetGarbage(&mView)); ASSERT(view.valid());
garbage.emplace_back(GetGarbage(&view));
}
if (!garbage.empty())
{
renderer->collectGarbage(std::move(mUse), std::move(garbage)); renderer->collectGarbage(std::move(mUse), std::move(garbage));
// Ensure the resource use is always valid. // Ensure the resource use is always valid.
mUse.init(); mUse.init();
} }
mViews.clear();
mOffset = 0;
mSize = 0;
// Update image view serial. // Update image view serial.
mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial(); mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
} }
void BufferViewHelper::destroy(VkDevice device) 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; mViewSerial = kInvalidImageOrBufferViewSerial;
} }
angle::Result BufferViewHelper::initView(ContextVk *contextVk, angle::Result BufferViewHelper::getView(ContextVk *contextVk,
const BufferHelper &buffer, const BufferHelper &buffer,
const Format &format, const Format &format,
VkDeviceSize offset, const BufferView **viewOut)
VkDeviceSize size)
{ {
ASSERT(format.valid()); 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 // 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 // be read anyway, and this is a requirement of Vulkan (for size to be a multiple of format
// texel block size). // texel block size).
const angle::Format &bufferFormat = format.actualBufferFormat(false); const angle::Format &bufferFormat = format.actualBufferFormat(false);
const GLuint pixelBytes = bufferFormat.pixelBytes; const GLuint pixelBytes = bufferFormat.pixelBytes;
size -= size % pixelBytes; VkDeviceSize size = mSize - mSize % pixelBytes;
VkBufferViewCreateInfo viewCreateInfo = {}; VkBufferViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; viewCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
viewCreateInfo.buffer = buffer.getBuffer().getHandle(); viewCreateInfo.buffer = buffer.getBuffer().getHandle();
viewCreateInfo.format = format.vkBufferFormat; viewCreateInfo.format = format.vkBufferFormat;
viewCreateInfo.offset = offset; viewCreateInfo.offset = mOffset;
viewCreateInfo.range = size; 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; return angle::Result::Continue;
} }
......
...@@ -2162,23 +2162,29 @@ class BufferViewHelper final : public Resource ...@@ -2162,23 +2162,29 @@ class BufferViewHelper final : public Resource
BufferViewHelper(BufferViewHelper &&other); BufferViewHelper(BufferViewHelper &&other);
~BufferViewHelper() override; ~BufferViewHelper() override;
void init(RendererVk *renderer); void init(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size);
void release(RendererVk *renderer); void release(RendererVk *renderer);
void destroy(VkDevice device); void destroy(VkDevice device);
const BufferView &getView() const { return mView; } angle::Result getView(ContextVk *contextVk,
const BufferHelper &buffer,
angle::Result initView(ContextVk *contextVk, const Format &format,
const BufferHelper &buffer, const BufferView **viewOut);
const Format &format,
VkDeviceSize offset,
VkDeviceSize size);
// Return unique Serial for a bufferView. // Return unique Serial for a bufferView.
ImageOrBufferViewSubresourceSerial getSerial() const; ImageOrBufferViewSubresourceSerial getSerial() const;
private: 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 // Serial for the buffer view. An ImageOrBufferViewSerial is used for texture buffers so that
// they fit together with the other texture types. // they fit together with the other texture types.
......
...@@ -186,9 +186,6 @@ ...@@ -186,9 +186,6 @@
// Cannot create 2D (array) view of 3D texture. // Cannot create 2D (array) view of 3D texture.
3886 VULKAN : dEQP-GLES31.functional.image_load_store.3d.*layer = FAIL 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 //// 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