Vulkan: Support binding texture levels as a rendertarget This CL refactors how TextureVk handles rendertargets. It removes the single rendertarget that previously supported 2D, and expands the layer/level list of rendertargets to handle all cases. Bug: angleproject:3184 Bug: angleproject:3996 Test: Texture2DTestES3.FramebufferTextureChangingBaselevel/ES3_Vulkan Test: FramebufferRenderMipmapTest.RenderToMipmap/ES2_Vulkan Test: FramebufferRenderMipmapTest.RenderToMipmap/ES3_Vulkan Test: ComputeShaderTest.ImageStoreMipmapSlice/ES3_1_Vulkan Change-Id: I466d0389cc6744994f88c40cc388fca694b53a99 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1854895 Reviewed-by: Ian Elliott <ianelliott@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Cody Northrop <cnorthrop@google.com>
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp index e910be1..025a718 100644 --- a/src/libANGLE/renderer/vulkan/TextureVk.cpp +++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -79,6 +79,11 @@ { switch (index.getType()) { + case gl::TextureType::_2D: + *layerIndex = 0; + *layerCount = 1; + return; + case gl::TextureType::CubeMap: *layerIndex = index.cubeMapFaceIndex(); *layerCount = gl::kCubeFaceCount; @@ -894,10 +899,12 @@ mImage->initStagingBuffer(contextVk->getRenderer(), format, vk::kStagingBufferFlags, mStagingBufferInitialSize); - mRenderTarget.init(mImage, &mDrawImageView, getNativeImageLevel(0), getNativeImageLayer(0)); - - // Force re-creation of layered render targets next time they are needed - mLayerRenderTargets.clear(); + // Force re-creation of render targets next time they are needed + for (vk::RenderTargetVector &renderTargetLevels : mRenderTargets) + { + renderTargetLevels.clear(); + } + mRenderTargets.clear(); mSerial = contextVk->generateTextureSerial(); } @@ -1251,31 +1258,18 @@ GLsizei samples, FramebufferAttachmentRenderTarget **rtOut) { - // Non-zero mip level attachments are an ES 3.0 feature. - ASSERT(imageIndex.getLevelIndex() == 0); + ASSERT(imageIndex.getLevelIndex() >= 0); ContextVk *contextVk = vk::GetImpl(context); ANGLE_TRY(ensureImageInitialized(contextVk)); GLuint layerIndex = 0, layerCount = 0; + GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerCount, &layerIndex); - switch (imageIndex.getType()) - { - case gl::TextureType::_2D: - *rtOut = &mRenderTarget; - break; - case gl::TextureType::CubeMap: - case gl::TextureType::_2DArray: - case gl::TextureType::_3D: - // Special handling required for different types, grab the count and index - GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerCount, &layerIndex); + ANGLE_TRY(initRenderTargets(contextVk, layerCount, imageIndex.getLevelIndex())); - ANGLE_TRY(initLayerRenderTargets(contextVk, layerCount)); - *rtOut = &mLayerRenderTargets[layerIndex]; - break; - default: - UNREACHABLE(); - } + ASSERT(imageIndex.getLevelIndex() < static_cast<int32_t>(mRenderTargets.size())); + *rtOut = &mRenderTargets[imageIndex.getLevelIndex()][layerIndex]; return angle::Result::Continue; } @@ -1317,20 +1311,27 @@ commandBuffer); } -angle::Result TextureVk::initLayerRenderTargets(ContextVk *contextVk, GLuint layerCount) +angle::Result TextureVk::initRenderTargets(ContextVk *contextVk, + GLuint layerCount, + GLuint levelIndex) { + if (mRenderTargets.size() <= levelIndex) + { + mRenderTargets.resize(levelIndex + 1); + } + // Lazy init. Check if already initialized. - if (!mLayerRenderTargets.empty()) + if (!mRenderTargets[levelIndex].empty()) return angle::Result::Continue; - mLayerRenderTargets.resize(layerCount); + mRenderTargets[levelIndex].resize(layerCount); for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) { const vk::ImageView *drawView; - ANGLE_TRY(getLayerLevelDrawImageView(contextVk, layerIndex, 0, &drawView)); - mLayerRenderTargets[layerIndex].init(mImage, drawView, getNativeImageLevel(0), - getNativeImageLayer(layerIndex)); + ANGLE_TRY(getLayerLevelDrawImageView(contextVk, layerIndex, levelIndex, &drawView)); + mRenderTargets[levelIndex][layerIndex].init( + mImage, drawView, getNativeImageLevel(levelIndex), getNativeImageLayer(layerIndex)); } return angle::Result::Continue; } @@ -1692,13 +1693,6 @@ layerCount)); } - if (!format.imageFormat().isBlock) - { - ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), aspectFlags, - gl::SwizzleState(), &mDrawImageView, baseLevel, 1, - baseLayer, layerCount)); - } - return angle::Result::Continue; } @@ -1718,7 +1712,13 @@ releaseImageViews(contextVk); - mLayerRenderTargets.clear(); + for (vk::RenderTargetVector &renderTargetLevels : mRenderTargets) + { + // Clear the layers tracked for each level + renderTargetLevels.clear(); + } + // Then clear the levels + mRenderTargets.clear(); onStagingBufferChange(); } @@ -1728,7 +1728,6 @@ contextVk->addGarbage(&mReadImageView); contextVk->addGarbage(&mFetchImageView); contextVk->addGarbage(&mStencilReadImageView); - contextVk->addGarbage(&mDrawImageView); for (vk::ImageViewVector &layerViews : mLayerLevelDrawImageViews) {
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.h b/src/libANGLE/renderer/vulkan/TextureVk.h index dc48211..6802996 100644 --- a/src/libANGLE/renderer/vulkan/TextureVk.h +++ b/src/libANGLE/renderer/vulkan/TextureVk.h
@@ -299,7 +299,7 @@ const bool sized, uint32_t levelCount, uint32_t layerCount); - angle::Result initLayerRenderTargets(ContextVk *contextVk, GLuint layerCount); + angle::Result initRenderTargets(ContextVk *contextVk, GLuint layerCount, GLuint levelIndex); vk::ImageView *getLevelImageViewImpl(vk::ImageViewVector *imageViews, size_t level); vk::ImageView *getLayerLevelImageViewImpl(vk::LayerLevelImageViewVector *imageViews, size_t layer, @@ -334,15 +334,16 @@ vk::ImageView mStencilReadImageView; // Draw views. - vk::ImageView mDrawImageView; vk::LayerLevelImageViewVector mLayerLevelDrawImageViews; // Storage image views. vk::ImageViewVector mLevelStorageImageViews; vk::Sampler mSampler; - RenderTargetVk mRenderTarget; - std::vector<RenderTargetVk> mLayerRenderTargets; + + // Render targets stored as vector of vectors + // Level is first dimension, layer is second + std::vector<vk::RenderTargetVector> mRenderTargets; // The serial is used for cache indexing. Serial mSerial;
diff --git a/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp b/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp index 2edcfec..79269fc 100644 --- a/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp +++ b/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp
@@ -124,6 +124,8 @@ // Vulkan natively supports 32-bit indices, entry in kIndexTypeMap mNativeExtensions.elementIndexUint = true; + mNativeExtensions.fboRenderMipmap = true; + // https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s02.html mNativeCaps.maxElementIndex = std::numeric_limits<GLuint>::max() - 1; mNativeCaps.max3DTextureSize = limitsVk.maxImageDimension3D;
diff --git a/src/libANGLE/renderer/vulkan/vk_utils.h b/src/libANGLE/renderer/vulkan/vk_utils.h index b3e91f0..11e47d9 100644 --- a/src/libANGLE/renderer/vulkan/vk_utils.h +++ b/src/libANGLE/renderer/vulkan/vk_utils.h
@@ -597,6 +597,8 @@ using ImageViewVector = std::vector<ImageView>; // A vector of vector of image views. Primary index is layer, secondary index is level. using LayerLevelImageViewVector = std::vector<ImageViewVector>; +// A vector of rendertargets +using RenderTargetVector = std::vector<RenderTargetVk>; } // namespace vk
diff --git a/src/tests/gl_tests/ComputeShaderTest.cpp b/src/tests/gl_tests/ComputeShaderTest.cpp index 87b8a8a..4716c80 100644 --- a/src/tests/gl_tests/ComputeShaderTest.cpp +++ b/src/tests/gl_tests/ComputeShaderTest.cpp
@@ -3010,9 +3010,6 @@ // TODO(xinghua.cao@intel.com): http://anglebug.com/3101 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL()); - // Non-zero-level render target attachments are not yet supported. http://anglebug.com/3184 - ANGLE_SKIP_TEST_IF(IsVulkan()); - GLTexture texture[2]; GLFramebuffer framebuffer; constexpr char kCS[] = R"(#version 310 es
diff --git a/src/tests/gl_tests/FramebufferRenderMipmapTest.cpp b/src/tests/gl_tests/FramebufferRenderMipmapTest.cpp index b6aa154..930864b 100644 --- a/src/tests/gl_tests/FramebufferRenderMipmapTest.cpp +++ b/src/tests/gl_tests/FramebufferRenderMipmapTest.cpp
@@ -163,4 +163,5 @@ ES3_OPENGL(), ES2_OPENGLES(), ES3_OPENGLES(), - ES2_VULKAN()); + ES2_VULKAN(), + ES3_VULKAN());
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp index e7485fb..2e5ca72 100644 --- a/src/tests/gl_tests/TextureTest.cpp +++ b/src/tests/gl_tests/TextureTest.cpp
@@ -2017,8 +2017,8 @@ // TODO(geofflang): Investigate on D3D11. http://anglebug.com/2291 ANGLE_SKIP_TEST_IF(IsD3D11()); - // TODO(cnorthrop): Framebuffer level support. http://anglebug.com/3184 - ANGLE_SKIP_TEST_IF(IsVulkan()); + // TODO(cnorthrop): Failing on Vulkan/Windows/AMD. http://anglebug.com/3996 + ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && IsAMD()); setUpProgram();