Commit 4e0e6f8a by Jamie Madill Committed by Commit Bot

WebGL Compat: Add DEPTH_STENCIL renderbuffers.

This special internal format was defined in the WebGL 1 spec as a special unsized format with at least 16 bits of depth and at least 8 bits of stencil. Intenally ANGLE will translate this to packed 24/8 depth/stencil. The new test is adapted from the WebGL test: conformance/renderbuffers/framebuffer-object-attachment BUG=angleproject:1708 Change-Id: I44b03e41889eed02481f603b8d52c530dcfed5ce Reviewed-on: https://chromium-review.googlesource.com/442094Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 2597fb64
...@@ -266,14 +266,15 @@ Context::Context(rx::EGLImplFactory *implFactory, ...@@ -266,14 +266,15 @@ Context::Context(rx::EGLImplFactory *implFactory,
mResetStrategy(GetResetStrategy(attribs)), mResetStrategy(GetResetStrategy(attribs)),
mRobustAccess(GetRobustAccess(attribs)), mRobustAccess(GetRobustAccess(attribs)),
mCurrentSurface(nullptr), mCurrentSurface(nullptr),
mSurfacelessFramebuffer(nullptr) mSurfacelessFramebuffer(nullptr),
mWebGLContext(GetWebGLContext(attribs))
{ {
if (mRobustAccess) if (mRobustAccess)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
initCaps(GetWebGLContext(attribs), displayExtensions); initCaps(displayExtensions);
initWorkarounds(); initWorkarounds();
mGLState.initialize(mCaps, mExtensions, getClientVersion(), GetDebug(attribs), mGLState.initialize(mCaps, mExtensions, getClientVersion(), GetDebug(attribs),
...@@ -2410,7 +2411,7 @@ bool Context::hasActiveTransformFeedback(GLuint program) const ...@@ -2410,7 +2411,7 @@ bool Context::hasActiveTransformFeedback(GLuint program) const
return false; return false;
} }
void Context::initCaps(bool webGLContext, const egl::DisplayExtensions &displayExtensions) void Context::initCaps(const egl::DisplayExtensions &displayExtensions)
{ {
mCaps = mImplementation->getNativeCaps(); mCaps = mImplementation->getNativeCaps();
...@@ -2468,11 +2469,11 @@ void Context::initCaps(bool webGLContext, const egl::DisplayExtensions &displayE ...@@ -2468,11 +2469,11 @@ void Context::initCaps(bool webGLContext, const egl::DisplayExtensions &displayE
mCaps.maxFragmentInputComponents = std::min<GLuint>(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4); mCaps.maxFragmentInputComponents = std::min<GLuint>(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
// WebGL compatibility // WebGL compatibility
mExtensions.webglCompatibility = webGLContext; mExtensions.webglCompatibility = mWebGLContext;
for (const auto &extensionInfo : GetExtensionInfoMap()) for (const auto &extensionInfo : GetExtensionInfoMap())
{ {
// If this context is for WebGL, disable all enableable extensions // If this context is for WebGL, disable all enableable extensions
if (webGLContext && extensionInfo.second.Requestable) if (mWebGLContext && extensionInfo.second.Requestable)
{ {
mExtensions.*(extensionInfo.second.ExtensionsMember) = false; mExtensions.*(extensionInfo.second.ExtensionsMember) = false;
} }
...@@ -2487,11 +2488,10 @@ void Context::updateCaps() ...@@ -2487,11 +2488,10 @@ void Context::updateCaps()
mCaps.compressedTextureFormats.clear(); mCaps.compressedTextureFormats.clear();
mTextureCaps.clear(); mTextureCaps.clear();
const TextureCapsMap &rendererFormats = mImplementation->getNativeTextureCaps(); for (auto capsIt : mImplementation->getNativeTextureCaps())
for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++)
{ {
GLenum format = i->first; GLenum format = capsIt.first;
TextureCaps formatCaps = i->second; TextureCaps formatCaps = capsIt.second;
const InternalFormat &formatInfo = GetInternalFormatInfo(format); const InternalFormat &formatInfo = GetInternalFormatInfo(format);
...@@ -3786,8 +3786,11 @@ void Context::renderbufferStorage(GLenum target, ...@@ -3786,8 +3786,11 @@ void Context::renderbufferStorage(GLenum target,
GLsizei width, GLsizei width,
GLsizei height) GLsizei height)
{ {
// Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
GLenum convertedInternalFormat = getConvertedRenderbufferFormat(internalformat);
Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer(); Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer();
handleError(renderbuffer->setStorage(internalformat, width, height)); handleError(renderbuffer->setStorage(convertedInternalFormat, width, height));
} }
void Context::renderbufferStorageMultisample(GLenum target, void Context::renderbufferStorageMultisample(GLenum target,
...@@ -3796,9 +3799,12 @@ void Context::renderbufferStorageMultisample(GLenum target, ...@@ -3796,9 +3799,12 @@ void Context::renderbufferStorageMultisample(GLenum target,
GLsizei width, GLsizei width,
GLsizei height) GLsizei height)
{ {
// Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
GLenum convertedInternalFormat = getConvertedRenderbufferFormat(internalformat);
Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer(); Renderbuffer *renderbuffer = mGLState.getCurrentRenderbuffer();
handleError(renderbuffer->setStorageMultisample(samples, internalformat, width, height)); handleError(
renderbuffer->setStorageMultisample(samples, convertedInternalFormat, width, height));
} }
} // namespace gl } // namespace gl
...@@ -655,7 +655,7 @@ class Context final : public ValidationContext ...@@ -655,7 +655,7 @@ class Context final : public ValidationContext
void initVersionStrings(); void initVersionStrings();
void initExtensionStrings(); void initExtensionStrings();
void initCaps(bool webGLContext, const egl::DisplayExtensions &displayExtensions); void initCaps(const egl::DisplayExtensions &displayExtensions);
void updateCaps(); void updateCaps();
void initWorkarounds(); void initWorkarounds();
...@@ -713,6 +713,7 @@ class Context final : public ValidationContext ...@@ -713,6 +713,7 @@ class Context final : public ValidationContext
bool mRobustAccess; bool mRobustAccess;
egl::Surface *mCurrentSurface; egl::Surface *mCurrentSurface;
Framebuffer *mSurfacelessFramebuffer; Framebuffer *mSurfacelessFramebuffer;
bool mWebGLContext;
State::DirtyBits mTexImageDirtyBits; State::DirtyBits mTexImageDirtyBits;
State::DirtyObjects mTexImageDirtyObjects; State::DirtyObjects mTexImageDirtyObjects;
......
...@@ -713,4 +713,12 @@ bool ValidationContext::usingDisplayTextureShareGroup() const ...@@ -713,4 +713,12 @@ bool ValidationContext::usingDisplayTextureShareGroup() const
return mDisplayTextureShareGroup; return mDisplayTextureShareGroup;
} }
GLenum ValidationContext::getConvertedRenderbufferFormat(GLenum internalformat) const
{
return mState.mExtensions.webglCompatibility && mState.mClientVersion.major == 2 &&
internalformat == GL_DEPTH_STENCIL
? GL_DEPTH24_STENCIL8
: internalformat;
}
} // namespace gl } // namespace gl
...@@ -121,6 +121,9 @@ class ValidationContext : angle::NonCopyable ...@@ -121,6 +121,9 @@ class ValidationContext : angle::NonCopyable
bool usingDisplayTextureShareGroup() const; bool usingDisplayTextureShareGroup() const;
// Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
GLenum getConvertedRenderbufferFormat(GLenum internalformat) const;
protected: protected:
ContextState mState; ContextState mState;
bool mSkipValidation; bool mSkipValidation;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "libANGLE/Buffer.h" #include "libANGLE/Buffer.h"
#include "libANGLE/Config.h" #include "libANGLE/Config.h"
#include "libANGLE/Context.h"
#include "libANGLE/Framebuffer.h" #include "libANGLE/Framebuffer.h"
#include "libANGLE/Program.h" #include "libANGLE/Program.h"
#include "libANGLE/Renderbuffer.h" #include "libANGLE/Renderbuffer.h"
...@@ -610,7 +611,10 @@ void QueryProgramiv(const Program *program, GLenum pname, GLint *params) ...@@ -610,7 +611,10 @@ void QueryProgramiv(const Program *program, GLenum pname, GLint *params)
} }
} }
void QueryRenderbufferiv(const Renderbuffer *renderbuffer, GLenum pname, GLint *params) void QueryRenderbufferiv(const Context *context,
const Renderbuffer *renderbuffer,
GLenum pname,
GLint *params)
{ {
ASSERT(renderbuffer != nullptr); ASSERT(renderbuffer != nullptr);
...@@ -623,7 +627,17 @@ void QueryRenderbufferiv(const Renderbuffer *renderbuffer, GLenum pname, GLint * ...@@ -623,7 +627,17 @@ void QueryRenderbufferiv(const Renderbuffer *renderbuffer, GLenum pname, GLint *
*params = renderbuffer->getHeight(); *params = renderbuffer->getHeight();
break; break;
case GL_RENDERBUFFER_INTERNAL_FORMAT: case GL_RENDERBUFFER_INTERNAL_FORMAT:
*params = renderbuffer->getFormat().info->internalFormat; // Special case the WebGL 1 DEPTH_STENCIL format.
if (context->getExtensions().webglCompatibility &&
context->getClientMajorVersion() == 2 &&
renderbuffer->getFormat().info->internalFormat == GL_DEPTH24_STENCIL8)
{
*params = GL_DEPTH_STENCIL;
}
else
{
*params = renderbuffer->getFormat().info->internalFormat;
}
break; break;
case GL_RENDERBUFFER_RED_SIZE: case GL_RENDERBUFFER_RED_SIZE:
*params = renderbuffer->getRedSize(); *params = renderbuffer->getRedSize();
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
namespace gl namespace gl
{ {
class Buffer; class Buffer;
class Context;
class Framebuffer; class Framebuffer;
class Program; class Program;
class Renderbuffer; class Renderbuffer;
...@@ -37,7 +38,10 @@ void QueryBufferParameteriv(const Buffer *buffer, GLenum pname, GLint *params); ...@@ -37,7 +38,10 @@ void QueryBufferParameteriv(const Buffer *buffer, GLenum pname, GLint *params);
void QueryBufferParameteri64v(const Buffer *buffer, GLenum pname, GLint64 *params); void QueryBufferParameteri64v(const Buffer *buffer, GLenum pname, GLint64 *params);
void QueryBufferPointerv(const Buffer *buffer, GLenum pname, void **params); void QueryBufferPointerv(const Buffer *buffer, GLenum pname, void **params);
void QueryProgramiv(const Program *program, GLenum pname, GLint *params); void QueryProgramiv(const Program *program, GLenum pname, GLint *params);
void QueryRenderbufferiv(const Renderbuffer *renderbuffer, GLenum pname, GLint *params); void QueryRenderbufferiv(const Context *context,
const Renderbuffer *renderbuffer,
GLenum pname,
GLint *params);
void QueryShaderiv(const Shader *shader, GLenum pname, GLint *params); void QueryShaderiv(const Shader *shader, GLenum pname, GLint *params);
void QueryTexLevelParameterfv(const Texture *texture, void QueryTexLevelParameterfv(const Texture *texture,
GLenum target, GLenum target,
......
...@@ -1954,7 +1954,10 @@ bool ValidateRenderbufferStorageParametersBase(ValidationContext *context, ...@@ -1954,7 +1954,10 @@ bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
return false; return false;
} }
const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat); // Hack for the special WebGL 1 "DEPTH_STENCIL" internal format.
GLenum convertedInternalFormat = context->getConvertedRenderbufferFormat(internalformat);
const TextureCaps &formatCaps = context->getTextureCaps().get(convertedInternalFormat);
if (!formatCaps.renderable) if (!formatCaps.renderable)
{ {
context->handleError(Error(GL_INVALID_ENUM)); context->handleError(Error(GL_INVALID_ENUM));
...@@ -1964,7 +1967,7 @@ bool ValidateRenderbufferStorageParametersBase(ValidationContext *context, ...@@ -1964,7 +1967,7 @@ bool ValidateRenderbufferStorageParametersBase(ValidationContext *context,
// ANGLE_framebuffer_multisample does not explicitly state that the internal format must be // ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
// sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains // sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
// only sized internal formats. // only sized internal formats.
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat); const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(convertedInternalFormat);
if (formatInfo.pixelBytes == 0) if (formatInfo.pixelBytes == 0)
{ {
context->handleError(Error(GL_INVALID_ENUM)); context->handleError(Error(GL_INVALID_ENUM));
......
...@@ -1297,7 +1297,7 @@ void GL_APIENTRY GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* ...@@ -1297,7 +1297,7 @@ void GL_APIENTRY GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint*
} }
Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer(); Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
QueryRenderbufferiv(renderbuffer, pname, params); QueryRenderbufferiv(context, renderbuffer, pname, params);
} }
} }
......
...@@ -2151,7 +2151,7 @@ ANGLE_EXPORT void GL_APIENTRY GetRenderbufferParameterivRobustANGLE(GLenum targe ...@@ -2151,7 +2151,7 @@ ANGLE_EXPORT void GL_APIENTRY GetRenderbufferParameterivRobustANGLE(GLenum targe
} }
Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer(); Renderbuffer *renderbuffer = context->getGLState().getCurrentRenderbuffer();
QueryRenderbufferiv(renderbuffer, pname, params); QueryRenderbufferiv(context, renderbuffer, pname, params);
SetRobustLengthParam(length, numParams); SetRobustLengthParam(length, numParams);
} }
} }
......
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
'<(angle_path)/src/tests/gl_tests/VertexAttributeTest.cpp', '<(angle_path)/src/tests/gl_tests/VertexAttributeTest.cpp',
'<(angle_path)/src/tests/gl_tests/ViewportTest.cpp', '<(angle_path)/src/tests/gl_tests/ViewportTest.cpp',
'<(angle_path)/src/tests/gl_tests/WebGLCompatibilityTest.cpp', '<(angle_path)/src/tests/gl_tests/WebGLCompatibilityTest.cpp',
'<(angle_path)/src/tests/gl_tests/WebGLFramebufferTest.cpp',
'<(angle_path)/src/tests/egl_tests/EGLContextCompatibilityTest.cpp', '<(angle_path)/src/tests/egl_tests/EGLContextCompatibilityTest.cpp',
'<(angle_path)/src/tests/egl_tests/EGLContextSharingTest.cpp', '<(angle_path)/src/tests/egl_tests/EGLContextSharingTest.cpp',
'<(angle_path)/src/tests/egl_tests/EGLQueryContextTest.cpp', '<(angle_path)/src/tests/egl_tests/EGLQueryContextTest.cpp',
......
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// WebGLFramebufferTest.cpp : Framebuffer tests for GL_ANGLE_webgl_compatibility.
// Based on WebGL 1 test renderbuffers/framebuffer-object-attachment.
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
namespace angle
{
class WebGLFramebufferTest : public ANGLETest
{
protected:
WebGLFramebufferTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setWebGLCompatibilityEnabled(true);
}
void SetUp() override
{
ANGLETest::SetUp();
glRequestExtensionANGLE = reinterpret_cast<PFNGLREQUESTEXTENSIONANGLEPROC>(
eglGetProcAddress("glRequestExtensionANGLE"));
}
void TearDown() override { ANGLETest::TearDown(); }
PFNGLREQUESTEXTENSIONANGLEPROC glRequestExtensionANGLE = nullptr;
};
constexpr GLint ALLOW_COMPLETE = 0x1;
constexpr GLint ALLOW_UNSUPPORTED = 0x2;
constexpr GLint ALLOW_INCOMPLETE_ATTACHMENT = 0x4;
void checkFramebufferForAllowedStatuses(GLbitfield allowedStatuses)
{
// If the framebuffer is in an error state for multiple reasons,
// we can't guarantee which one will be reported.
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
bool statusAllowed =
((allowedStatuses & ALLOW_COMPLETE) && (status == GL_FRAMEBUFFER_COMPLETE)) ||
((allowedStatuses & ALLOW_UNSUPPORTED) && (status == GL_FRAMEBUFFER_UNSUPPORTED)) ||
((allowedStatuses & ALLOW_INCOMPLETE_ATTACHMENT) &&
(status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT));
EXPECT_TRUE(statusAllowed);
}
void checkBufferBits(GLenum attachment)
{
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return;
bool haveDepthBuffer =
attachment == GL_DEPTH_ATTACHMENT || attachment == GL_DEPTH_STENCIL_ATTACHMENT;
bool haveStencilBuffer =
attachment == GL_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL_ATTACHMENT;
GLint redBits = 0;
GLint greenBits = 0;
GLint blueBits = 0;
GLint alphaBits = 0;
GLint depthBits = 0;
GLint stencilBits = 0;
glGetIntegerv(GL_RED_BITS, &redBits);
glGetIntegerv(GL_GREEN_BITS, &greenBits);
glGetIntegerv(GL_BLUE_BITS, &blueBits);
glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
glGetIntegerv(GL_DEPTH_BITS, &depthBits);
glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
EXPECT_GE(redBits + greenBits + blueBits + alphaBits, 16);
if (haveDepthBuffer)
EXPECT_GE(depthBits, 16);
else
EXPECT_EQ(0, depthBits);
if (haveStencilBuffer)
EXPECT_GE(stencilBits, 8);
else
EXPECT_EQ(0, stencilBits);
}
// Tests that certain required combinations work in WebGL compatiblity.
TEST_P(WebGLFramebufferTest, TestFramebufferRequiredCombinations)
{
// Per discussion with the OpenGL ES working group, the following framebuffer attachment
// combinations are required to work in all WebGL implementations:
// 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
// 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16
// renderbuffer
// 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL
// renderbuffer
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
constexpr int width = 64;
constexpr int height = 64;
// 1. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
GLTexture 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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
EXPECT_GL_NO_ERROR();
checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
checkBufferBits(GL_COLOR_ATTACHMENT0);
// 2. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16
// renderbuffer
GLRenderbuffer renderbuffer;
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
EXPECT_GL_NO_ERROR();
checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
checkBufferBits(GL_DEPTH_ATTACHMENT);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
// 3. COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL
// renderbuffer
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
renderbuffer);
EXPECT_GL_NO_ERROR();
checkFramebufferForAllowedStatuses(ALLOW_COMPLETE);
checkBufferBits(GL_DEPTH_STENCIL_ATTACHMENT);
}
// Only run against WebGL 1 validation, since much was changed in 2.
ANGLE_INSTANTIATE_TEST(WebGLFramebufferTest,
ES2_D3D9(),
ES2_D3D11(),
ES2_D3D11_FL9_3(),
ES2_OPENGL(),
ES2_OPENGLES());
} // namespace
...@@ -38,6 +38,8 @@ class GLWrapper ...@@ -38,6 +38,8 @@ class GLWrapper
return mHandle; return mHandle;
} }
operator GLuint() { return get(); }
private: private:
GLuint mHandle = 0; GLuint mHandle = 0;
}; };
......
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