Commit d84728e0 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Fix copySubImage to non-cube-complete images.

When copying to a non-cube-complete level of a texture we would fail because we would try to get the base level's current format. Instead we can get the format of the level that is being copied to. Bug: angleproject:2911 Change-Id: Ib6a5c5cef67ad9c880c1b76ea71ed9317eb20c97 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1483951 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent 979f3bbe
......@@ -282,7 +282,7 @@ angle::Result TextureVk::copySubImage(const gl::Context *context,
const gl::Rectangle &sourceArea,
gl::Framebuffer *source)
{
const gl::InternalFormat &currentFormat = *mState.getBaseLevelDesc().format.info;
const gl::InternalFormat &currentFormat = *mState.getImageDesc(index).format.info;
return copySubImageImpl(context, index, destOffset, sourceArea, currentFormat, source);
}
......@@ -408,7 +408,8 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
ASSERT(offsetImageIndex.getLayerCount() == 1);
return copySubImageImplWithDraw(contextVk, offsetImageIndex, modifiedDestOffset, destFormat,
0, clippedSourceArea, isViewportFlipY, false, false, false,
0, colorReadRT->getLayerIndex(), clippedSourceArea,
isViewportFlipY, false, false, false,
&colorReadRT->getImage(), colorReadRT->getReadImageView());
}
......@@ -457,7 +458,7 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
if (CanCopyWithDraw(renderer, sourceVkFormat, destVkFormat) && !forceCpuPath)
{
return copySubImageImplWithDraw(contextVk, offsetImageIndex, destOffset, destVkFormat,
sourceLevel, sourceArea, false, unpackFlipY,
sourceLevel, 0, sourceArea, false, unpackFlipY,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
&source->getImage(), &source->getReadImageView());
}
......@@ -607,6 +608,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
const gl::Offset &destOffset,
const vk::Format &destFormat,
size_t sourceLevel,
size_t sourceLayer,
const gl::Rectangle &sourceArea,
bool isSrcFlipY,
bool unpackFlipY,
......@@ -637,6 +639,33 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : 0;
uint32_t layerCount = index.getLayerCount();
// If the source image is a cube map, the view is of VK_IMAGE_VIEW_TYPE_CUBE type. However,
// GLSL's texelFetch cannot take a textureCube. We need to create a 2D_ARRAY type view to be
// able to perform the copy.
//
// Note(syoussefi): Array textures are not yet supported in Vulkan. Once they are, the if below
// should be changed to detect cube maps only.
vk::ImageView cubeAs2DArrayView;
if (srcImage->getLayerCount() % 6 == 0)
{
// TODO(syoussefi): If the cube map is LUMA, we need swizzle. http://anglebug.com/2911
// This can't happen when copying from framebuffers, so only source of concern would be
// copy[Sub]Texture copying from a LUMA cube map.
ASSERT(!srcImage->getFormat().textureFormat().isLUMA());
gl::TextureType arrayTextureType =
Get2DTextureType(srcImage->getLayerCount(), srcImage->getSamples());
ANGLE_TRY(srcImage->initImageView(contextVk, arrayTextureType, VK_IMAGE_ASPECT_COLOR_BIT,
gl::SwizzleState(), &cubeAs2DArrayView, 0,
srcImage->getLevelCount()));
srcView = &cubeAs2DArrayView;
}
else
{
// Source layer is otherwise baked into the view
sourceLayer = 0;
}
// If destination is valid, copy the source directly into it.
if (mImage->valid())
{
......@@ -645,7 +674,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
{
params.srcLayer = layerIndex;
params.srcLayer = sourceLayer + layerIndex;
vk::ImageView *destView;
ANGLE_TRY(
......@@ -673,7 +702,7 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
{
params.srcLayer = layerIndex;
params.srcLayer = sourceLayer + layerIndex;
// Create a temporary view for this layer.
vk::ImageView stagingView;
......@@ -695,6 +724,11 @@ angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
gl::Extents(sourceArea.width, sourceArea.height, 1));
}
if (cubeAs2DArrayView.valid())
{
renderer->releaseObject(currentQueueSerial, &cubeAs2DArrayView);
}
return angle::Result::Continue;
}
......
......@@ -240,6 +240,7 @@ class TextureVk : public TextureImpl
const gl::Offset &destOffset,
const vk::Format &destFormat,
size_t sourceLevel,
size_t sourceLayer,
const gl::Rectangle &sourceArea,
bool isSrcFlipY,
bool unpackFlipY,
......
......@@ -371,6 +371,120 @@ TEST_P(CopyTexImageTest, SubDefaultFramebuffer)
EXPECT_GL_NO_ERROR();
}
// Calling CopyTexSubImage from cubeMap texture.
TEST_P(CopyTexImageTest, CopyTexSubImageFromCubeMap)
{
// TODO: Diagnose and fix. http://anglebug.com/2954
ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel());
constexpr GLsizei kCubeMapFaceCount = 6;
// The framebuffer will be a face of a cube map with a different colors for each face. Each
// glCopyTexSubImage2D will take one face of this image to copy over a pixel in a 1x6
// framebuffer.
GLColor fboPixels[kCubeMapFaceCount] = {GLColor::red, GLColor::yellow, GLColor::green,
GLColor::cyan, GLColor::blue, GLColor::magenta};
GLColor whitePixels[kCubeMapFaceCount] = {GLColor::white, GLColor::white, GLColor::white,
GLColor::white, GLColor::white, GLColor::white};
GLTexture fboTex;
glBindTexture(GL_TEXTURE_CUBE_MAP, fboTex);
for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
face++)
{
GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
glTexImage2D(face, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &fboPixels[faceIndex]);
}
GLTexture dstTex;
glBindTexture(GL_TEXTURE_2D, dstTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kCubeMapFaceCount, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
whitePixels);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
face++)
{
GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face, fboTex, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Copy the fbo (a cube map face) into a pixel of the destination texture.
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, faceIndex, 0, 0, 0, 1, 1);
}
// Make sure all the copies are done correctly.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
for (GLsizei faceIndex = 0; faceIndex < kCubeMapFaceCount; ++faceIndex)
{
EXPECT_PIXEL_COLOR_EQ(faceIndex, 0, fboPixels[faceIndex]);
}
}
// Calling CopyTexSubImage to a non-cube-complete texture.
TEST_P(CopyTexImageTest, CopyTexSubImageToNonCubeCompleteDestination)
{
constexpr GLsizei kCubeMapFaceCount = 6;
// The framebuffer will be a 1x6 image with 6 different colors. Each glCopyTexSubImage2D will
// take one pixel of this image to copy over each face of a cube map.
GLColor fboPixels[kCubeMapFaceCount] = {GLColor::red, GLColor::yellow, GLColor::green,
GLColor::cyan, GLColor::blue, GLColor::magenta};
GLColor whitePixel = GLColor::white;
GLTexture fboTex;
glBindTexture(GL_TEXTURE_2D, fboTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kCubeMapFaceCount, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
fboPixels);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
GLTexture cubeMap;
glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMap);
for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
face++)
{
GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
// Initialize the face with a color not found in the fbo.
glTexImage2D(face, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &whitePixel);
// Copy one pixel from the fbo into this face. The first 5 copies are done on a
// non-cube-complete texture.
glCopyTexSubImage2D(face, 0, 0, 0, faceIndex, 0, 1, 1);
}
// Make sure all the copies are done correctly.
for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
face++)
{
GLsizei faceIndex = face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, face, cubeMap, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
EXPECT_PIXEL_COLOR_EQ(0, 0, fboPixels[faceIndex]);
}
}
// specialization of CopyTexImageTest is added so that some tests can be explicitly run with an ES3
// context
class CopyTexImageTestES3 : public CopyTexImageTest
......
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