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.
Xinyi He
Sunny Sun
Xiaoxuan Liu
Ancheng Qiao
Broadcom Inc.
Gary Sweet
......
......@@ -512,8 +512,9 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
// Read back the requested region of the source texture
uint8_t *sourceData = nullptr;
ANGLE_TRY(source->copyImageDataToBufferAndGetData(contextVk, sourceLevel, 1, sourceArea,
&sourceData));
gl::Box area(0, 0, 0, sourceArea.width, sourceArea.height, 1);
ANGLE_TRY(
source->copyImageDataToBufferAndGetData(contextVk, sourceLevel, 1, area, &sourceData));
const angle::Format &sourceTextureFormat = sourceVkFormat.actualImageFormat();
const angle::Format &destTextureFormat = destVkFormat.actualImageFormat();
......@@ -986,7 +987,7 @@ angle::Result TextureVk::redefineImage(const gl::Context *context,
angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
size_t sourceLevel,
uint32_t layerCount,
const gl::Rectangle &sourceArea,
const gl::Box &sourceArea,
uint8_t **outDataPtr)
{
ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBufferAndGetData");
......@@ -994,13 +995,11 @@ angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
// Make sure the source is initialized and it's images are flushed.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
gl::Box area(0, 0, 0, sourceArea.width, sourceArea.height, 1);
vk::BufferHelper *copyBuffer = nullptr;
vk::StagingBufferOffsetArray sourceCopyOffsets = {0, 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,
outDataPtr));
......@@ -1071,14 +1070,16 @@ angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
uint32_t imageLayerCount = mImage->getLayerCount();
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(),
imageLayerCount, imageArea, &imageData));
const angle::Format &angleFormat = mImage->getFormat().actualImageFormat();
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
// 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)
ANGLE_TRY(generateMipmapLevelsWithCPU(
contextVk, angleFormat, layer, mState.getEffectiveBaseLevel() + 1,
mState.getMipmapMaxLevel(), baseLevelExtents.width, baseLevelExtents.height,
sourceRowPitch, imageData + bufferOffset));
baseLevelExtents.depth, sourceRowPitch, sourceDepthPitch, imageData + bufferOffset));
}
vk::CommandBuffer *commandBuffer = nullptr;
......@@ -1750,26 +1751,33 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
GLuint maxMipLevel,
const size_t sourceWidth,
const size_t sourceHeight,
const size_t sourceDepth,
const size_t sourceRowPitch,
const size_t sourceDepthPitch,
uint8_t *sourceData)
{
size_t previousLevelWidth = sourceWidth;
size_t previousLevelHeight = sourceHeight;
uint8_t *previousLevelData = sourceData;
size_t previousLevelRowPitch = sourceRowPitch;
size_t previousLevelWidth = sourceWidth;
size_t previousLevelHeight = sourceHeight;
size_t previousLevelDepth = sourceDepth;
uint8_t *previousLevelData = sourceData;
size_t previousLevelRowPitch = sourceRowPitch;
size_t previousLevelDepthPitch = sourceDepthPitch;
for (GLuint currentMipLevel = firstMipLevel; currentMipLevel <= maxMipLevel; currentMipLevel++)
{
// Compute next level width and height.
size_t mipWidth = std::max<size_t>(1, previousLevelWidth >> 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.
uint8_t *destData = nullptr;
size_t destRowPitch = mipWidth * sourceFormat.pixelBytes;
uint8_t *destData = nullptr;
size_t destRowPitch = mipWidth * sourceFormat.pixelBytes;
size_t destDepthPitch = destRowPitch * mipHeight;
size_t mipAllocationSize = destRowPitch * mipHeight;
gl::Extents mipLevelExtents(static_cast<int>(mipWidth), static_cast<int>(mipHeight), 1);
size_t mipAllocationSize = destDepthPitch * mipDepth;
gl::Extents mipLevelExtents(static_cast<int>(mipWidth), static_cast<int>(mipHeight),
static_cast<int>(mipDepth));
ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
contextVk, mipAllocationSize,
......@@ -1778,15 +1786,17 @@ angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
onStagingBufferChange();
// Generate the mipmap into that new buffer
sourceFormat.mipGenerationFunction(previousLevelWidth, previousLevelHeight, 1,
previousLevelData, previousLevelRowPitch, 0, destData,
destRowPitch, 0);
sourceFormat.mipGenerationFunction(
previousLevelWidth, previousLevelHeight, previousLevelDepth, previousLevelData,
previousLevelRowPitch, previousLevelDepthPitch, destData, destRowPitch, destDepthPitch);
// Swap for the next iteration
previousLevelWidth = mipWidth;
previousLevelHeight = mipHeight;
previousLevelData = destData;
previousLevelRowPitch = destRowPitch;
previousLevelWidth = mipWidth;
previousLevelHeight = mipHeight;
previousLevelDepth = mipDepth;
previousLevelData = destData;
previousLevelRowPitch = destRowPitch;
previousLevelDepthPitch = destDepthPitch;
}
return angle::Result::Continue;
......
......@@ -270,7 +270,7 @@ class TextureVk : public TextureImpl
angle::Result copyImageDataToBufferAndGetData(ContextVk *contextVk,
size_t sourceLevel,
uint32_t layerCount,
const gl::Rectangle &sourceArea,
const gl::Box &sourceArea,
uint8_t **outDataPtr);
angle::Result copyBufferDataToImage(ContextVk *contextVk,
......@@ -288,9 +288,11 @@ class TextureVk : public TextureImpl
GLuint layer,
GLuint firstMipLevel,
GLuint maxMipLevel,
size_t sourceWidth,
size_t sourceHeight,
size_t sourceRowPitch,
const size_t sourceWidth,
const size_t sourceHeight,
const size_t sourceDepth,
const size_t sourceRowPitch,
const size_t sourceDepthPitch,
uint8_t *sourceData);
angle::Result copySubImageImpl(const gl::Context *context,
......
......@@ -2313,6 +2313,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
// is a faster way we can generate the mips.
int32_t mipWidth = mExtents.width;
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
// usual one.
......@@ -2330,6 +2331,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
{
int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 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.oldLayout = getCurrentLayout();
......@@ -2342,13 +2344,13 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
barrier);
VkImageBlit blit = {};
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.mipLevel = mipLevel - 1;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = mLayerCount;
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.mipLevel = mipLevel;
blit.dstSubresource.baseArrayLayer = 0;
......@@ -2356,6 +2358,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
mipWidth = nextMipWidth;
mipHeight = nextMipHeight;
mipDepth = nextMipDepth;
bool formatSupportsLinearFiltering = contextVk->getRenderer()->hasImageFormatFeatureBits(
getFormat().vkImageFormat, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
......
......@@ -954,9 +954,9 @@ TEST_P(MipmapTestES3, MipmapForDeepTextureArray)
// Then tests if the mipmaps are rendered correctly for all two layers.
TEST_P(MipmapTestES3, MipmapsForTexture3D)
{
// TODO(cnorthrop): Enabled the group to cover texture base level, but this test
// needs some triage: http://anglebug.com/3950
ANGLE_SKIP_TEST_IF(IsVulkan());
// Currently block on swiftshader Blit3D support, tracked on
// https://issuetracker.google.com/issues/150155499
ANGLE_SKIP_TEST_IF(isVulkanSwiftshaderRenderer());
int px = getWindowWidth() / 2;
int py = getWindowHeight() / 2;
......@@ -1002,17 +1002,37 @@ TEST_P(MipmapTestES3, MipmapsForTexture3D)
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
// Mipmap level 1
// The second mipmap should only have one slice.
// Regenerate mipmap of same color texture
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.);
drawQuad(m3DProgram, "position", 0.5f);
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);
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
......
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