Commit 3589d9a0 by Shahbaz Youssefi Committed by Commit Bot

Add a test for generateMipmap after modify

To make sure TextureVk::syncState is called before generateMipmap. Bug: angleproject:4551 Change-Id: Ibce0738b72fc81270e07617f04ffee57f1c8ed20 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2248209 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 1c484343
...@@ -1344,55 +1344,36 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context) ...@@ -1344,55 +1344,36 @@ angle::Result TextureVk::generateMipmap(const gl::Context *context)
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc(); const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
// Some data is pending, or the image has not been defined at all yet // The image should already be allocated by a prior syncState.
if (!mImage->valid()) ASSERT(mImage->valid());
{
// Let's initialize the image so we can generate the next levels. // If base level has changed, the front-end should have called syncState already.
if (mImage->hasStagedUpdates()) ASSERT(mImage->getBaseLevel() == mState.getEffectiveBaseLevel());
{
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain));
ASSERT(mImage->valid());
needRedefineImage = false;
}
else
{
// There is nothing to generate if there is nothing uploaded so far.
return angle::Result::Continue;
}
}
// Check whether the image is already full mipmap // Check whether the image is already full mipmap
if (mImage->getLevelCount() == getMipLevelCount(ImageMipLevels::FullMipChain) && if (mImage->getLevelCount() == getMipLevelCount(ImageMipLevels::FullMipChain))
mImage->getBaseLevel() == mState.getEffectiveBaseLevel())
{ {
needRedefineImage = false; needRedefineImage = false;
} }
// Only staged update here can be the robust resource init.
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
if (needRedefineImage) if (needRedefineImage)
{ {
// Flush update if needed.
if (mImage->hasStagedUpdates())
{
vk::CommandBuffer *commandBuffer = nullptr;
mImage->retain(&contextVk->getResourceUseList());
ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
ANGLE_TRY(mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0),
mImage->getLevelCount(), getNativeImageLayer(0),
mImage->getLayerCount(), {}, commandBuffer));
}
// Redefine the images with mipmaps. // Redefine the images with mipmaps.
// Copy image to the staging buffer and stage an update to the new one. // Copy image to the staging buffer and stage an update to the new one.
ANGLE_TRY(copyAndStageImageSubresource(contextVk, baseLevelDesc, false, ANGLE_TRY(copyAndStageImageSubresource(contextVk, baseLevelDesc, false,
getNativeImageLayer(0), 0, mImage->getBaseLevel())); getNativeImageLayer(0), 0, mImage->getBaseLevel()));
// Release the origin image and recreate it with new mipmap counts. // Release the original image and recreate it with new mipmap counts.
releaseImage(contextVk); releaseImage(contextVk);
mImage->retain(&contextVk->getResourceUseList()); mImage->retain(&contextVk->getResourceUseList());
ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain)); ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain));
} }
// Check if the image supports blit. If it does, we can do the mipmap generation on the gpu // Check if the image supports blit. If it does, we can do the mipmap generation on the gpu
// only. // only.
if (renderer->hasImageFormatFeatureBits(mImage->getFormat().vkImageFormat, kBlitFeatureFlags)) if (renderer->hasImageFormatFeatureBits(mImage->getFormat().vkImageFormat, kBlitFeatureFlags))
......
...@@ -2714,7 +2714,7 @@ angle::Result ImageHelper::initMemory(Context *context, ...@@ -2714,7 +2714,7 @@ angle::Result ImageHelper::initMemory(Context *context,
{ {
// TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162 // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
VkDeviceSize size; VkDeviceSize size;
ANGLE_TRY(AllocateImageMemory(context, flags, nullptr, &mImage, &mDeviceMemory, &size)); ANGLE_TRY(AllocateImageMemory(context, flags, &flags, nullptr, &mImage, &mDeviceMemory, &size));
mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex(); mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex();
RendererVk *renderer = context->getRenderer(); RendererVk *renderer = context->getRenderer();
......
...@@ -516,13 +516,13 @@ angle::Result AllocateBufferMemory(vk::Context *context, ...@@ -516,13 +516,13 @@ angle::Result AllocateBufferMemory(vk::Context *context,
angle::Result AllocateImageMemory(vk::Context *context, angle::Result AllocateImageMemory(vk::Context *context,
VkMemoryPropertyFlags memoryPropertyFlags, VkMemoryPropertyFlags memoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const void *extraAllocationInfo, const void *extraAllocationInfo,
Image *image, Image *image,
DeviceMemory *deviceMemoryOut, DeviceMemory *deviceMemoryOut,
VkDeviceSize *sizeOut) VkDeviceSize *sizeOut)
{ {
VkMemoryPropertyFlags memoryPropertyFlagsOut = 0; return AllocateBufferOrImageMemory(context, memoryPropertyFlags, memoryPropertyFlagsOut,
return AllocateBufferOrImageMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut,
extraAllocationInfo, image, deviceMemoryOut, sizeOut); extraAllocationInfo, image, deviceMemoryOut, sizeOut);
} }
......
...@@ -346,6 +346,7 @@ angle::Result AllocateBufferMemory(Context *context, ...@@ -346,6 +346,7 @@ angle::Result AllocateBufferMemory(Context *context,
angle::Result AllocateImageMemory(Context *context, angle::Result AllocateImageMemory(Context *context,
VkMemoryPropertyFlags memoryPropertyFlags, VkMemoryPropertyFlags memoryPropertyFlags,
VkMemoryPropertyFlags *memoryPropertyFlagsOut,
const void *extraAllocationInfo, const void *extraAllocationInfo,
Image *image, Image *image,
DeviceMemory *deviceMemoryOut, DeviceMemory *deviceMemoryOut,
......
...@@ -576,6 +576,44 @@ TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender) ...@@ -576,6 +576,44 @@ TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender)
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
} }
// Test that generating mipmaps, then modifying the base level and generating mipmaps again works.
TEST_P(MipmapTest, GenerateMipmapAfterModifyingBaseLevel)
{
uint32_t width = getWindowWidth();
uint32_t height = getWindowHeight();
const std::vector<GLColor> kInitData(width * height, GLColor::blue);
// Pass in initial data so the texture is blue.
glBindTexture(GL_TEXTURE_2D, mTexture2D);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
kInitData.data());
// Then generate the mips.
glGenerateMipmap(GL_TEXTURE_2D);
ASSERT_GL_NO_ERROR();
// Enable mipmaps.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
// Draw and make sure the second mip is blue. This is to make sure the texture image is
// allocated.
clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, kInitData[0]);
// Modify mip 0 without redefining it.
const std::vector<GLColor> kModifyData(width * height, GLColor::green);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
kModifyData.data());
// Generate the mips again, which should update all levels to the new (green) color.
glGenerateMipmap(GL_TEXTURE_2D);
ASSERT_GL_NO_ERROR();
clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, kModifyData[0]);
}
// This test ensures that mips are correctly generated from a rendered image. // This test ensures that mips are correctly generated from a rendered image.
// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level // In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level
// texture, rather than the mipped one. The test ensures that the zero-level texture is correctly // texture, rather than the mipped one. The test ensures that the zero-level texture is correctly
......
...@@ -1185,6 +1185,59 @@ TEST_P(RobustResourceInitTestES3, GenerateMipmap) ...@@ -1185,6 +1185,59 @@ TEST_P(RobustResourceInitTestES3, GenerateMipmap)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
} }
// Tests creating mipmaps with robust resource init multiple times.
TEST_P(RobustResourceInitTestES3, GenerateMipmapAfterRedefine)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
constexpr GLint kTextureSize = 16;
const std::vector<GLColor> kInitData(kTextureSize * kTextureSize, GLColor::blue);
// Initialize a 16x16 RGBA8 texture with blue.
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA,
GL_UNSIGNED_BYTE, kInitData.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
std::string shader = GetSimpleTextureFragmentShader("");
ANGLE_GL_PROGRAM(program, kSimpleTextureVertexShader, shader.c_str());
// Generate mipmaps.
glGenerateMipmap(GL_TEXTURE_2D);
ASSERT_GL_NO_ERROR();
// Validate a small mip.
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
// Set viewport to resize the texture and draw.
glViewport(0, 0, 2, 2);
drawQuad(program, "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
// Redefine mip 0 with no data.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTextureSize, kTextureSize, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
// Generate mipmaps again. Mip 0 must be cleared before the mipmaps are regenerated.
glGenerateMipmap(GL_TEXTURE_2D);
EXPECT_GL_NO_ERROR();
// Validate a small mip.
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
glViewport(0, 0, 2, 2);
drawQuad(program, "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
}
// Tests creating mipmaps for cube maps with robust resource init. // Tests creating mipmaps for cube maps with robust resource init.
TEST_P(RobustResourceInitTestES3, GenerateMipmapCubeMap) TEST_P(RobustResourceInitTestES3, GenerateMipmapCubeMap)
{ {
......
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