Commit eb0479e2 by Cody Northrop Committed by Commit Bot

Vulkan: Texture 3D and 2DArray layers as framebuffer attachments

Support glFramebufferTextureLayer by correctly handling layers from 3D and 2DArray textures. Modeled after CubeMap layers support. Bug: angleproject:3188 Bug: angleproject:3189 Change-Id: Ic73a6017134e9d2b49beed103487454397a97167 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1738436Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Cody Northrop <cnorthrop@google.com>
parent bd203b57
......@@ -1439,9 +1439,23 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
size_t level = renderTarget->getLevelIndex();
size_t layer = renderTarget->getLayerIndex();
VkOffset3D srcOffset = {area.x, area.y, 0};
VkImageSubresourceLayers srcSubresource = {};
srcSubresource.aspectMask = copyAspectFlags;
srcSubresource.mipLevel = level;
srcSubresource.baseArrayLayer = layer;
srcSubresource.layerCount = 1;
VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
1};
if (srcImage->getExtents().depth > 1)
{
// Depth > 1 means this is a 3D texture and we need special handling
srcOffset.z = layer;
srcSubresource.baseArrayLayer = 0;
}
// If the source image is multisampled, we need to resolve it into a temporary image before
// performing a readback.
bool isMultisampled = srcImage->getSamples() > 1;
......@@ -1461,10 +1475,7 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
VkImageResolve resolveRegion = {};
resolveRegion.srcSubresource.aspectMask = copyAspectFlags;
resolveRegion.srcSubresource.mipLevel = level;
resolveRegion.srcSubresource.baseArrayLayer = layer;
resolveRegion.srcSubresource.layerCount = 1;
resolveRegion.srcSubresource = srcSubresource;
resolveRegion.srcOffset = srcOffset;
resolveRegion.dstSubresource.aspectMask = copyAspectFlags;
resolveRegion.dstSubresource.mipLevel = 0;
......@@ -1483,6 +1494,9 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
level = 0;
layer = 0;
srcOffset = {0, 0, 0};
srcSubresource.baseArrayLayer = 0;
srcSubresource.layerCount = 1;
srcSubresource.mipLevel = 0;
}
VkBuffer bufferHandle = VK_NULL_HANDLE;
......@@ -1493,16 +1507,13 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
ANGLE_TRY(mReadPixelBuffer.allocate(contextVk, allocationSize, &readPixelBuffer, &bufferHandle,
&stagingOffset, nullptr));
VkBufferImageCopy region = {};
region.bufferImageHeight = srcExtent.height;
region.bufferOffset = stagingOffset;
region.bufferRowLength = srcExtent.width;
region.imageExtent = srcExtent;
region.imageOffset = srcOffset;
region.imageSubresource.aspectMask = copyAspectFlags;
region.imageSubresource.baseArrayLayer = layer;
region.imageSubresource.layerCount = 1;
region.imageSubresource.mipLevel = level;
VkBufferImageCopy region = {};
region.bufferImageHeight = srcExtent.height;
region.bufferOffset = stagingOffset;
region.bufferRowLength = srcExtent.width;
region.imageExtent = srcExtent;
region.imageOffset = srcOffset;
region.imageSubresource = srcSubresource;
commandBuffer->copyImageToBuffer(srcImage->getImage(), srcImage->getCurrentLayout(),
bufferHandle, 1, &region);
......
......@@ -65,6 +65,12 @@ bool ForceCpuPathForCopy(RendererVk *renderer, vk::ImageHelper *image)
{
return image->getLayerCount() > 1 && renderer->getFeatures().forceCpuPathForCubeMapCopy.enabled;
}
uint32_t GetRenderTargetLayerCount(vk::ImageHelper *image)
{
// Depth > 1 means this is a 3D texture and depth is our layer count
return image->getExtents().depth > 1 ? image->getExtents().depth : image->getLayerCount();
}
} // anonymous namespace
angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
......@@ -892,8 +898,9 @@ void TextureVk::setImageHelper(ContextVk *contextVk,
mRenderTarget.init(mImage, &mDrawBaseLevelImageView, &mFetchBaseLevelImageView,
getNativeImageLevel(0), getNativeImageLayer(0));
// Force re-creation of cube map render targets next time they are needed
// Force re-creation of layered render targets next time they are needed
mCubeMapRenderTargets.clear();
m3DRenderTargets.clear();
mSerial = contextVk->generateTextureSerial();
}
......@@ -1116,6 +1123,11 @@ angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
case gl::TextureType::_2D:
*rtOut = &mRenderTarget;
break;
case gl::TextureType::_2DArray:
case gl::TextureType::_3D:
ANGLE_TRY(init3DRenderTargets(contextVk));
*rtOut = &m3DRenderTargets[imageIndex.getLayerIndex()];
break;
case gl::TextureType::CubeMap:
ANGLE_TRY(initCubeMapRenderTargets(contextVk));
*rtOut = &mCubeMapRenderTargets[imageIndex.cubeMapFaceIndex()];
......@@ -1162,6 +1174,38 @@ angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk,
commandBuffer);
}
angle::Result TextureVk::init3DRenderTargets(ContextVk *contextVk)
{
// Lazy init. Check if already initialized.
if (!m3DRenderTargets.empty())
return angle::Result::Continue;
uint32_t layerCount = GetRenderTargetLayerCount(mImage);
mLayerFetchImageView.resize(layerCount);
m3DRenderTargets.resize(layerCount);
for (size_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
{
vk::ImageView *drawView;
ANGLE_TRY(getLayerLevelDrawImageView(contextVk, layerIndex, 0, &drawView));
// Users of the render target expect the views to directly view the desired layer, so we
// need create a fetch view for each layer as well.
gl::SwizzleState mappedSwizzle;
MapSwizzleState(contextVk, mImage->getFormat(), mState.getSwizzleState(), &mappedSwizzle);
gl::TextureType arrayType = vk::Get2DTextureType(layerCount, mImage->getSamples());
ANGLE_TRY(mImage->initLayerImageView(contextVk, arrayType, mImage->getAspectFlags(),
mappedSwizzle, &mLayerFetchImageView[layerIndex],
getNativeImageLevel(0), 1,
getNativeImageLayer(layerIndex), 1));
m3DRenderTargets[layerIndex].init(mImage, drawView, &mLayerFetchImageView[layerIndex],
getNativeImageLevel(0), getNativeImageLayer(layerIndex));
}
return angle::Result::Continue;
}
angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk)
{
// Lazy init. Check if already initialized.
......@@ -1333,10 +1377,13 @@ angle::Result TextureVk::getLayerLevelDrawImageView(vk::Context *context,
ASSERT(mImage->valid());
ASSERT(!mImage->getFormat().imageFormat().isBlock);
// For 3D textures, layer count is tracked as depth
uint32_t layerCount = mState.getType() == gl::TextureType::_3D ? mImage->getExtents().depth
: mImage->getLayerCount();
// Lazily allocate the storage for image views
if (mLayerLevelDrawImageViews.empty())
{
mLayerLevelDrawImageViews.resize(mImage->getLayerCount());
mLayerLevelDrawImageViews.resize(layerCount);
}
ASSERT(mLayerLevelDrawImageViews.size() > layer);
......@@ -1355,7 +1402,8 @@ angle::Result TextureVk::getLayerLevelDrawImageView(vk::Context *context,
// Lazily allocate the image view itself.
// Note that these views are specifically made to be used as color attachments, and therefore
// don't have swizzle.
return mImage->initLayerImageView(context, mState.getType(), mImage->getAspectFlags(),
gl::TextureType viewType = vk::Get2DTextureType(layerCount, mImage->getSamples());
return mImage->initLayerImageView(context, viewType, mImage->getAspectFlags(),
gl::SwizzleState(), *imageViewOut, getNativeImageLevel(level),
1, getNativeImageLayer(layer), 1);
}
......@@ -1488,6 +1536,7 @@ void TextureVk::releaseImage(ContextVk *contextVk)
releaseImageViews(contextVk);
mCubeMapRenderTargets.clear();
m3DRenderTargets.clear();
onStagingBufferChange();
}
......
......@@ -282,6 +282,7 @@ class TextureVk : public TextureImpl
const vk::Format &format,
uint32_t levelCount,
uint32_t layerCount);
angle::Result init3DRenderTargets(ContextVk *contextVk);
angle::Result initCubeMapRenderTargets(ContextVk *contextVk);
angle::Result ensureImageInitializedImpl(ContextVk *contextVk,
......@@ -315,6 +316,7 @@ class TextureVk : public TextureImpl
RenderTargetVk mRenderTarget;
std::vector<vk::ImageView> mLayerFetchImageView;
std::vector<RenderTargetVk> m3DRenderTargets;
std::vector<RenderTargetVk> mCubeMapRenderTargets;
// The serial is used for cache indexing.
......
......@@ -535,12 +535,6 @@
// MAX_FRAGMENT_INPUT_COMPONENTS is 0
3676 VULKAN : dEQP-GLES3.functional.state_query.integers.max_fragment_input_components_get* = FAIL
// 3D texture:
3188 VULKAN : dEQP-GLES3.functional.fbo.color.tex3d.* = SKIP
// 2D array (anglebug.com/3189), new formats in ES 3.0 (anglebug.com/3190):
3189 VULKAN : dEQP-GLES3.functional.fbo.color.tex2darray.* = SKIP
// New or broken formats in ES 3.0:
3190 VULKAN : dEQP-GLES3.functional.texture.specification.texstorage2d.format.depth32* = FAIL
3190 VULKAN : dEQP-GLES3.functional.texture.specification.texstorage3d.format.depth32* = FAIL
......
......@@ -564,6 +564,9 @@ TEST_P(DrawBuffersTestES3, 3DTextures)
{
ANGLE_SKIP_TEST_IF(!setupTest());
// Fails on Intel (intel-hd-630) Ubuntu 17.04 with Vulkan: http://anglebug.com/3784
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
GLTexture texture;
glBindTexture(GL_TEXTURE_3D, texture.get());
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), getWindowWidth(),
......@@ -653,4 +656,4 @@ ANGLE_INSTANTIATE_TEST(DrawBuffersTest,
ANGLE_INSTANTIATE_TEST(DrawBuffersWebGL2Test, ES3_D3D11(), ES3_OPENGL(), ES3_VULKAN());
ANGLE_INSTANTIATE_TEST(DrawBuffersTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(DrawBuffersTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES(), ES3_VULKAN());
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