Commit 349c0830 by Mohan Maiya Committed by Angle LUCI CQ

Vulkan: Handle immutable sampler state change in TextureVk

Transitioning between sources in RGB and YUV colorspace or between YUV formats with different layout should force the recreation of pipeline layout and the invalidation of texture's sampler. Only textures that are EGLImage targets are handled for now. Bug: b/155487768 Bug: angleproject:5033 Bug: angleproject:5773 Test: ImageTest.SourceAHBTarget2DExternalCycleThrough*Vulkan Change-Id: I02d5763e7f89b910313e14b57bfc5403113dfbb2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2924415Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
parent 135d1483
...@@ -4820,7 +4820,7 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context) ...@@ -4820,7 +4820,7 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask(); const gl::ActiveTextureMask &activeTextures = executable->getActiveSamplersMask();
const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes(); const gl::ActiveTextureTypeArray &textureTypes = executable->getActiveSamplerTypes();
bool haveImmutableSampler = false; bool recreatePipelineLayout = false;
for (size_t textureUnit : activeTextures) for (size_t textureUnit : activeTextures)
{ {
gl::Texture *texture = textures[textureUnit]; gl::Texture *texture = textures[textureUnit];
...@@ -4898,16 +4898,13 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context) ...@@ -4898,16 +4898,13 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context)
textureVk->getImageViewSubresourceSerial(samplerState); textureVk->getImageViewSubresourceSerial(samplerState);
mActiveTexturesDesc.update(textureUnit, imageViewSerial, samplerHelper.getSamplerSerial()); mActiveTexturesDesc.update(textureUnit, imageViewSerial, samplerHelper.getSamplerSerial());
if (textureVk->getImage().hasImmutableSampler()) recreatePipelineLayout =
{ textureVk->getAndResetImmutableSamplerDirtyState() || recreatePipelineLayout;
haveImmutableSampler = true;
}
} }
if (haveImmutableSampler) // Recreate the pipeline layout, if necessary.
if (recreatePipelineLayout)
{ {
// TODO(http://anglebug.com/5033): This will recreate the descriptor pools each time, which
// will likely affect performance negatively.
ANGLE_TRY(mExecutable->createPipelineLayout(context, &mActiveTextures)); ANGLE_TRY(mExecutable->createPipelineLayout(context, &mActiveTextures));
// The default uniforms descriptor set was reset during createPipelineLayout(), so mark them // The default uniforms descriptor set was reset during createPipelineLayout(), so mark them
......
...@@ -269,6 +269,7 @@ TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer) ...@@ -269,6 +269,7 @@ TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer)
: TextureImpl(state), : TextureImpl(state),
mOwnsImage(false), mOwnsImage(false),
mRequiresMutableStorage(false), mRequiresMutableStorage(false),
mImmutableSamplerDirty(false),
mImageNativeType(gl::TextureType::InvalidEnum), mImageNativeType(gl::TextureType::InvalidEnum),
mImageLayerOffset(0), mImageLayerOffset(0),
mImageLevelOffset(0), mImageLevelOffset(0),
...@@ -1289,18 +1290,50 @@ angle::Result TextureVk::setStorageExternalMemory(const gl::Context *context, ...@@ -1289,18 +1290,50 @@ angle::Result TextureVk::setStorageExternalMemory(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
void TextureVk::handleImmutableSamplerTransition(const vk::ImageHelper *previousImage,
const vk::ImageHelper *nextImage)
{
// Did the previous image have an immutable sampler
bool previousImageHadImmutableSampler =
previousImage && previousImage->valid() && previousImage->hasImmutableSampler();
// Does the next image require an immutable sampler?
bool nextImageRequiresImmutableSampler =
nextImage && nextImage->valid() && nextImage->hasImmutableSampler();
// Has the external format changed?
bool externalFormatChanged = false;
if (previousImageHadImmutableSampler && nextImageRequiresImmutableSampler)
{
externalFormatChanged =
previousImage->getExternalFormat() != nextImage->getExternalFormat();
}
// Handle transition of immutable sampler state
if ((previousImageHadImmutableSampler != nextImageRequiresImmutableSampler) ||
externalFormatChanged)
{
// The immutable sampler state is dirty.
mSampler.reset();
mImmutableSamplerDirty = true;
}
}
angle::Result TextureVk::setEGLImageTarget(const gl::Context *context, angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
gl::TextureType type, gl::TextureType type,
egl::Image *image) egl::Image *image)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
ImageVk *imageVk = vk::GetImpl(image);
// TODO: Textures other than EGLImage targets can have immutable samplers.
// http://anglebug.com/5773
handleImmutableSamplerTransition(mImage, (imageVk) ? imageVk->getImage() : nullptr);
releaseAndDeleteImageAndViews(contextVk); releaseAndDeleteImageAndViews(contextVk);
const vk::Format &format = renderer->getFormat(image->getFormat().info->sizedInternalFormat); const vk::Format &format = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
ImageVk *imageVk = vk::GetImpl(image);
setImageHelper(contextVk, imageVk->getImage(), imageVk->getImageTextureType(), format, setImageHelper(contextVk, imageVk->getImage(), imageVk->getImageTextureType(), format,
imageVk->getImageLevel().get(), imageVk->getImageLayer(), imageVk->getImageLevel().get(), imageVk->getImageLayer(),
gl::LevelIndex(mState.getEffectiveBaseLevel()), false); gl::LevelIndex(mState.getEffectiveBaseLevel()), false);
......
...@@ -273,6 +273,13 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -273,6 +273,13 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
angle::Result ensureMutable(ContextVk *contextVk); angle::Result ensureMutable(ContextVk *contextVk);
bool getAndResetImmutableSamplerDirtyState()
{
bool isDirty = mImmutableSamplerDirty;
mImmutableSamplerDirty = false;
return isDirty;
}
private: private:
// Transform an image index from the frontend into one that can be used on the backing // Transform an image index from the frontend into one that can be used on the backing
// ImageHelper, taking into account mipmap or cube face offsets // ImageHelper, taking into account mipmap or cube face offsets
...@@ -469,9 +476,12 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface ...@@ -469,9 +476,12 @@ class TextureVk : public TextureImpl, public angle::ObserverInterface
angle::Result refreshImageViews(ContextVk *contextVk); angle::Result refreshImageViews(ContextVk *contextVk);
bool shouldDecodeSRGB(ContextVk *contextVk, GLenum srgbDecode, bool texelFetchStaticUse) const; bool shouldDecodeSRGB(ContextVk *contextVk, GLenum srgbDecode, bool texelFetchStaticUse) const;
void initImageUsageFlags(ContextVk *contextVk, const vk::Format &format); void initImageUsageFlags(ContextVk *contextVk, const vk::Format &format);
void handleImmutableSamplerTransition(const vk::ImageHelper *previousImage,
const vk::ImageHelper *nextImage);
bool mOwnsImage; bool mOwnsImage;
bool mRequiresMutableStorage; bool mRequiresMutableStorage;
bool mImmutableSamplerDirty;
gl::TextureType mImageNativeType; gl::TextureType mImageNativeType;
......
...@@ -1871,7 +1871,7 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -1871,7 +1871,7 @@ class ImageHelper final : public Resource, public angle::Subject
uint32_t layerStart, uint32_t layerStart,
uint32_t layerCount, uint32_t layerCount,
VkImageAspectFlags aspectFlags); VkImageAspectFlags aspectFlags);
bool hasImmutableSampler() { return mExternalFormat != 0; } bool hasImmutableSampler() const { return mExternalFormat != 0; }
uint64_t getExternalFormat() const { return mExternalFormat; } uint64_t getExternalFormat() const { return mExternalFormat; }
// Used by framebuffer and render pass functions to decide loadOps and invalidate/un-invalidate // Used by framebuffer and render pass functions to decide loadOps and invalidate/un-invalidate
......
...@@ -93,9 +93,11 @@ GLubyte kSrgbColorCube[] = {18, 62, 155, 255, 149, 26, 60, 255, 41, 149, 38, ...@@ -93,9 +93,11 @@ GLubyte kSrgbColorCube[] = {18, 62, 155, 255, 149, 26, 60, 255, 41, 149, 38,
3, 26, 202, 255, 117, 164, 16, 255, 19, 41, 32, 255}; 3, 26, 202, 255, 117, 164, 16, 255, 19, 41, 32, 255};
constexpr int kColorspaceAttributeIndex = 2; constexpr int kColorspaceAttributeIndex = 2;
constexpr int AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1; constexpr int AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1;
constexpr int AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31; constexpr int AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31;
constexpr int AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23; constexpr int AHARDWAREBUFFER_FORMAT_Y8Cr8Cb8_420_SP = 0x11;
constexpr int AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23;
constexpr int AHARDWAREBUFFER_FORMAT_YV12 = 0x32315659;
} // anonymous namespace } // anonymous namespace
...@@ -1878,6 +1880,148 @@ void ImageTest::SourceAHBTarget2D_helper(const EGLint *attribs) ...@@ -1878,6 +1880,148 @@ void ImageTest::SourceAHBTarget2D_helper(const EGLint *attribs)
glDeleteTextures(1, &target); glDeleteTextures(1, &target);
} }
// Testing source AHB EGL images, target 2D external texture, cycling through YUV sources.
TEST_P(ImageTest, SourceAHBTarget2DExternalCycleThroughYuvSourcesNoData)
{
ANGLE_SKIP_TEST_IF(!IsAndroid());
EGLWindow *window = getEGLWindow();
ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt() || !has2DTextureExt());
ANGLE_SKIP_TEST_IF(!hasAndroidImageNativeBufferExt() || !hasAndroidHardwareBufferSupport());
// Create YCbCr source and image but without initial data
AHardwareBuffer *ycbcrSource;
EGLImageKHR ycbcrImage;
createEGLImageAndroidHardwareBufferSource(2, 2, 1, AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
kDefaultAttribs, {}, &ycbcrSource, &ycbcrImage);
EXPECT_NE(ycbcrSource, nullptr);
EXPECT_NE(ycbcrImage, EGL_NO_IMAGE_KHR);
// Create YCrCb source and image but without initial data
AHardwareBuffer *ycrcbSource;
EGLImageKHR ycrcbImage;
createEGLImageAndroidHardwareBufferSource(2, 2, 1, AHARDWAREBUFFER_FORMAT_Y8Cr8Cb8_420_SP,
kDefaultAttribs, {}, &ycrcbSource, &ycrcbImage);
EXPECT_NE(ycrcbSource, nullptr);
EXPECT_NE(ycrcbImage, EGL_NO_IMAGE_KHR);
// Create YV12 source and image but without initial data
AHardwareBuffer *yv12Source;
EGLImageKHR yv12Image;
createEGLImageAndroidHardwareBufferSource(2, 2, 1, AHARDWAREBUFFER_FORMAT_YV12, kDefaultAttribs,
{}, &yv12Source, &yv12Image);
EXPECT_NE(yv12Source, nullptr);
EXPECT_NE(yv12Image, EGL_NO_IMAGE_KHR);
// Create a texture target to bind the egl image
GLTexture target;
glBindTexture(GL_TEXTURE_EXTERNAL_OES, target);
// Disable mipmapping
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Bind YCbCr image
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, ycbcrImage);
// Draw while sampling should result in no EGL/GL errors
glUseProgram(mTextureExternalProgram);
glUniform1i(mTextureExternalUniformLocation, 0);
drawQuad(mTextureExternalProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
// Bind YCrCb image
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, ycrcbImage);
// Draw while sampling should result in no EGL/GL errors
glUseProgram(mTextureExternalProgram);
glUniform1i(mTextureExternalUniformLocation, 0);
drawQuad(mTextureExternalProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
// Bind YV12 image
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, yv12Image);
// Draw while sampling should result in no EGL/GL errors
glUseProgram(mTextureExternalProgram);
glUniform1i(mTextureExternalUniformLocation, 0);
drawQuad(mTextureExternalProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
// Clean up
eglDestroyImageKHR(window->getDisplay(), ycbcrImage);
destroyAndroidHardwareBuffer(ycbcrSource);
eglDestroyImageKHR(window->getDisplay(), ycrcbImage);
destroyAndroidHardwareBuffer(ycrcbSource);
eglDestroyImageKHR(window->getDisplay(), yv12Image);
destroyAndroidHardwareBuffer(yv12Source);
}
// Testing source AHB EGL images, target 2D external texture, cycling through RGB and YUV sources.
TEST_P(ImageTest, SourceAHBTarget2DExternalCycleThroughRgbAndYuvSources)
{
ANGLE_SKIP_TEST_IF(!IsAndroid());
EGLWindow *window = getEGLWindow();
ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt() || !has2DTextureExt());
ANGLE_SKIP_TEST_IF(!hasAndroidImageNativeBufferExt() || !hasAndroidHardwareBufferSupport());
// Create RGB Image
GLubyte rgbColor[4] = {0, 0, 255, 255};
AHardwareBuffer *rgbSource;
EGLImageKHR rgbImage;
createEGLImageAndroidHardwareBufferSource(1, 1, 1, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
kDefaultAttribs, {{rgbColor, 4}}, &rgbSource,
&rgbImage);
// Create YUV Image
// 3 planes of data
GLubyte dataY[4] = {40, 40, 40, 40};
GLubyte dataCb[1] = {
240,
};
GLubyte dataCr[1] = {
109,
};
GLubyte expectedRgbColor[4] = {0, 0, 255, 255};
AHardwareBuffer *yuvSource;
EGLImageKHR yuvImage;
createEGLImageAndroidHardwareBufferSource(
2, 2, 1, AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420, kDefaultAttribs,
{{dataY, 1}, {dataCb, 1}, {dataCr, 1}}, &yuvSource, &yuvImage);
// Create a texture target to bind the egl image
GLTexture target;
glBindTexture(GL_TEXTURE_EXTERNAL_OES, target);
// Disable mipmapping
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
ASSERT_GL_NO_ERROR();
// Bind YUV image
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, yuvImage);
// Expect render target to have the same color as expectedRgbColor
verifyResultsExternal(target, expectedRgbColor);
// Bind RGB image
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, rgbImage);
// Expect render target to have the same color as rgbColor
verifyResultsExternal(target, rgbColor);
// Bind YUV image
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, yuvImage);
// Expect render target to have the same color as expectedRgbColor
verifyResultsExternal(target, expectedRgbColor);
// Clean up
eglDestroyImageKHR(window->getDisplay(), yuvImage);
destroyAndroidHardwareBuffer(yuvSource);
eglDestroyImageKHR(window->getDisplay(), rgbImage);
destroyAndroidHardwareBuffer(rgbSource);
}
// Testing source AHB EGL image, target 2D texture retaining initial data. // Testing source AHB EGL image, target 2D texture retaining initial data.
TEST_P(ImageTest, SourceAHBTarget2DRetainInitialData) TEST_P(ImageTest, SourceAHBTarget2DRetainInitialData)
{ {
......
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