Commit 61a117fa by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix aliasing format for non-layered image bindings

This was correctly handled for layered bindings by the change anglebug.com/3885#c20. This change uses the same mechanism for non-layered bindings. Bug: angleproject:5347 Change-Id: Ida55b3589d0bdbe5d824c1614c9bf9f867a7f652 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2541182Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 738092ae
...@@ -2520,18 +2520,23 @@ angle::Result TextureVk::getStorageImageView(ContextVk *contextVk, ...@@ -2520,18 +2520,23 @@ angle::Result TextureVk::getStorageImageView(ContextVk *contextVk,
angle::FormatID formatID = angle::Format::InternalFormatToID(binding.format); angle::FormatID formatID = angle::Format::InternalFormatToID(binding.format);
const vk::Format &format = contextVk->getRenderer()->getFormat(formatID); const vk::Format &format = contextVk->getRenderer()->getFormat(formatID);
gl::LevelIndex nativeLevelGL =
getNativeImageLevel(gl::LevelIndex(static_cast<uint32_t>(binding.level)));
vk::LevelIndex nativeLevelVk = mImage->toVkLevel(nativeLevelGL);
if (binding.layered != GL_TRUE) if (binding.layered != GL_TRUE)
{ {
return getLevelLayerImageView(contextVk, gl::LevelIndex(binding.level), binding.layer, uint32_t nativeLayer = getNativeImageLayer(static_cast<uint32_t>(binding.layer));
imageViewOut);
return getImageViews().getLevelLayerStorageImageView(
contextVk, *mImage, nativeLevelVk, nativeLayer,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, format.vkImageFormat,
imageViewOut);
} }
gl::LevelIndex nativeLevelGL = uint32_t nativeLayer = getNativeImageLayer(0);
getNativeImageLevel(gl::LevelIndex(static_cast<uint32_t>(binding.level)));
vk::LevelIndex nativeLevelVk = mImage->toVkLevel(nativeLevelGL);
uint32_t nativeLayer = getNativeImageLayer(0);
return getImageViews().getLevelDrawImageView( return getImageViews().getLevelStorageImageView(
contextVk, mState.getType(), *mImage, nativeLevelVk, nativeLayer, contextVk, mState.getType(), *mImage, nativeLevelVk, nativeLayer,
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, format.vkImageFormat, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, format.vkImageFormat,
imageViewOut); imageViewOut);
......
...@@ -529,6 +529,24 @@ ImageView *GetLevelImageView(ImageViewVector *imageViews, LevelIndex levelVk, ui ...@@ -529,6 +529,24 @@ ImageView *GetLevelImageView(ImageViewVector *imageViews, LevelIndex levelVk, ui
return &(*imageViews)[levelVk.get()]; return &(*imageViews)[levelVk.get()];
} }
ImageView *GetLevelLayerImageView(LayerLevelImageViewVector *imageViews,
LevelIndex levelVk,
uint32_t layer,
uint32_t levelCount,
uint32_t layerCount)
{
// Lazily allocate the storage for image views. We allocate the full layer count because we
// don't want to trigger any std::vector reallocations. Reallocations could invalidate our
// view pointers.
if (imageViews->empty())
{
imageViews->resize(layerCount);
}
ASSERT(imageViews->size() > layer);
return GetLevelImageView(&(*imageViews)[layer], levelVk, levelCount);
}
// Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
// into a depth or stencil section of the destination buffer. See the spec: // into a depth or stencil section of the destination buffer. See the spec:
// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
...@@ -6308,8 +6326,9 @@ ImageViewHelper::ImageViewHelper(ImageViewHelper &&other) : Resource(std::move(o ...@@ -6308,8 +6326,9 @@ ImageViewHelper::ImageViewHelper(ImageViewHelper &&other) : Resource(std::move(o
std::swap(mLinearColorspace, other.mLinearColorspace); std::swap(mLinearColorspace, other.mLinearColorspace);
std::swap(mPerLevelStencilReadImageViews, other.mPerLevelStencilReadImageViews); std::swap(mPerLevelStencilReadImageViews, other.mPerLevelStencilReadImageViews);
std::swap(mLevelDrawImageViews, other.mLevelDrawImageViews);
std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews); std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
std::swap(mLevelStorageImageViews, other.mLevelStorageImageViews);
std::swap(mLayerLevelStorageImageViews, other.mLayerLevelStorageImageViews);
std::swap(mImageViewSerial, other.mImageViewSerial); std::swap(mImageViewSerial, other.mImageViewSerial);
} }
...@@ -6339,7 +6358,6 @@ void ImageViewHelper::release(RendererVk *renderer) ...@@ -6339,7 +6358,6 @@ void ImageViewHelper::release(RendererVk *renderer)
ReleaseImageViews(&mPerLevelStencilReadImageViews, &garbage); ReleaseImageViews(&mPerLevelStencilReadImageViews, &garbage);
// Release the draw views // Release the draw views
ReleaseImageViews(&mLevelDrawImageViews, &garbage);
for (ImageViewVector &layerViews : mLayerLevelDrawImageViews) for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
{ {
for (ImageView &imageView : layerViews) for (ImageView &imageView : layerViews)
...@@ -6352,6 +6370,20 @@ void ImageViewHelper::release(RendererVk *renderer) ...@@ -6352,6 +6370,20 @@ void ImageViewHelper::release(RendererVk *renderer)
} }
mLayerLevelDrawImageViews.clear(); mLayerLevelDrawImageViews.clear();
// Release the storage views
ReleaseImageViews(&mLevelStorageImageViews, &garbage);
for (ImageViewVector &layerViews : mLayerLevelStorageImageViews)
{
for (ImageView &imageView : layerViews)
{
if (imageView.valid())
{
garbage.emplace_back(GetGarbage(&imageView));
}
}
}
mLayerLevelStorageImageViews.clear();
if (!garbage.empty()) if (!garbage.empty())
{ {
renderer->collectGarbage(std::move(mUse), std::move(garbage)); renderer->collectGarbage(std::move(mUse), std::move(garbage));
...@@ -6378,7 +6410,6 @@ void ImageViewHelper::destroy(VkDevice device) ...@@ -6378,7 +6410,6 @@ void ImageViewHelper::destroy(VkDevice device)
DestroyImageViews(&mPerLevelStencilReadImageViews, device); DestroyImageViews(&mPerLevelStencilReadImageViews, device);
// Release the draw views // Release the draw views
DestroyImageViews(&mLevelDrawImageViews, device);
for (ImageViewVector &layerViews : mLayerLevelDrawImageViews) for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
{ {
for (ImageView &imageView : layerViews) for (ImageView &imageView : layerViews)
...@@ -6388,6 +6419,17 @@ void ImageViewHelper::destroy(VkDevice device) ...@@ -6388,6 +6419,17 @@ void ImageViewHelper::destroy(VkDevice device)
} }
mLayerLevelDrawImageViews.clear(); mLayerLevelDrawImageViews.clear();
// Release the storage views
DestroyImageViews(&mLevelStorageImageViews, device);
for (ImageViewVector &layerViews : mLayerLevelStorageImageViews)
{
for (ImageView &imageView : layerViews)
{
imageView.destroy(device);
}
}
mLayerLevelStorageImageViews.clear();
mImageViewSerial = kInvalidImageOrBufferViewSerial; mImageViewSerial = kInvalidImageOrBufferViewSerial;
} }
...@@ -6578,20 +6620,21 @@ angle::Result ImageViewHelper::initSRGBReadViewsImpl(ContextVk *contextVk, ...@@ -6578,20 +6620,21 @@ angle::Result ImageViewHelper::initSRGBReadViewsImpl(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ImageViewHelper::getLevelDrawImageView(ContextVk *contextVk, angle::Result ImageViewHelper::getLevelStorageImageView(ContextVk *contextVk,
gl::TextureType viewType, gl::TextureType viewType,
const ImageHelper &image, const ImageHelper &image,
LevelIndex levelVk, LevelIndex levelVk,
uint32_t layer, uint32_t layer,
VkImageUsageFlags imageUsageFlags, VkImageUsageFlags imageUsageFlags,
VkFormat vkImageFormat, VkFormat vkImageFormat,
const ImageView **imageViewOut) const ImageView **imageViewOut)
{ {
ASSERT(mImageViewSerial.valid()); ASSERT(mImageViewSerial.valid());
retain(&contextVk->getResourceUseList()); retain(&contextVk->getResourceUseList());
ImageView *imageView = GetLevelImageView(&mLevelDrawImageViews, levelVk, image.getLevelCount()); ImageView *imageView =
GetLevelImageView(&mLevelStorageImageViews, levelVk, image.getLevelCount());
*imageViewOut = imageView; *imageViewOut = imageView;
if (imageView->valid()) if (imageView->valid())
...@@ -6605,6 +6648,37 @@ angle::Result ImageViewHelper::getLevelDrawImageView(ContextVk *contextVk, ...@@ -6605,6 +6648,37 @@ angle::Result ImageViewHelper::getLevelDrawImageView(ContextVk *contextVk,
image.getLayerCount(), imageUsageFlags, vkImageFormat); image.getLayerCount(), imageUsageFlags, vkImageFormat);
} }
angle::Result ImageViewHelper::getLevelLayerStorageImageView(ContextVk *contextVk,
const ImageHelper &image,
LevelIndex levelVk,
uint32_t layer,
VkImageUsageFlags imageUsageFlags,
VkFormat vkImageFormat,
const ImageView **imageViewOut)
{
ASSERT(image.valid());
ASSERT(mImageViewSerial.valid());
ASSERT(!image.getFormat().actualImageFormat().isBlock);
retain(&contextVk->getResourceUseList());
ImageView *imageView =
GetLevelLayerImageView(&mLayerLevelStorageImageViews, levelVk, layer, image.getLevelCount(),
GetImageLayerCountForView(image));
*imageViewOut = imageView;
if (imageView->valid())
{
return angle::Result::Continue;
}
// Create the view. Note that storage images are not affected by swizzle parameters.
gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
return image.initAliasedLayerImageView(contextVk, viewType, image.getAspectFlags(),
gl::SwizzleState(), imageView, levelVk, 1, layer, 1,
imageUsageFlags, vkImageFormat);
}
angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk, angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk,
const ImageHelper &image, const ImageHelper &image,
LevelIndex levelVk, LevelIndex levelVk,
...@@ -6617,17 +6691,10 @@ angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk, ...@@ -6617,17 +6691,10 @@ angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk,
retain(&contextVk->getResourceUseList()); retain(&contextVk->getResourceUseList());
uint32_t layerCount = GetImageLayerCountForView(image);
// Lazily allocate the storage for image views // Lazily allocate the storage for image views
if (mLayerLevelDrawImageViews.empty())
{
mLayerLevelDrawImageViews.resize(layerCount);
}
ASSERT(mLayerLevelDrawImageViews.size() > layer);
ImageView *imageView = ImageView *imageView =
GetLevelImageView(&mLayerLevelDrawImageViews[layer], levelVk, image.getLevelCount()); GetLevelLayerImageView(&mLayerLevelDrawImageViews, levelVk, layer, image.getLevelCount(),
GetImageLayerCountForView(image));
*imageViewOut = imageView; *imageViewOut = imageView;
if (imageView->valid()) if (imageView->valid())
......
...@@ -2029,17 +2029,26 @@ class ImageViewHelper final : public Resource ...@@ -2029,17 +2029,26 @@ class ImageViewHelper final : public Resource
bool requiresSRGBViews, bool requiresSRGBViews,
VkImageUsageFlags imageUsageFlags); VkImageUsageFlags imageUsageFlags);
// Creates a view with all layers of the level. // Creates a storage view with all layers of the level.
angle::Result getLevelDrawImageView(ContextVk *contextVk, angle::Result getLevelStorageImageView(ContextVk *contextVk,
gl::TextureType viewType, gl::TextureType viewType,
const ImageHelper &image, const ImageHelper &image,
LevelIndex levelVk, LevelIndex levelVk,
uint32_t layer, uint32_t layer,
VkImageUsageFlags imageUsageFlags, VkImageUsageFlags imageUsageFlags,
VkFormat vkImageFormat, VkFormat vkImageFormat,
const ImageView **imageViewOut); const ImageView **imageViewOut);
// Creates a view with a single layer of the level. // Creates a storage view with a single layer of the level.
angle::Result getLevelLayerStorageImageView(ContextVk *contextVk,
const ImageHelper &image,
LevelIndex levelVk,
uint32_t layer,
VkImageUsageFlags imageUsageFlags,
VkFormat vkImageFormat,
const ImageView **imageViewOut);
// Creates a draw view with a single layer of the level.
angle::Result getLevelLayerDrawImageView(ContextVk *contextVk, angle::Result getLevelLayerDrawImageView(ContextVk *contextVk,
const ImageHelper &image, const ImageHelper &image,
LevelIndex levelVk, LevelIndex levelVk,
...@@ -2135,10 +2144,13 @@ class ImageViewHelper final : public Resource ...@@ -2135,10 +2144,13 @@ class ImageViewHelper final : public Resource
bool mLinearColorspace; bool mLinearColorspace;
// Draw views. // Draw views
ImageViewVector mLevelDrawImageViews;
LayerLevelImageViewVector mLayerLevelDrawImageViews; LayerLevelImageViewVector mLayerLevelDrawImageViews;
// Storage views
ImageViewVector mLevelStorageImageViews;
LayerLevelImageViewVector mLayerLevelStorageImageViews;
// Serial for the image view set. getSubresourceSerial combines it with subresource info. // Serial for the image view set. getSubresourceSerial combines it with subresource info.
ImageOrBufferViewSerial mImageViewSerial; ImageOrBufferViewSerial mImageViewSerial;
}; };
......
...@@ -4050,6 +4050,127 @@ void main() { ...@@ -4050,6 +4050,127 @@ void main() {
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER); glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
} }
// Write to image array with an aliasing format.
TEST_P(ComputeShaderTest, AliasingFormatForImageArray)
{
// http://anglebug.com/5352
ANGLE_SKIP_TEST_IF(IsD3D11());
constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=2) in;
layout(r32ui, binding = 0) writeonly uniform highp uimage2DArray image;
void main()
{
uint yellow = 0xFF00FFFFu;
imageStore(image, ivec3(gl_LocalInvocationID.xyz), uvec4(yellow, 0, 0, 0));
})";
constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
const std::vector<GLColor> kInitData(kWidth * kHeight * kDepth, GLColor::black);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, kWidth, kHeight, kDepth);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
GL_UNSIGNED_BYTE, kInitData.data());
EXPECT_GL_NO_ERROR();
ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
glUseProgram(program);
// Output yellow to both layers.
glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
// Verify results.
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
EXPECT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 1);
EXPECT_GL_NO_ERROR();
glReadBuffer(GL_COLOR_ATTACHMENT0);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
glReadBuffer(GL_COLOR_ATTACHMENT1);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
}
// Write to one layer of image array with an aliasing format.
TEST_P(ComputeShaderTest, AliasingFormatForOneLayerOfImageArray)
{
// http://anglebug.com/5352
ANGLE_SKIP_TEST_IF(IsD3D11());
constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(r32ui, binding = 0) writeonly uniform highp uimage2D image;
void main()
{
uint yellow = 0xFF00FFFFu;
imageStore(image, ivec2(gl_LocalInvocationID.xy), uvec4(yellow, 0, 0, 0));
})";
constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
const std::vector<GLColor> kInitData(kWidth * kHeight * kDepth, GLColor::black);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, kWidth, kHeight, kDepth);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
GL_UNSIGNED_BYTE, kInitData.data());
EXPECT_GL_NO_ERROR();
GLFramebuffer framebuffer;
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 1);
EXPECT_GL_NO_ERROR();
ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
glUseProgram(program);
// Output yellow to layer 0.
glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
// Verify that only layer 0 was changed.
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
EXPECT_GL_NO_ERROR();
glReadBuffer(GL_COLOR_ATTACHMENT0);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
glReadBuffer(GL_COLOR_ATTACHMENT1);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
// Reset texture back to black.
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
GL_UNSIGNED_BYTE, kInitData.data());
// Output yellow to layer 1.
glBindImageTexture(0, texture, 0, GL_FALSE, 1, GL_WRITE_ONLY, GL_R32UI);
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
// Verify that only layer 1 was changed.
glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
EXPECT_GL_NO_ERROR();
glReadBuffer(GL_COLOR_ATTACHMENT0);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
glReadBuffer(GL_COLOR_ATTACHMENT1);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
}
ANGLE_INSTANTIATE_TEST_ES31(ComputeShaderTest); ANGLE_INSTANTIATE_TEST_ES31(ComputeShaderTest);
ANGLE_INSTANTIATE_TEST_ES3(ComputeShaderTestES3); ANGLE_INSTANTIATE_TEST_ES3(ComputeShaderTestES3);
ANGLE_INSTANTIATE_TEST_ES31(WebGL2ComputeTest); ANGLE_INSTANTIATE_TEST_ES31(WebGL2ComputeTest);
......
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