Commit 1f2782e0 by Courtney Goeltzenleuchter Committed by Commit Bot

Vulkan: fix unsized internalformat depth sampling

Many implementations provide OES_depth_texture behavior if the texture was specified with a non-sized format (e.g. GL_DEPTH_COMPONENT). This change implements that behavior for Vulkan and adds a couple of tests to verify it. Bug: angleproject:3890 Change-Id: I005b1eaa30db033f7d78a5cf2236aab7f442b7f5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1764301 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 26a87516
......@@ -767,7 +767,9 @@ angle::Result TextureVk::setStorage(const gl::Context *context,
releaseImage(contextVk);
}
ANGLE_TRY(initImage(contextVk, format, size, static_cast<uint32_t>(levels)));
gl::Format glFormat(internalFormat);
ANGLE_TRY(
initImage(contextVk, format, glFormat.info->sized, size, static_cast<uint32_t>(levels)));
return angle::Result::Continue;
}
......@@ -792,8 +794,9 @@ angle::Result TextureVk::setStorageExternalMemory(const gl::Context *context,
ANGLE_TRY(
memoryObjectVk->createImage(context, type, levels, internalFormat, size, offset, mImage));
ANGLE_TRY(
initImageViews(contextVk, format, static_cast<uint32_t>(levels), mImage->getLayerCount()));
gl::Format glFormat(internalFormat);
ANGLE_TRY(initImageViews(contextVk, format, glFormat.info->sized, static_cast<uint32_t>(levels),
mImage->getLayerCount()));
// TODO(spang): This needs to be reworked when semaphores are added.
// http://anglebug.com/3289
......@@ -826,7 +829,7 @@ angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
imageVk->getImageLevel(), imageVk->getImageLayer(), false);
ASSERT(type != gl::TextureType::CubeMap);
ANGLE_TRY(initImageViews(contextVk, format, 1, 1));
ANGLE_TRY(initImageViews(contextVk, format, image->getFormat().info->sized, 1, 1));
// Transfer the image to this queue if needed
uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
......@@ -1116,7 +1119,8 @@ angle::Result TextureVk::bindTexImage(const gl::Context *context, egl::Surface *
releaseAndDeleteImage(contextVk);
const vk::Format &format = renderer->getFormat(surface->getConfig()->renderTargetFormat);
GLenum internalFormat = surface->getConfig()->renderTargetFormat;
const vk::Format &format = renderer->getFormat(internalFormat);
// eglBindTexImage can only be called with pbuffer (offscreen) surfaces
OffscreenSurfaceVk *offscreenSurface = GetImplAs<OffscreenSurfaceVk>(surface);
......@@ -1124,7 +1128,8 @@ angle::Result TextureVk::bindTexImage(const gl::Context *context, egl::Surface *
surface->getMipmapLevel(), 0, false);
ASSERT(mImage->getLayerCount() == 1);
return initImageViews(contextVk, format, 1, 1);
gl::Format glFormat(internalFormat);
return initImageViews(contextVk, format, glFormat.info->sized, 1, 1);
}
angle::Result TextureVk::releaseTexImage(const gl::Context *context)
......@@ -1192,7 +1197,10 @@ angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk,
if (!mImage->valid())
{
ANGLE_TRY(initImage(contextVk, format, baseLevelExtents, levelCount));
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
ANGLE_TRY(initImage(contextVk, format, baseLevelDesc.format.info->sized, baseLevelExtents,
levelCount));
}
vk::CommandBuffer *commandBuffer = nullptr;
......@@ -1209,6 +1217,7 @@ angle::Result TextureVk::init3DRenderTargets(ContextVk *contextVk)
return angle::Result::Continue;
uint32_t layerCount = GetImageLayerCountForView(*mImage);
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
mLayerFetchImageView.resize(layerCount);
m3DRenderTargets.resize(layerCount);
......@@ -1221,7 +1230,8 @@ angle::Result TextureVk::init3DRenderTargets(ContextVk *contextVk)
// Users of the render target expect the views to directly view the desired layer, so we
// need create a fetch view for each layer as well.
gl::SwizzleState mappedSwizzle;
MapSwizzleState(contextVk, mImage->getFormat(), mState.getSwizzleState(), &mappedSwizzle);
MapSwizzleState(contextVk, mImage->getFormat(), baseLevelDesc.format.info->sized,
mState.getSwizzleState(), &mappedSwizzle);
gl::TextureType arrayType = vk::Get2DTextureType(layerCount, mImage->getSamples());
ANGLE_TRY(mImage->initLayerImageView(contextVk, arrayType, mImage->getAspectFlags(),
mappedSwizzle, &mLayerFetchImageView[layerIndex],
......@@ -1240,6 +1250,8 @@ angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk)
if (!mCubeMapRenderTargets.empty())
return angle::Result::Continue;
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
mLayerFetchImageView.resize(gl::kCubeFaceCount);
mCubeMapRenderTargets.resize(gl::kCubeFaceCount);
for (uint32_t cubeMapFaceIndex = 0; cubeMapFaceIndex < gl::kCubeFaceCount; ++cubeMapFaceIndex)
......@@ -1250,7 +1262,8 @@ angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk)
// Users of the render target expect the views to directly view the desired layer, so we
// need create a fetch view for each layer as well.
gl::SwizzleState mappedSwizzle;
MapSwizzleState(contextVk, mImage->getFormat(), mState.getSwizzleState(), &mappedSwizzle);
MapSwizzleState(contextVk, mImage->getFormat(), baseLevelDesc.format.info->sized,
mState.getSwizzleState(), &mappedSwizzle);
gl::TextureType arrayType = vk::Get2DTextureType(gl::kCubeFaceCount, mImage->getSamples());
ANGLE_TRY(mImage->initLayerImageView(contextVk, arrayType, mImage->getAspectFlags(),
mappedSwizzle, &mLayerFetchImageView[cubeMapFaceIndex],
......@@ -1296,7 +1309,10 @@ angle::Result TextureVk::syncState(const gl::Context *context,
mState.getType() == gl::TextureType::_2D ? 1 : mImage->getLayerCount();
releaseImageViews(contextVk);
ANGLE_TRY(initImageViews(contextVk, mImage->getFormat(), mImage->getLevelCount(),
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
ANGLE_TRY(initImageViews(contextVk, mImage->getFormat(),
baseLevelDesc.format.info->sized, mImage->getLevelCount(),
layerCount));
}
}
......@@ -1527,6 +1543,7 @@ const vk::Sampler &TextureVk::getSampler() const
angle::Result TextureVk::initImage(ContextVk *contextVk,
const vk::Format &format,
const bool sized,
const gl::Extents &extents,
const uint32_t levelCount)
{
......@@ -1566,7 +1583,7 @@ angle::Result TextureVk::initImage(ContextVk *contextVk,
ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags));
ANGLE_TRY(initImageViews(contextVk, format, levelCount, layerCount));
ANGLE_TRY(initImageViews(contextVk, format, sized, levelCount, layerCount));
// If the image has an emulated channel, always clear it. These channels will be masked out in
// future writes, and shouldn't contain uninitialized values.
......@@ -1631,13 +1648,14 @@ angle::Result TextureVk::initImageViewImpl(ContextVk *contextVk,
angle::Result TextureVk::initImageViews(ContextVk *contextVk,
const vk::Format &format,
const bool sized,
uint32_t levelCount,
uint32_t layerCount)
{
ASSERT(mImage != nullptr);
gl::SwizzleState mappedSwizzle;
MapSwizzleState(contextVk, format, mState.getSwizzleState(), &mappedSwizzle);
MapSwizzleState(contextVk, format, sized, mState.getSwizzleState(), &mappedSwizzle);
VkImageAspectFlags aspectFlags = vk::GetFormatAspectFlags(format.angleFormat());
if (HasBothDepthAndStencilAspects(aspectFlags))
......
......@@ -289,6 +289,7 @@ class TextureVk : public TextureImpl
angle::Result initImage(ContextVk *contextVk,
const vk::Format &format,
const bool sized,
const gl::Extents &extents,
const uint32_t levelCount);
void releaseImage(ContextVk *contextVk);
......@@ -297,6 +298,7 @@ class TextureVk : public TextureImpl
uint32_t getLevelCount() const;
angle::Result initImageViews(ContextVk *contextVk,
const vk::Format &format,
const bool sized,
uint32_t levelCount,
uint32_t layerCount);
angle::Result init3DRenderTargets(ContextVk *contextVk);
......
......@@ -334,6 +334,7 @@ void ComposeSwizzleState(const gl::SwizzleState &first,
void MapSwizzleState(const ContextVk *contextVk,
const vk::Format &format,
const bool sized,
const gl::SwizzleState &swizzleState,
gl::SwizzleState *swizzleStateOut)
{
......@@ -367,7 +368,8 @@ void MapSwizzleState(const ContextVk *contextVk,
bool hasRed = angleFormat.depthBits > 0;
// In OES_depth_texture/ARB_depth_texture, depth
// textures are treated as luminance.
bool hasGB = hasRed && contextVk->getClientMajorVersion() <= 2;
// If the internalformat was not sized, use OES_depth_texture behavior
bool hasGB = hasRed && !sized;
internalSwizzle.swizzleRed = hasRed ? GL_RED : GL_ZERO;
internalSwizzle.swizzleGreen = hasGB ? GL_RED : GL_ZERO;
......
......@@ -155,6 +155,7 @@ size_t GetVertexInputAlignment(const vk::Format &format);
void MapSwizzleState(const ContextVk *contextVk,
const vk::Format &format,
const bool sized,
const gl::SwizzleState &swizzleState,
gl::SwizzleState *swizzleStateOut);
} // namespace rx
......
......@@ -4341,6 +4341,169 @@ TEST_P(Texture2DTestES3, DepthTexturesWithMipmaps)
ASSERT_GL_NO_ERROR();
}
class Texture2DDepthTest : public Texture2DTest
{
protected:
Texture2DDepthTest() : Texture2DTest() {}
const char *getVertexShaderSource() override
{
return "attribute vec4 vPosition;\n"
"void main() {\n"
" gl_Position = vPosition;\n"
"}\n";
}
const char *getFragmentShaderSource() override
{
return "precision mediump float;\n"
"uniform sampler2D ShadowMap;"
"void main() {\n"
" vec4 shadow_value = texture2D(ShadowMap, vec2(0.5, 0.5));"
" if (shadow_value.x == shadow_value.z && shadow_value.x != 0.0) {"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);"
" } else {"
" gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
" }"
"}\n";
}
bool checkTexImageFormatSupport(GLenum format, GLenum internalformat, GLenum type)
{
EXPECT_GL_NO_ERROR();
GLTexture tex;
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, format, 1, 1, 0, format, type, nullptr);
return (glGetError() == GL_NO_ERROR);
}
void testBehavior(bool useSizedComponent)
{
int w = getWindowWidth();
int h = getWindowHeight();
GLuint format = GL_DEPTH_COMPONENT;
GLuint internalFormat = GL_DEPTH_COMPONENT;
if (useSizedComponent)
{
internalFormat = GL_DEPTH_COMPONENT24;
}
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
ASSERT_GL_NO_ERROR();
GLTexture depthTexture;
glBindTexture(GL_TEXTURE_2D, depthTexture);
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);
TexCoordDrawTest::setUpProgram();
GLint shadowMapLocation = glGetUniformLocation(mProgram, "ShadowMap");
ASSERT_NE(-1, shadowMapLocation);
GLint positionLocation = glGetAttribLocation(mProgram, "vPosition");
ASSERT_NE(-1, positionLocation);
ANGLE_SKIP_TEST_IF(!checkTexImageFormatSupport(format, internalFormat, GL_UNSIGNED_INT));
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, GL_UNSIGNED_INT, nullptr);
ASSERT_GL_NO_ERROR();
// try adding a color buffer.
GLuint colorTex = 0;
glGenTextures(1, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
ASSERT_GL_NO_ERROR();
glViewport(0, 0, w, h);
// Fill depthTexture with 0.75
glClearDepthf(0.75);
glClear(GL_DEPTH_BUFFER_BIT);
// Revert to normal framebuffer to test depth shader
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, w, h);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepthf(0.0f);
ASSERT_GL_NO_ERROR();
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glUseProgram(mProgram);
ASSERT_GL_NO_ERROR();
glUniform1i(shadowMapLocation, 0);
const GLfloat gTriangleVertices[] = {-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f};
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
ASSERT_GL_NO_ERROR();
glEnableVertexAttribArray(positionLocation);
ASSERT_GL_NO_ERROR();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
ASSERT_GL_NO_ERROR();
GLuint pixels[1];
glReadPixels(w / 2, h / 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
ASSERT_GL_NO_ERROR();
// The GLES 3.x spec says that the depth texture sample can be found in the RED component.
// However, the OES_depth_texture indicates that the depth value is treated as luminance and
// is in all the color components. Multiple implementations implement a workaround that
// follows the OES_depth_texture behavior if the internalformat given at glTexImage2D was a
// unsized format (e.g. DEPTH_COMPONENT) and the GLES 3.x behavior if it was a sized
// internalformat such as GL_DEPTH_COMPONENT24. The shader will write out a different color
// depending on if it sees the texture sample in only the RED component.
if (useSizedComponent)
{
ASSERT_NE(pixels[0], 0xff0000ff);
}
else
{
ASSERT_EQ(pixels[0], 0xff0000ff);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteProgram(mProgram);
}
};
// Test depth texture compatibility with OES_depth_texture. Uses unsized internformat.
TEST_P(Texture2DDepthTest, DepthTextureES2Compatibility)
{
ANGLE_SKIP_TEST_IF(IsD3D11());
ANGLE_SKIP_TEST_IF(IsIntel() && IsD3D9());
// When the depth texture is specified with unsized internalformat implementations follow
// OES_depth_texture behavior. Otherwise they follow GLES 3.0 behavior.
testBehavior(false);
}
// Test depth texture compatibility with GLES3 using sized internalformat.
TEST_P(Texture2DDepthTest, DepthTextureES3Compatibility)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
testBehavior(true);
}
// Tests unpacking into the unsized GL_ALPHA format.
TEST_P(Texture2DTestES3, UnsizedAlphaUnpackBuffer)
{
......@@ -5105,5 +5268,12 @@ ANGLE_INSTANTIATE_TEST(TextureCubeIntegerEdgeTestES3, ES3_D3D11(), ES3_OPENGL())
ANGLE_INSTANTIATE_TEST(Texture2DIntegerProjectiveOffsetTestES3, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(Texture2DArrayIntegerTestES3, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(Texture3DIntegerTestES3, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(Texture2DDepthTest,
ES2_D3D9(),
ES2_D3D11(),
ES2_OPENGL(),
ES2_OPENGLES(),
ES2_VULKAN(),
ES3_VULKAN());
} // anonymous namespace
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