Commit 15d5965d by Mohan Maiya Committed by Commit Bot

Vulkan: Support VK_KHR_image_format_list for PbufferSurfaces

PbufferSurfaces are now created with VK_KHR_image_format_list extension support enabled. Bug: angleproject:2514 Bug: angleproject:5281 Test: PbufferTest.ClearAndBindTexImageSrgb*Vulkan Change-Id: I8977484c958328d00f688faa7adffff85a37a3b8 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2530535 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 4a74427e
...@@ -211,7 +211,9 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -211,7 +211,9 @@ void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->imageNativeBuffer = outExtensions->imageNativeBuffer =
getRenderer()->getFeatures().supportsAndroidHardwareBuffer.enabled; getRenderer()->getFeatures().supportsAndroidHardwareBuffer.enabled;
outExtensions->surfacelessContext = true; outExtensions->surfacelessContext = true;
outExtensions->glColorspace = getRenderer()->getFeatures().supportsSwapchainColorspace.enabled; outExtensions->glColorspace =
getRenderer()->getFeatures().supportsSwapchainColorspace.enabled &&
getRenderer()->getFeatures().supportsImageFormatList.enabled;
outExtensions->imageGlColorspace = outExtensions->imageGlColorspace =
outExtensions->glColorspace && getRenderer()->getFeatures().supportsImageFormatList.enabled; outExtensions->glColorspace && getRenderer()->getFeatures().supportsImageFormatList.enabled;
......
...@@ -115,6 +115,53 @@ bool Is90DegreeRotation(VkSurfaceTransformFlagsKHR transform) ...@@ -115,6 +115,53 @@ bool Is90DegreeRotation(VkSurfaceTransformFlagsKHR transform)
return ((transform & k90DegreeRotationVariants) != 0); return ((transform & k90DegreeRotationVariants) != 0);
} }
angle::Result InitImageHelper(DisplayVk *displayVk,
EGLint width,
EGLint height,
const vk::Format &vkFormat,
GLint samples,
bool isRobustResourceInitEnabled,
vk::ImageHelper *imageHelper)
{
RendererVk *renderer = displayVk->getRenderer();
const angle::Format &textureFormat = vkFormat.actualImageFormat();
bool isDepthOrStencilFormat = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0;
const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVkDepthStencilImageUsageFlags
: kSurfaceVkColorImageUsageFlags;
VkExtent3D extents = {std::max(static_cast<uint32_t>(width), 1u),
std::max(static_cast<uint32_t>(height), 1u), 1u};
// With the introduction of sRGB related GLES extensions any texture could be respecified
// causing it to be interpreted in a different colorspace. Create the VkImage accordingly.
VkImageCreateFlags imageCreateFlags = vk::kVkImageCreateFlagsNone;
VkImageFormatListCreateInfoKHR *additionalCreateInfo = nullptr;
VkFormat vkImageFormat = vkFormat.vkImageFormat;
VkFormat vkImageListFormat = vkFormat.actualImageFormat().isSRGB
? vk::ConvertToLinear(vkImageFormat)
: vk::ConvertToSRGB(vkImageFormat);
VkImageFormatListCreateInfoKHR formatListInfo = {};
if (renderer->getFeatures().supportsImageFormatList.enabled)
{
// Add VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to VkImage create flag
imageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
// There is just 1 additional format we might use to create a VkImageView for this VkImage
formatListInfo.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
formatListInfo.pNext = nullptr;
formatListInfo.viewFormatCount = 1;
formatListInfo.pViewFormats = &vkImageListFormat;
additionalCreateInfo = &formatListInfo;
}
ANGLE_TRY(imageHelper->initExternal(displayVk, gl::TextureType::_2D, extents, vkFormat, samples,
usage, imageCreateFlags, vk::ImageLayout::Undefined,
additionalCreateInfo, gl::LevelIndex(0), gl::LevelIndex(0),
1, 1, isRobustResourceInitEnabled));
return angle::Result::Continue;
}
} // namespace } // namespace
SurfaceVk::SurfaceVk(const egl::SurfaceState &surfaceState) : SurfaceImpl(surfaceState) {} SurfaceVk::SurfaceVk(const egl::SurfaceState &surfaceState) : SurfaceImpl(surfaceState) {}
...@@ -163,18 +210,10 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display ...@@ -163,18 +210,10 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display
GLint samples, GLint samples,
bool isRobustResourceInitEnabled) bool isRobustResourceInitEnabled)
{ {
RendererVk *renderer = displayVk->getRenderer(); ANGLE_TRY(InitImageHelper(displayVk, width, height, vkFormat, samples,
isRobustResourceInitEnabled, &image));
const angle::Format &textureFormat = vkFormat.actualImageFormat();
bool isDepthOrStencilFormat = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0;
const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVkDepthStencilImageUsageFlags
: kSurfaceVkColorImageUsageFlags;
VkExtent3D extents = {std::max(static_cast<uint32_t>(width), 1u),
std::max(static_cast<uint32_t>(height), 1u), 1u};
ANGLE_TRY(image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, samples, usage,
gl::LevelIndex(0), gl::LevelIndex(0), 1, 1, isRobustResourceInitEnabled));
RendererVk *renderer = displayVk->getRenderer();
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(image.initMemory(displayVk, renderer->getMemoryProperties(), flags)); ANGLE_TRY(image.initMemory(displayVk, renderer->getMemoryProperties(), flags));
...@@ -193,18 +232,10 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initializeWithExternalMemory( ...@@ -193,18 +232,10 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initializeWithExternalMemory(
bool isRobustResourceInitEnabled) bool isRobustResourceInitEnabled)
{ {
RendererVk *renderer = displayVk->getRenderer(); RendererVk *renderer = displayVk->getRenderer();
ASSERT(renderer->getFeatures().supportsExternalMemoryHost.enabled); ASSERT(renderer->getFeatures().supportsExternalMemoryHost.enabled);
const angle::Format &textureFormat = vkFormat.actualImageFormat(); ANGLE_TRY(InitImageHelper(displayVk, width, height, vkFormat, samples,
bool isDepthOrStencilFormat = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0; isRobustResourceInitEnabled, &image));
const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVkDepthStencilImageUsageFlags
: kSurfaceVkColorImageUsageFlags;
VkExtent3D extents = {std::max(static_cast<uint32_t>(width), 1u),
std::max(static_cast<uint32_t>(height), 1u), 1u};
ANGLE_TRY(image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, samples, usage,
gl::LevelIndex(0), gl::LevelIndex(0), 1, 1, isRobustResourceInitEnabled));
VkImportMemoryHostPointerInfoEXT importMemoryHostPointerInfo = {}; VkImportMemoryHostPointerInfoEXT importMemoryHostPointerInfo = {};
importMemoryHostPointerInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT; importMemoryHostPointerInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT;
......
...@@ -102,6 +102,34 @@ class PbufferTest : public ANGLETest ...@@ -102,6 +102,34 @@ class PbufferTest : public ANGLETest
} }
} }
void recreatePbufferInSrgbColorspace()
{
EGLWindow *window = getEGLWindow();
if (mPbuffer)
{
eglDestroySurface(window->getDisplay(), mPbuffer);
}
const EGLint pBufferSrgbAttributes[] = {
EGL_WIDTH,
static_cast<EGLint>(mPbufferSize),
EGL_HEIGHT,
static_cast<EGLint>(mPbufferSize),
EGL_TEXTURE_FORMAT,
mSupportsBindTexImage ? EGL_TEXTURE_RGBA : EGL_NO_TEXTURE,
EGL_TEXTURE_TARGET,
mSupportsBindTexImage ? EGL_TEXTURE_2D : EGL_NO_TEXTURE,
EGL_GL_COLORSPACE_KHR,
EGL_GL_COLORSPACE_SRGB_KHR,
EGL_NONE,
EGL_NONE,
};
mPbuffer = eglCreatePbufferSurface(window->getDisplay(), window->getConfig(),
pBufferSrgbAttributes);
}
GLuint mTextureProgram; GLuint mTextureProgram;
GLint mTextureUniformLocation; GLint mTextureUniformLocation;
...@@ -199,6 +227,77 @@ TEST_P(PbufferTest, BindTexImage) ...@@ -199,6 +227,77 @@ TEST_P(PbufferTest, BindTexImage)
glDeleteTextures(1, &texture); glDeleteTextures(1, &texture);
} }
// Test clearing a Pbuffer in sRGB colorspace and checking the color is correct.
// Then bind the Pbuffer to a texture and verify it renders correctly
TEST_P(PbufferTest, ClearAndBindTexImageSrgb)
{
EGLWindow *window = getEGLWindow();
// Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA
// textures.
ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage);
ANGLE_SKIP_TEST_IF(
!IsEGLDisplayExtensionEnabled(window->getDisplay(), "EGL_KHR_gl_colorspace"));
// Possible GLES driver bug on Pixel2 devices: http://anglebug.com/5321
ANGLE_SKIP_TEST_IF(IsPixel2() && IsOpenGLES());
GLubyte kLinearColor[] = {132, 55, 219, 255};
GLubyte kSrgbColor[] = {190, 128, 238, 255};
// Switch to sRGB
recreatePbufferInSrgbColorspace();
EGLint colorspace = 0;
eglQuerySurface(window->getDisplay(), mPbuffer, EGL_GL_COLORSPACE, &colorspace);
EXPECT_EQ(colorspace, EGL_GL_COLORSPACE_SRGB_KHR);
// Clear the Pbuffer surface with `kLinearColor`
eglMakeCurrent(window->getDisplay(), mPbuffer, mPbuffer, window->getContext());
ASSERT_EGL_SUCCESS();
glViewport(0, 0, static_cast<GLsizei>(mPbufferSize), static_cast<GLsizei>(mPbufferSize));
glClearColor(kLinearColor[0] / 255.0f, kLinearColor[1] / 255.0f, kLinearColor[2] / 255.0f,
kLinearColor[3] / 255.0f);
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
// Expect glReadPixels to be `kSrgbColor` with a tolerance of 1
EXPECT_PIXEL_NEAR(static_cast<GLint>(mPbufferSize) / 2, static_cast<GLint>(mPbufferSize) / 2,
kSrgbColor[0], kSrgbColor[1], kSrgbColor[2], kSrgbColor[3], 1);
window->makeCurrent();
// Create a texture and bind the Pbuffer to it
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
EXPECT_GL_NO_ERROR();
eglBindTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
glViewport(0, 0, getWindowWidth(), getWindowHeight());
ASSERT_EGL_SUCCESS();
// Sample from a texture with `kSrgbColor` data and render into a surface in linear colorspace.
glUseProgram(mTextureProgram);
glUniform1i(mTextureUniformLocation, 0);
drawQuad(mTextureProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
// Unbind the texture
eglReleaseTexImage(window->getDisplay(), mPbuffer, EGL_BACK_BUFFER);
ASSERT_EGL_SUCCESS();
// Expect glReadPixels to be `kLinearColor` with a tolerance of 1
EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, kLinearColor[0], kLinearColor[1],
kLinearColor[2], kLinearColor[3], 1);
glDeleteTextures(1, &texture);
}
// Verify that when eglBind/ReleaseTexImage are called, the texture images are freed and their // Verify that when eglBind/ReleaseTexImage are called, the texture images are freed and their
// size information is correctly updated. // size information is correctly updated.
TEST_P(PbufferTest, TextureSizeReset) TEST_P(PbufferTest, TextureSizeReset)
......
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