Commit 36787dcb by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix PBO assuming color images

Bug: b/172354898 Change-Id: I777eaa33ddac853492d38a03c16caeddad0c2d16 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2520108 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarIan Elliott <ianelliott@google.com>
parent 72001c7d
...@@ -41,6 +41,9 @@ constexpr VkImageUsageFlags kTransferStagingImageFlags = ...@@ -41,6 +41,9 @@ constexpr VkImageUsageFlags kTransferStagingImageFlags =
constexpr VkFormatFeatureFlags kBlitFeatureFlags = constexpr VkFormatFeatureFlags kBlitFeatureFlags =
VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
constexpr VkImageAspectFlags kDepthStencilAspects =
VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
constexpr angle::SubjectIndex kTextureImageSubjectIndex = 0; constexpr angle::SubjectIndex kTextureImageSubjectIndex = 0;
// Test whether a texture level is within the range of levels for which the current image is // Test whether a texture level is within the range of levels for which the current image is
...@@ -433,8 +436,14 @@ angle::Result TextureVk::setSubImageImpl(const gl::Context *context, ...@@ -433,8 +436,14 @@ angle::Result TextureVk::setSubImageImpl(const gl::Context *context,
size_t offsetBytes = static_cast<size_t>(offset + inputSkipBytes); size_t offsetBytes = static_cast<size_t>(offset + inputSkipBytes);
// Note: cannot directly copy from a depth/stencil PBO. GL requires depth and stencil data
// to be packed, while Vulkan requires them to be separate.
const VkImageAspectFlags aspectFlags = vk::GetFormatAspectFlags(vkFormat.intendedFormat());
const bool isCombinedDepthStencil =
(aspectFlags & kDepthStencilAspects) == kDepthStencilAspects;
if (!shouldUpdateBeStaged(gl::LevelIndex(index.getLevelIndex())) && if (!shouldUpdateBeStaged(gl::LevelIndex(index.getLevelIndex())) &&
isFastUnpackPossible(vkFormat, offsetBytes)) isFastUnpackPossible(vkFormat, offsetBytes) && !isCombinedDepthStencil)
{ {
GLuint pixelSize = formatInfo.pixelBytes; GLuint pixelSize = formatInfo.pixelBytes;
GLuint blockWidth = formatInfo.compressedBlockWidth; GLuint blockWidth = formatInfo.compressedBlockWidth;
...@@ -451,7 +460,7 @@ angle::Result TextureVk::setSubImageImpl(const gl::Context *context, ...@@ -451,7 +460,7 @@ angle::Result TextureVk::setSubImageImpl(const gl::Context *context,
GLuint imageHeightPixels = inputDepthPitch / inputRowPitch * blockHeight; GLuint imageHeightPixels = inputDepthPitch / inputRowPitch * blockHeight;
ANGLE_TRY(copyBufferDataToImage(contextVk, &bufferHelper, index, rowLengthPixels, ANGLE_TRY(copyBufferDataToImage(contextVk, &bufferHelper, index, rowLengthPixels,
imageHeightPixels, area, offsetBytes)); imageHeightPixels, area, offsetBytes, aspectFlags));
} }
else else
{ {
...@@ -1547,7 +1556,8 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk, ...@@ -1547,7 +1556,8 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
uint32_t rowLength, uint32_t rowLength,
uint32_t imageHeight, uint32_t imageHeight,
const gl::Box &sourceArea, const gl::Box &sourceArea,
size_t offset) size_t offset,
VkImageAspectFlags aspectFlags)
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyBufferDataToImage"); ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyBufferDataToImage");
...@@ -1558,6 +1568,8 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk, ...@@ -1558,6 +1568,8 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
GLuint layerCount = index.getLayerCount(); GLuint layerCount = index.getLayerCount();
GLuint layerIndex = 0; GLuint layerIndex = 0;
ASSERT((aspectFlags & kDepthStencilAspects) != kDepthStencilAspects);
VkBufferImageCopy region = {}; VkBufferImageCopy region = {};
region.bufferOffset = offset; region.bufferOffset = offset;
region.bufferRowLength = rowLength; region.bufferRowLength = rowLength;
...@@ -1568,7 +1580,7 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk, ...@@ -1568,7 +1580,7 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
region.imageOffset.x = sourceArea.x; region.imageOffset.x = sourceArea.x;
region.imageOffset.y = sourceArea.y; region.imageOffset.y = sourceArea.y;
region.imageOffset.z = sourceArea.z; region.imageOffset.z = sourceArea.z;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.aspectMask = aspectFlags;
region.imageSubresource.layerCount = layerCount; region.imageSubresource.layerCount = layerCount;
region.imageSubresource.mipLevel = mImage->toVkLevel(level).get(); region.imageSubresource.mipLevel = mImage->toVkLevel(level).get();
...@@ -1585,7 +1597,7 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk, ...@@ -1585,7 +1597,7 @@ angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer)); ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer));
ANGLE_TRY(contextVk->onImageTransferWrite(level, 1, layerIndex, layerCount, ANGLE_TRY(contextVk->onImageTransferWrite(level, 1, layerIndex, layerCount,
VK_IMAGE_ASPECT_COLOR_BIT, mImage)); mImage->getAspectFlags(), mImage));
vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer(); vk::CommandBuffer &commandBuffer = contextVk->getOutsideRenderPassCommandBuffer();
......
...@@ -325,7 +325,8 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -325,7 +325,8 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
uint32_t rowLength, uint32_t rowLength,
uint32_t imageHeight, uint32_t imageHeight,
const gl::Box &sourceArea, const gl::Box &sourceArea,
size_t offset); size_t offset,
VkImageAspectFlags aspectFlags);
// Called from syncState to prepare the image for mipmap generation. // Called from syncState to prepare the image for mipmap generation.
void prepareForGenerateMipmap(ContextVk *contextVk); void prepareForGenerateMipmap(ContextVk *contextVk);
......
...@@ -2591,6 +2591,236 @@ TEST_P(Texture2DTest, TexImageWithRGBA5551PBO) ...@@ -2591,6 +2591,236 @@ TEST_P(Texture2DTest, TexImageWithRGBA5551PBO)
EXPECT_PIXEL_EQ(width / 2 - 1, height / 2 - 1, 0, 255, 0, 255); EXPECT_PIXEL_EQ(width / 2 - 1, height / 2 - 1, 0, 255, 0, 255);
} }
// Test that glTexSubImage2D combined with a PBO works properly when glTexStorage2D has
// initialized the image with a depth-only format.
TEST_P(Texture2DTestES3, TexImageWithDepthPBO)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_pixel_buffer_object"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_storage"));
// http://anglebug.com/5315
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
// http://anglebug.com/5316
ANGLE_SKIP_TEST_IF(IsMetal() && IsOSX());
constexpr GLsizei kSize = 4;
// Set up the framebuffer.
GLTexture colorTexture;
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
GLTexture depthTexture;
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, kSize, kSize);
ASSERT_GL_NO_ERROR();
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
// Clear depth to 0, ensuring the texture's image is allocated.
glClearDepthf(0);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
// Fill depth with 1.0f.
std::vector<GLushort> pixels(kSize * kSize);
for (size_t pixelId = 0; pixelId < pixels.size(); ++pixelId)
{
pixels[pixelId] = 0xFFFF;
}
GLuint pbo;
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, pixels.size() * sizeof(pixels[0]), pixels.data(),
GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
// Upload PBO data.
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT,
nullptr);
// If depth is not set to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// Draw red
ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.95f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::red);
}
// Test that glTexSubImage2D combined with a PBO works properly when glTexStorage2D has
// initialized the image with a stencil-only format.
TEST_P(Texture2DTestES3, TexImageWithStencilPBO)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_pixel_buffer_object"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_storage"));
// http://anglebug.com/5313
ANGLE_SKIP_TEST_IF(IsVulkan() && (IsAndroid() || (IsWindows() && IsIntel())));
// http://anglebug.com/5315
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
// http://anglebug.com/5316
ANGLE_SKIP_TEST_IF(IsMetal() && IsOSX());
// http://anglebug.com/5317
ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D());
constexpr GLsizei kSize = 4;
// Set up the framebuffer.
GLTexture colorTexture;
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
GLTexture stencilTexture;
glBindTexture(GL_TEXTURE_2D, stencilTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_STENCIL_INDEX8, kSize, kSize);
ASSERT_GL_NO_ERROR();
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
// Clear stencil to 0, ensuring the texture's image is allocated.
glClearStencil(0);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
// Fill stencil with 0x4E
std::vector<GLubyte> pixels(kSize * kSize);
for (size_t pixelId = 0; pixelId < pixels.size(); ++pixelId)
{
pixels[pixelId] = 0x4E;
}
GLuint pbo;
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, pixels.size() * sizeof(pixels[0]), pixels.data(),
GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
// Upload PBO data.
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
nullptr);
ASSERT_GL_NO_ERROR();
// If stencil is not set to 0x4E, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0x4E, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Draw red
ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.95f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::red);
}
// Test that glTexSubImage2D combined with a PBO works properly when glTexStorage2D has
// initialized the image with a depth/stencil format.
TEST_P(Texture2DTestES3, TexImageWithDepthStencilPBO)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_pixel_buffer_object"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_storage"));
// http://anglebug.com/5313
ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
// http://anglebug.com/5315
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsOSX());
// http://anglebug.com/5316
ANGLE_SKIP_TEST_IF(IsMetal() && IsOSX());
// http://anglebug.com/5317
ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D());
constexpr GLsizei kSize = 4;
// Set up the framebuffer.
GLTexture colorTexture;
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
GLTexture depthStencilTexture;
glBindTexture(GL_TEXTURE_2D, depthStencilTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, kSize, kSize);
ASSERT_GL_NO_ERROR();
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
depthStencilTexture, 0);
ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
ASSERT_GL_NO_ERROR();
// Clear depth and stencil to 0, ensuring the texture's image is allocated.
glClearDepthf(0);
glClearStencil(0);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
// Fill depth with 1.0f and stencil with 0xD5
std::vector<GLuint> pixels(kSize * kSize);
for (size_t pixelId = 0; pixelId < pixels.size(); ++pixelId)
{
pixels[pixelId] = 0xFFFFFFD5;
}
GLuint pbo;
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, pixels.size() * sizeof(pixels[0]), pixels.data(),
GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
// Upload PBO data.
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8,
nullptr);
// If depth is not set to 1, rendering would fail.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// If stencil is not set to 0xD5, rendering would fail.
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 0xD5, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilMask(0xFF);
// Draw red
ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.95f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, GLColor::red);
}
// Tests CopySubImage for float formats // Tests CopySubImage for float formats
TEST_P(Texture2DTest, CopySubImageFloat_R_R) TEST_P(Texture2DTest, CopySubImageFloat_R_R)
{ {
......
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