Commit 90019cea by Ancheng Qiao Committed by Commit Bot

Vulkan: Add depth to mipmap generation

In generateMipmaps, remove hard coded depth of 1, shift depth like every other dimension. Remove MipmapsForTexture3D test pixel value check, in es spec3.2 8.14.4 "No particular filter algorithm is required, though a box filter is recommended." It's implementation-dependent. In current angle implementation, will choose VK_FILTER_LINEAR/VK_FILTER_NEAREST according to vkdeice support. Bug: angleproject:3983 Test: MipmapTestES3.MipmapsForTexture3D/ES3_Vulkan Test: dEQP-GLES3.functional.samplers.single_tex_3d.diff_max_lod Test: dEQP-GLES3.functional.samplers.single_tex_3d.diff_min_lod Test: dEQP-GLES3.functional.samplers.multi_tex_3d.diff_max_lod Test: dEQP-GLES3.functional.samplers.multi_tex_3d.diff_min_lod Change-Id: I5e73f8c743053aeb521b5e0b3e372bbe77e57ad2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2076740Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent f8b28678
...@@ -170,6 +170,7 @@ Arm Ltd. ...@@ -170,6 +170,7 @@ Arm Ltd.
Xinyi He Xinyi He
Sunny Sun Sunny Sun
Xiaoxuan Liu Xiaoxuan Liu
Ancheng Qiao
Broadcom Inc. Broadcom Inc.
Gary Sweet Gary Sweet
......
...@@ -512,8 +512,9 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk, ...@@ -512,8 +512,9 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
// Read back the requested region of the source texture // Read back the requested region of the source texture
uint8_t *sourceData = nullptr; uint8_t *sourceData = nullptr;
ANGLE_TRY(source->copyImageDataToBufferAndGetData(contextVk, sourceLevel, 1, sourceArea, gl::Box area(0, 0, 0, sourceArea.width, sourceArea.height, 1);
&sourceData)); ANGLE_TRY(
source->copyImageDataToBufferAndGetData(contextVk, sourceLevel, 1, area, &sourceData));
const angle::Format &sourceTextureFormat = sourceVkFormat.actualImageFormat(); const angle::Format &sourceTextureFormat = sourceVkFormat.actualImageFormat();
const angle::Format &destTextureFormat = destVkFormat.actualImageFormat(); const angle::Format &destTextureFormat = destVkFormat.actualImageFormat();
...@@ -986,7 +987,7 @@ angle::Result TextureVk::redefineImage(const gl::Context *context, ...@@ -986,7 +987,7 @@ angle::Result TextureVk::redefineImage(const gl::Context *context,
angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk, angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
size_t sourceLevel, size_t sourceLevel,
uint32_t layerCount, uint32_t layerCount,
const gl::Rectangle &sourceArea, const gl::Box &sourceArea,
uint8_t **outDataPtr) uint8_t **outDataPtr)
{ {
ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBufferAndGetData"); ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBufferAndGetData");
...@@ -994,13 +995,11 @@ angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk, ...@@ -994,13 +995,11 @@ angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
// Make sure the source is initialized and it's images are flushed. // Make sure the source is initialized and it's images are flushed.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels)); ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
gl::Box area(0, 0, 0, sourceArea.width, sourceArea.height, 1);
vk::BufferHelper *copyBuffer = nullptr; vk::BufferHelper *copyBuffer = nullptr;
vk::StagingBufferOffsetArray sourceCopyOffsets = {0, 0}; vk::StagingBufferOffsetArray sourceCopyOffsets = {0, 0};
size_t bufferSize = 0; size_t bufferSize = 0;
ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceLevel, layerCount, 0, area, ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceLevel, layerCount, 0, sourceArea,
&copyBuffer, &bufferSize, &sourceCopyOffsets, &copyBuffer, &bufferSize, &sourceCopyOffsets,
outDataPtr)); outDataPtr));
...@@ -1071,14 +1070,16 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context) ...@@ -1071,14 +1070,16 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
uint32_t imageLayerCount = mImage->getLayerCount(); uint32_t imageLayerCount = mImage->getLayerCount();
uint8_t *imageData = nullptr; uint8_t *imageData = nullptr;
gl::Rectangle imageArea(0, 0, baseLevelExtents.width, baseLevelExtents.height); gl::Box imageArea(0, 0, 0, baseLevelExtents.width, baseLevelExtents.height,
baseLevelExtents.depth);
ANGLE_TRY(copyImageDataToBufferAndGetData(contextVk, mState.getEffectiveBaseLevel(), ANGLE_TRY(copyImageDataToBufferAndGetData(contextVk, mState.getEffectiveBaseLevel(),
imageLayerCount, imageArea, &imageData)); imageLayerCount, imageArea, &imageData));
const angle::Format &angleFormat = mImage->getFormat().actualImageFormat(); const angle::Format &angleFormat = mImage->getFormat().actualImageFormat();
GLuint sourceRowPitch = baseLevelExtents.width * angleFormat.pixelBytes; GLuint sourceRowPitch = baseLevelExtents.width * angleFormat.pixelBytes;
size_t baseLevelAllocationSize = sourceRowPitch * baseLevelExtents.height; GLuint sourceDepthPitch = sourceRowPitch * baseLevelExtents.height;
size_t baseLevelAllocationSize = sourceDepthPitch * baseLevelExtents.depth;
// We now have the base level available to be manipulated in the imageData pointer. Generate all // We now have the base level available to be manipulated in the imageData pointer. Generate all
// the missing mipmaps with the slow path. For each layer, use the copied data to generate all // the missing mipmaps with the slow path. For each layer, use the copied data to generate all
...@@ -1090,7 +1091,7 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context) ...@@ -1090,7 +1091,7 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
ANGLE_TRY(generateMipmapLevelsWithCPU( ANGLE_TRY(generateMipmapLevelsWithCPU(
contextVk, angleFormat, layer, mState.getEffectiveBaseLevel() + 1, contextVk, angleFormat, layer, mState.getEffectiveBaseLevel() + 1,
mState.getMipmapMaxLevel(), baseLevelExtents.width, baseLevelExtents.height, mState.getMipmapMaxLevel(), baseLevelExtents.width, baseLevelExtents.height,
sourceRowPitch, imageData + bufferOffset)); baseLevelExtents.depth, sourceRowPitch, sourceDepthPitch, imageData + bufferOffset));
} }
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
...@@ -1750,26 +1751,33 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk, ...@@ -1750,26 +1751,33 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
GLuint maxMipLevel, GLuint maxMipLevel,
const size_t sourceWidth, const size_t sourceWidth,
const size_t sourceHeight, const size_t sourceHeight,
const size_t sourceDepth,
const size_t sourceRowPitch, const size_t sourceRowPitch,
const size_t sourceDepthPitch,
uint8_t *sourceData) uint8_t *sourceData)
{ {
size_t previousLevelWidth = sourceWidth; size_t previousLevelWidth = sourceWidth;
size_t previousLevelHeight = sourceHeight; size_t previousLevelHeight = sourceHeight;
uint8_t *previousLevelData = sourceData; size_t previousLevelDepth = sourceDepth;
size_t previousLevelRowPitch = sourceRowPitch; uint8_t *previousLevelData = sourceData;
size_t previousLevelRowPitch = sourceRowPitch;
size_t previousLevelDepthPitch = sourceDepthPitch;
for (GLuint currentMipLevel = firstMipLevel; currentMipLevel <= maxMipLevel; currentMipLevel++) for (GLuint currentMipLevel = firstMipLevel; currentMipLevel <= maxMipLevel; currentMipLevel++)
{ {
// Compute next level width and height. // Compute next level width and height.
size_t mipWidth = std::max<size_t>(1, previousLevelWidth >> 1); size_t mipWidth = std::max<size_t>(1, previousLevelWidth >> 1);
size_t mipHeight = std::max<size_t>(1, previousLevelHeight >> 1); size_t mipHeight = std::max<size_t>(1, previousLevelHeight >> 1);
size_t mipDepth = std::max<size_t>(1, previousLevelDepth >> 1);
// With the width and height of the next mip, we can allocate the next buffer we need. // With the width and height of the next mip, we can allocate the next buffer we need.
uint8_t *destData = nullptr; uint8_t *destData = nullptr;
size_t destRowPitch = mipWidth * sourceFormat.pixelBytes; size_t destRowPitch = mipWidth * sourceFormat.pixelBytes;
size_t destDepthPitch = destRowPitch * mipHeight;
size_t mipAllocationSize = destRowPitch * mipHeight; size_t mipAllocationSize = destDepthPitch * mipDepth;
gl::Extents mipLevelExtents(static_cast<int>(mipWidth), static_cast<int>(mipHeight), 1); gl::Extents mipLevelExtents(static_cast<int>(mipWidth), static_cast<int>(mipHeight),
static_cast<int>(mipDepth));
ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData( ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
contextVk, mipAllocationSize, contextVk, mipAllocationSize,
...@@ -1778,15 +1786,17 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk, ...@@ -1778,15 +1786,17 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
onStagingBufferChange(); onStagingBufferChange();
// Generate the mipmap into that new buffer // Generate the mipmap into that new buffer
sourceFormat.mipGenerationFunction(previousLevelWidth, previousLevelHeight, 1, sourceFormat.mipGenerationFunction(
previousLevelData, previousLevelRowPitch, 0, destData, previousLevelWidth, previousLevelHeight, previousLevelDepth, previousLevelData,
destRowPitch, 0); previousLevelRowPitch, previousLevelDepthPitch, destData, destRowPitch, destDepthPitch);
// Swap for the next iteration // Swap for the next iteration
previousLevelWidth = mipWidth; previousLevelWidth = mipWidth;
previousLevelHeight = mipHeight; previousLevelHeight = mipHeight;
previousLevelData = destData; previousLevelDepth = mipDepth;
previousLevelRowPitch = destRowPitch; previousLevelData = destData;
previousLevelRowPitch = destRowPitch;
previousLevelDepthPitch = destDepthPitch;
} }
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -270,7 +270,7 @@ class TextureVk : public TextureImpl ...@@ -270,7 +270,7 @@ class TextureVk : public TextureImpl
angle::Result copyImageDataToBufferAndGetData(ContextVk *contextVk, angle::Result copyImageDataToBufferAndGetData(ContextVk *contextVk,
size_t sourceLevel, size_t sourceLevel,
uint32_t layerCount, uint32_t layerCount,
const gl::Rectangle &sourceArea, const gl::Box &sourceArea,
uint8_t **outDataPtr); uint8_t **outDataPtr);
angle::Result copyBufferDataToImage(ContextVk *contextVk, angle::Result copyBufferDataToImage(ContextVk *contextVk,
...@@ -288,9 +288,11 @@ class TextureVk : public TextureImpl ...@@ -288,9 +288,11 @@ class TextureVk : public TextureImpl
GLuint layer, GLuint layer,
GLuint firstMipLevel, GLuint firstMipLevel,
GLuint maxMipLevel, GLuint maxMipLevel,
size_t sourceWidth, const size_t sourceWidth,
size_t sourceHeight, const size_t sourceHeight,
size_t sourceRowPitch, const size_t sourceDepth,
const size_t sourceRowPitch,
const size_t sourceDepthPitch,
uint8_t *sourceData); uint8_t *sourceData);
angle::Result copySubImageImpl(const gl::Context *context, angle::Result copySubImageImpl(const gl::Context *context,
......
...@@ -2313,6 +2313,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -2313,6 +2313,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
// is a faster way we can generate the mips. // is a faster way we can generate the mips.
int32_t mipWidth = mExtents.width; int32_t mipWidth = mExtents.width;
int32_t mipHeight = mExtents.height; int32_t mipHeight = mExtents.height;
int32_t mipDepth = mExtents.depth;
// Manually manage the image memory barrier because it uses a lot more parameters than our // Manually manage the image memory barrier because it uses a lot more parameters than our
// usual one. // usual one.
...@@ -2330,6 +2331,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -2330,6 +2331,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
{ {
int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1); int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1);
int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1); int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
int32_t nextMipDepth = std::max<int32_t>(1, mipDepth >> 1);
barrier.subresourceRange.baseMipLevel = mipLevel - 1; barrier.subresourceRange.baseMipLevel = mipLevel - 1;
barrier.oldLayout = getCurrentLayout(); barrier.oldLayout = getCurrentLayout();
...@@ -2342,13 +2344,13 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -2342,13 +2344,13 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
barrier); barrier);
VkImageBlit blit = {}; VkImageBlit blit = {};
blit.srcOffsets[0] = {0, 0, 0}; blit.srcOffsets[0] = {0, 0, 0};
blit.srcOffsets[1] = {mipWidth, mipHeight, 1}; blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth};
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = mipLevel - 1; blit.srcSubresource.mipLevel = mipLevel - 1;
blit.srcSubresource.baseArrayLayer = 0; blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = mLayerCount; blit.srcSubresource.layerCount = mLayerCount;
blit.dstOffsets[0] = {0, 0, 0}; blit.dstOffsets[0] = {0, 0, 0};
blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, 1}; blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, nextMipDepth};
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = mipLevel; blit.dstSubresource.mipLevel = mipLevel;
blit.dstSubresource.baseArrayLayer = 0; blit.dstSubresource.baseArrayLayer = 0;
...@@ -2356,6 +2358,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -2356,6 +2358,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
mipWidth = nextMipWidth; mipWidth = nextMipWidth;
mipHeight = nextMipHeight; mipHeight = nextMipHeight;
mipDepth = nextMipDepth;
bool formatSupportsLinearFiltering = contextVk->getRenderer()->hasImageFormatFeatureBits( bool formatSupportsLinearFiltering = contextVk->getRenderer()->hasImageFormatFeatureBits(
getFormat().vkImageFormat, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT); getFormat().vkImageFormat, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
......
...@@ -954,9 +954,9 @@ TEST_P(MipmapTestES3, MipmapForDeepTextureArray) ...@@ -954,9 +954,9 @@ TEST_P(MipmapTestES3, MipmapForDeepTextureArray)
// Then tests if the mipmaps are rendered correctly for all two layers. // Then tests if the mipmaps are rendered correctly for all two layers.
TEST_P(MipmapTestES3, MipmapsForTexture3D) TEST_P(MipmapTestES3, MipmapsForTexture3D)
{ {
// TODO(cnorthrop): Enabled the group to cover texture base level, but this test // Currently block on swiftshader Blit3D support, tracked on
// needs some triage: http://anglebug.com/3950 // https://issuetracker.google.com/issues/150155499
ANGLE_SKIP_TEST_IF(IsVulkan()); ANGLE_SKIP_TEST_IF(isVulkanSwiftshaderRenderer());
int px = getWindowWidth() / 2; int px = getWindowWidth() / 2;
int py = getWindowHeight() / 2; int py = getWindowHeight() / 2;
...@@ -1002,17 +1002,37 @@ TEST_P(MipmapTestES3, MipmapsForTexture3D) ...@@ -1002,17 +1002,37 @@ TEST_P(MipmapTestES3, MipmapsForTexture3D)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green); EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
// Mipmap level 1 // Regenerate mipmap of same color texture
// The second mipmap should only have one slice. glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
pixelsRed.data());
glGenerateMipmap(GL_TEXTURE_3D);
EXPECT_GL_NO_ERROR();
// Mipmap level 1 8*8*1
glUniform1f(mTexture3DLODUniformLocation, 1.); glUniform1f(mTexture3DLODUniformLocation, 1.);
drawQuad(m3DProgram, "position", 0.5f); drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0); EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
glUniform1f(mTexture3DSliceUniformLocation, 0.75f); // Mipmap level 2 4*4*1
glUniform1f(mTexture3DLODUniformLocation, 2.);
drawQuad(m3DProgram, "position", 0.5f); drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0); EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
// Mipmap level 3 2*2*1
glUniform1f(mTexture3DLODUniformLocation, 3.);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
// Mipmap level 4 1*1*1
glUniform1f(mTexture3DLODUniformLocation, 4.);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
} }
// Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays // Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
......
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