Commit c287ea6e by Geoff Lang Committed by Commit Bot

Add WebGL validation extensions to ANGLE.

BUG=angleproject:1523 Change-Id: I6fecb5055ed8087665aeee34b3a066ea8f38d51b Reviewed-on: https://chromium-review.googlesource.com/386281Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarAntoine Labour <piman@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent 10f563d5
Name
ANGLE_webgl_compatibility
Name Strings
GL_ANGLE_webgl_compatibility
Contributors
Geoff Lang
Contact
Geoff Lang (geofflang 'at' google.com)
Notice
Copyright (c) 2016 The Khronos Group Inc. Copyright terms at
http://www.khronos.org/registry/speccopyright.html
Status
Draft
Version
Version 1, September 16, 2016
Number
OpenGL ES Extension #??
Dependencies
Requires OpenGL ES 2.0
Written against the OpenGL ES 2.0 specification.
Interacts with EGL_ANGLE_create_context_webgl_compatibility (or equivalent)
extension.
Overview
With this extension enabled, the OpenGL ES context will have additional
features and validation to be compatible with the WebGL specification.
New Procedures and Functions
boolean EnableExtension(const char *name)
New Tokens
None
Additions to the OpenGL ES Specification
The command
boolean EnableExtension(const char *name)
enables the OpenGL ES extension named <name>. Returns true on success and
false otherwise. If the extension does not support being enabled or <name>
does not name a valid OpenGL ES extension, INVALID_OPERATION is generated.
If the extension is valid but is not supported by the context, no error is
generated but false is returned.
Additional validation will be performed according to the the sections of
the WebGL specification entitled "Differences Between WebGL and OpenGL ES
2.0" and "Differences Between WebGL and OpenGL ES 3.0".
New State
None
Conformance Tests
TBD
Issues
(1) How can the user determine which extensions can be enabled without
potentially generating errors?
This can be solved by:
a) Never generate an error in EnableExtensions, simply return false when
the extension is not recognized or cannot be enabled.
b) Add another entry point to query all extensions that the context
supports enabling.
Revision History
Rev. Date Author Changes
---- ------------- --------- ----------------------------------------
1 Sept 16, 2016 geofflang Initial version
Name
ANGLE_create_context_webgl_compatibility
Name Strings
EGL_ANGLE_create_context_webgl_compatibility
Contributors
Geoff Lang
Contacts
Geoff Lang (geofflang 'at' google.com)
Status
Draft
Version
Version 1, September 16, 2016
Number
EGL Extension #??
Dependencies
Requires EGL 1.4.
Written against the EGL 1.4 specification.
This spec interacts with GL_ANGLE_webgl_compatibility (or equivalent)
extension.
Overview
This extension allows the creation of an OpenGL or OpenGL ES context that
provides additional WebGL features and validation.
New Types
None
New Procedures and Functions
None
New Tokens
Accepted as an attribute name in the <*attrib_list> argument to
eglCreateContext:
EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x3AAC
Additions to the EGL 1.4 Specification
Add the following to section 3.7.1 "Creating Rendering Contexts":
EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE indicates whether a WebGL mode should
be enabled for the OpenGL ES context. In this mode, the OpenGL ES context
will provide additional features and validation to be compatible with the
WebGL specification. The default value of
EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE is EGL_FALSE.
Errors
None
New State
None
Conformance Tests
TBD
Issues
None
Revision History
Rev. Date Author Changes
---- ------------- --------- ----------------------------------------
1 Sept 16, 2016 geofflang Initial version
...@@ -567,6 +567,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglStreamPostD3DTextureNV12ANGLE(EGLDisplay dpy, E ...@@ -567,6 +567,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglStreamPostD3DTextureNV12ANGLE(EGLDisplay dpy, E
#endif #endif
#endif /* EGL_ANGLE_stream_producer_d3d_texture_nv12 */ #endif /* EGL_ANGLE_stream_producer_d3d_texture_nv12 */
#ifndef EGL_ANGLE_create_context_webgl_compatibility
#define EGL_ANGLE_create_context_webgl_compatibility 1
#define EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x3AAC
#endif /* EGL_ANGLE_create_context_webgl_compatibility */
#ifndef EGL_ARM_pixmap_multisample_discard #ifndef EGL_ARM_pixmap_multisample_discard
#define EGL_ARM_pixmap_multisample_discard 1 #define EGL_ARM_pixmap_multisample_discard 1
#define EGL_DISCARD_SAMPLES_ARM 0x3286 #define EGL_DISCARD_SAMPLES_ARM 0x3286
......
...@@ -821,6 +821,14 @@ GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GL ...@@ -821,6 +821,14 @@ GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GL
#endif #endif
#endif /* GL_ANGLE_framebuffer_blit */ #endif /* GL_ANGLE_framebuffer_blit */
#ifndef GL_ANGLE_webgl_compatibility
#define GL_ANGLE_webgl_compatibility 1
typedef GLboolean(GL_APIENTRYP PFNGLENABLEEXTENSIONANGLEPROC) (const GLchar *name);
#ifdef GL_GLEXT_PROTOTYPES
GL_APICALL GLboolean GL_APIENTRY glEnableExtensionANGLE (const GLchar *name);
#endif
#endif /* GL_ANGLE_webgl_compatibility */
#ifndef GL_CHROMIUM_framebuffer_mixed_samples #ifndef GL_CHROMIUM_framebuffer_mixed_samples
#define GL_CHROMIUM_frambuffer_mixed_samples 1 #define GL_CHROMIUM_frambuffer_mixed_samples 1
#define GL_COVERAGE_MODULATION_CHROMIUM 0x9332 #define GL_COVERAGE_MODULATION_CHROMIUM 0x9332
......
...@@ -52,6 +52,7 @@ class TextureCapsMap ...@@ -52,6 +52,7 @@ class TextureCapsMap
void insert(GLenum internalFormat, const TextureCaps &caps); void insert(GLenum internalFormat, const TextureCaps &caps);
void remove(GLenum internalFormat); void remove(GLenum internalFormat);
void clear();
const TextureCaps &get(GLenum internalFormat) const; const TextureCaps &get(GLenum internalFormat) const;
...@@ -292,6 +293,9 @@ struct Extensions ...@@ -292,6 +293,9 @@ struct Extensions
// GL_CHROMIUM_copy_texture // GL_CHROMIUM_copy_texture
bool copyTexture; bool copyTexture;
// GL_ANGLE_webgl_compatibility
bool webglCompatibility;
// ES3 Extension support // ES3 Extension support
// GL_EXT_color_buffer_float // GL_EXT_color_buffer_float
...@@ -312,6 +316,19 @@ struct Extensions ...@@ -312,6 +316,19 @@ struct Extensions
bool pathRendering; bool pathRendering;
}; };
struct ExtensionInfo
{
// If this extension can be enabled with glEnableExtension (GL_ANGLE_webgl_compatibility)
bool Enableable = false;
// Pointer to a boolean member of the Extensions struct
typedef bool(Extensions::*ExtensionBool);
ExtensionBool ExtensionsMember = nullptr;
};
using ExtensionInfoMap = std::map<std::string, ExtensionInfo>;
const ExtensionInfoMap &GetExtensionInfoMap();
struct Limitations struct Limitations
{ {
Limitations(); Limitations();
...@@ -572,6 +589,9 @@ struct DisplayExtensions ...@@ -572,6 +589,9 @@ struct DisplayExtensions
// EGL_ANGLE_stream_producer_d3d_texture_nv12 // EGL_ANGLE_stream_producer_d3d_texture_nv12
bool streamProducerD3DTextureNV12; bool streamProducerD3DTextureNV12;
// EGL_ANGLE_create_context_webgl_compatibility
bool createContextWebGLCompatibility;
}; };
struct DeviceExtensions struct DeviceExtensions
......
...@@ -179,6 +179,11 @@ bool GetNoError(const egl::AttributeMap &attribs) ...@@ -179,6 +179,11 @@ bool GetNoError(const egl::AttributeMap &attribs)
return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE); return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE);
} }
bool GetWebGLContext(const egl::AttributeMap &attribs)
{
return (attribs.get(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE, EGL_FALSE) == EGL_TRUE);
}
std::string GetObjectLabelFromPointer(GLsizei length, const GLchar *label) std::string GetObjectLabelFromPointer(GLsizei length, const GLchar *label)
{ {
std::string labelName; std::string labelName;
...@@ -244,7 +249,7 @@ Context::Context(rx::EGLImplFactory *implFactory, ...@@ -244,7 +249,7 @@ Context::Context(rx::EGLImplFactory *implFactory,
{ {
ASSERT(!mRobustAccess); // Unimplemented ASSERT(!mRobustAccess); // Unimplemented
initCaps(); initCaps(GetWebGLContext(attribs));
mGLState.initialize(mCaps, mExtensions, mClientMajorVersion, GetDebug(attribs)); mGLState.initialize(mCaps, mExtensions, mClientMajorVersion, GetDebug(attribs));
...@@ -2292,26 +2297,30 @@ void Context::initRendererString() ...@@ -2292,26 +2297,30 @@ void Context::initRendererString()
mRendererString = MakeStaticString(rendererString.str()); mRendererString = MakeStaticString(rendererString.str());
} }
const std::string &Context::getRendererString() const const char *Context::getRendererString() const
{ {
return mRendererString; return mRendererString;
} }
void Context::initExtensionStrings() void Context::initExtensionStrings()
{ {
mExtensionStrings = mExtensions.getStrings(); for (const auto &extensionString : mExtensions.getStrings())
{
mExtensionStrings.push_back(MakeStaticString(extensionString));
}
std::ostringstream combinedStringStream; std::ostringstream combinedStringStream;
std::copy(mExtensionStrings.begin(), mExtensionStrings.end(), std::ostream_iterator<std::string>(combinedStringStream, " ")); std::copy(mExtensionStrings.begin(), mExtensionStrings.end(),
mExtensionString = combinedStringStream.str(); std::ostream_iterator<const char *>(combinedStringStream, " "));
mExtensionString = MakeStaticString(combinedStringStream.str());
} }
const std::string &Context::getExtensionString() const const char *Context::getExtensionString() const
{ {
return mExtensionString; return mExtensionString;
} }
const std::string &Context::getExtensionString(size_t idx) const const char *Context::getExtensionString(size_t idx) const
{ {
return mExtensionStrings[idx]; return mExtensionStrings[idx];
} }
...@@ -2342,7 +2351,7 @@ bool Context::hasActiveTransformFeedback(GLuint program) const ...@@ -2342,7 +2351,7 @@ bool Context::hasActiveTransformFeedback(GLuint program) const
return false; return false;
} }
void Context::initCaps() void Context::initCaps(bool webGLContext)
{ {
mCaps = mImplementation->getNativeCaps(); mCaps = mImplementation->getNativeCaps();
...@@ -2385,7 +2394,25 @@ void Context::initCaps() ...@@ -2385,7 +2394,25 @@ void Context::initCaps()
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
mExtensions.webglCompatibility = webGLContext;
for (const auto &extensionInfo : GetExtensionInfoMap())
{
// If this context is for WebGL, disable all enableable extensions
if (webGLContext && extensionInfo.second.Enableable)
{
mExtensions.*(extensionInfo.second.ExtensionsMember) = false;
}
}
// Generate texture caps
updateCaps();
}
void Context::updateCaps()
{
mCaps.compressedTextureFormats.clear(); mCaps.compressedTextureFormats.clear();
mTextureCaps.clear();
const TextureCapsMap &rendererFormats = mImplementation->getNativeTextureCaps(); const TextureCapsMap &rendererFormats = mImplementation->getNativeTextureCaps();
for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++) for (TextureCapsMap::const_iterator i = rendererFormats.begin(); i != rendererFormats.end(); i++)
...@@ -2924,6 +2951,32 @@ void Context::generateMipmap(GLenum target) ...@@ -2924,6 +2951,32 @@ void Context::generateMipmap(GLenum target)
handleError(texture->generateMipmap()); handleError(texture->generateMipmap());
} }
GLboolean Context::enableExtension(const char *name)
{
const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap();
ASSERT(extensionInfos.find(name) != extensionInfos.end());
const auto &extension = extensionInfos.at(name);
ASSERT(extension.Enableable);
if (mExtensions.*(extension.ExtensionsMember))
{
// Extension already enabled
return GL_TRUE;
}
const auto &nativeExtensions = mImplementation->getNativeExtensions();
if (!(nativeExtensions.*(extension.ExtensionsMember)))
{
// Underlying implementation does not support this valid extension
return GL_FALSE;
}
mExtensions.*(extension.ExtensionsMember) = true;
updateCaps();
initExtensionStrings();
return GL_TRUE;
}
void Context::copyTextureCHROMIUM(GLuint sourceId, void Context::copyTextureCHROMIUM(GLuint sourceId,
GLuint destId, GLuint destId,
GLint internalFormat, GLint internalFormat,
......
...@@ -481,6 +481,8 @@ class Context final : public ValidationContext ...@@ -481,6 +481,8 @@ class Context final : public ValidationContext
void generateMipmap(GLenum target); void generateMipmap(GLenum target);
GLboolean enableExtension(const char *name);
Error flush(); Error flush();
Error finish(); Error finish();
...@@ -582,10 +584,10 @@ class Context final : public ValidationContext ...@@ -582,10 +584,10 @@ class Context final : public ValidationContext
EGLenum getClientType() const; EGLenum getClientType() const;
EGLenum getRenderBuffer() const; EGLenum getRenderBuffer() const;
const std::string &getRendererString() const; const char *getRendererString() const;
const std::string &getExtensionString() const; const char *getExtensionString() const;
const std::string &getExtensionString(size_t idx) const; const char *getExtensionString(size_t idx) const;
size_t getExtensionStringCount() const; size_t getExtensionStringCount() const;
rx::ContextImpl *getImplementation() const { return mImplementation.get(); } rx::ContextImpl *getImplementation() const { return mImplementation.get(); }
...@@ -612,7 +614,8 @@ class Context final : public ValidationContext ...@@ -612,7 +614,8 @@ class Context final : public ValidationContext
void initRendererString(); void initRendererString();
void initExtensionStrings(); void initExtensionStrings();
void initCaps(); void initCaps(bool webGLContext);
void updateCaps();
LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const; LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const;
LabeledObject *getLabeledObjectFromPtr(const void *ptr) const; LabeledObject *getLabeledObjectFromPtr(const void *ptr) const;
...@@ -653,9 +656,9 @@ class Context final : public ValidationContext ...@@ -653,9 +656,9 @@ class Context final : public ValidationContext
ResourceMap<TransformFeedback> mTransformFeedbackMap; ResourceMap<TransformFeedback> mTransformFeedbackMap;
HandleAllocator mTransformFeedbackAllocator; HandleAllocator mTransformFeedbackAllocator;
std::string mRendererString; const char *mRendererString;
std::string mExtensionString; const char *mExtensionString;
std::vector<std::string> mExtensionStrings; std::vector<const char *> mExtensionStrings;
// Recorded errors // Recorded errors
typedef std::set<GLenum> ErrorSet; typedef std::set<GLenum> ErrorSet;
......
...@@ -918,6 +918,7 @@ void Display::initDisplayExtensions() ...@@ -918,6 +918,7 @@ void Display::initDisplayExtensions()
// Some extensions are always available because they are implemented in the EGL layer. // Some extensions are always available because they are implemented in the EGL layer.
mDisplayExtensions.createContext = true; mDisplayExtensions.createContext = true;
mDisplayExtensions.createContextNoError = true; mDisplayExtensions.createContextNoError = true;
mDisplayExtensions.createContextWebGLCompatibility = true;
// Force EGL_KHR_get_all_proc_addresses on. // Force EGL_KHR_get_all_proc_addresses on.
mDisplayExtensions.getAllProcAddresses = true; mDisplayExtensions.getAllProcAddresses = true;
......
...@@ -327,6 +327,21 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context ...@@ -327,6 +327,21 @@ Error ValidateCreateContext(Display *display, Config *configuration, gl::Context
} }
break; break;
case EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE:
if (!display->getExtensions().createContextWebGLCompatibility)
{
return Error(EGL_BAD_ATTRIBUTE,
"Attribute EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE requires "
"EGL_ANGLE_create_context_webgl_compatibility.");
}
if (value != EGL_TRUE && value != EGL_FALSE)
{
return Error(
EGL_BAD_ATTRIBUTE,
"EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE must be EGL_TRUE or EGL_FALSE.");
}
break;
default: default:
return Error(EGL_BAD_ATTRIBUTE); return Error(EGL_BAD_ATTRIBUTE);
} }
......
...@@ -482,7 +482,8 @@ bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment) ...@@ -482,7 +482,8 @@ bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
break; break;
case GL_DEPTH_STENCIL_ATTACHMENT: case GL_DEPTH_STENCIL_ATTACHMENT:
if (context->getClientMajorVersion() < 3) if (!context->getExtensions().webglCompatibility &&
context->getClientMajorVersion() < 3)
{ {
context->handleError(Error(GL_INVALID_ENUM)); context->handleError(Error(GL_INVALID_ENUM));
return false; return false;
......
...@@ -3433,4 +3433,24 @@ bool ValidateBufferSubData(ValidationContext *context, ...@@ -3433,4 +3433,24 @@ bool ValidateBufferSubData(ValidationContext *context,
return true; return true;
} }
bool ValidateEnableExtensionANGLE(ValidationContext *context, const GLchar *name)
{
if (!context->getExtensions().webglCompatibility)
{
context->handleError(
Error(GL_INVALID_OPERATION, "GL_ANGLE_webgl_compatibility is not available."));
return false;
}
const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap();
auto extension = extensionInfos.find(name);
if (extension == extensionInfos.end() || !extension->second.Enableable)
{
context->handleError(Error(GL_INVALID_OPERATION, "Extension %s is not enableable.", name));
return false;
}
return true;
}
} // namespace gl } // namespace gl
...@@ -317,6 +317,8 @@ bool ValidateBufferSubData(ValidationContext *context, ...@@ -317,6 +317,8 @@ bool ValidateBufferSubData(ValidationContext *context,
GLsizeiptr size, GLsizeiptr size,
const GLvoid *data); const GLvoid *data);
bool ValidateEnableExtensionANGLE(ValidationContext *context, const GLchar *name);
} // namespace gl } // namespace gl
#endif // LIBANGLE_VALIDATION_ES2_H_ #endif // LIBANGLE_VALIDATION_ES2_H_
...@@ -1472,6 +1472,9 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char * ...@@ -1472,6 +1472,9 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *
INSERT_PROC_ADDRESS(gl, CopyTextureCHROMIUM); INSERT_PROC_ADDRESS(gl, CopyTextureCHROMIUM);
INSERT_PROC_ADDRESS(gl, CopySubTextureCHROMIUM); INSERT_PROC_ADDRESS(gl, CopySubTextureCHROMIUM);
// GL_ANGLE_webgl_compatibility
INSERT_PROC_ADDRESS(gl, EnableExtensionANGLE);
// GLES3 core // GLES3 core
INSERT_PROC_ADDRESS(gl, ReadBuffer); INSERT_PROC_ADDRESS(gl, ReadBuffer);
INSERT_PROC_ADDRESS(gl, DrawRangeElements); INSERT_PROC_ADDRESS(gl, DrawRangeElements);
......
...@@ -2101,7 +2101,7 @@ const GLubyte *GL_APIENTRY GetString(GLenum name) ...@@ -2101,7 +2101,7 @@ const GLubyte *GL_APIENTRY GetString(GLenum name)
return reinterpret_cast<const GLubyte *>("Google Inc."); return reinterpret_cast<const GLubyte *>("Google Inc.");
case GL_RENDERER: case GL_RENDERER:
return reinterpret_cast<const GLubyte *>(context->getRendererString().c_str()); return reinterpret_cast<const GLubyte *>(context->getRendererString());
case GL_VERSION: case GL_VERSION:
if (context->getClientMajorVersion() == 2) if (context->getClientMajorVersion() == 2)
...@@ -2128,7 +2128,7 @@ const GLubyte *GL_APIENTRY GetString(GLenum name) ...@@ -2128,7 +2128,7 @@ const GLubyte *GL_APIENTRY GetString(GLenum name)
} }
case GL_EXTENSIONS: case GL_EXTENSIONS:
return reinterpret_cast<const GLubyte *>(context->getExtensionString().c_str()); return reinterpret_cast<const GLubyte *>(context->getExtensionString());
default: default:
context->handleError(Error(GL_INVALID_ENUM)); context->handleError(Error(GL_INVALID_ENUM));
......
...@@ -1935,4 +1935,22 @@ ANGLE_EXPORT void GL_APIENTRY CopySubTextureCHROMIUM(GLuint sourceId, ...@@ -1935,4 +1935,22 @@ ANGLE_EXPORT void GL_APIENTRY CopySubTextureCHROMIUM(GLuint sourceId,
} }
} }
GL_APICALL GLboolean GL_APIENTRY EnableExtensionANGLE(const GLchar *name)
{
EVENT("(const GLchar *name = %p)", name);
Context *context = GetValidGlobalContext();
if (context)
{
if (!context->skipValidation() && !ValidateEnableExtensionANGLE(context, name))
{
return GL_FALSE;
}
return context->enableExtension(name) ? GL_TRUE : GL_FALSE;
}
return GL_FALSE;
}
} // gl } // gl
...@@ -259,6 +259,9 @@ ANGLE_EXPORT void GL_APIENTRY CopySubTextureCHROMIUM(GLuint sourceId, ...@@ -259,6 +259,9 @@ ANGLE_EXPORT void GL_APIENTRY CopySubTextureCHROMIUM(GLuint sourceId,
GLboolean unpackPremultiplyAlpha, GLboolean unpackPremultiplyAlpha,
GLboolean unpackUnmultiplyAlpha); GLboolean unpackUnmultiplyAlpha);
// GL_ANGLE_webgl_compatibility
GL_APICALL GLboolean GL_APIENTRY EnableExtensionANGLE(const GLchar *name);
} // namespace gl } // namespace gl
#endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_ #endif // LIBGLESV2_ENTRYPOINTGLES20EXT_H_
...@@ -1441,7 +1441,7 @@ const GLubyte *GL_APIENTRY GetStringi(GLenum name, GLuint index) ...@@ -1441,7 +1441,7 @@ const GLubyte *GL_APIENTRY GetStringi(GLenum name, GLuint index)
return NULL; return NULL;
} }
return reinterpret_cast<const GLubyte*>(context->getExtensionString(index).c_str()); return reinterpret_cast<const GLubyte *>(context->getExtensionString(index));
} }
return NULL; return NULL;
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
'<(angle_path)/src/tests/gl_tests/UnpackRowLength.cpp', '<(angle_path)/src/tests/gl_tests/UnpackRowLength.cpp',
'<(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/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 2015 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.
//
// WebGLCompatibilityTest.cpp : Tests of the GL_ANGLE_webgl_compatibility extension.
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
namespace angle
{
class WebGLCompatibilityTest : public ANGLETest
{
protected:
WebGLCompatibilityTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setWebGLCompatibilityEnabled(true);
}
void SetUp() override
{
ANGLETest::SetUp();
glEnableExtensionANGLE = reinterpret_cast<PFNGLENABLEEXTENSIONANGLEPROC>(
eglGetProcAddress("glEnableExtensionANGLE"));
}
void TearDown() override { ANGLETest::TearDown(); }
PFNGLENABLEEXTENSIONANGLEPROC glEnableExtensionANGLE = nullptr;
};
// Context creation would fail if EGL_ANGLE_create_context_webgl_compatibility was not available so
// the GL extension should always be present
TEST_P(WebGLCompatibilityTest, ExtensionStringExposed)
{
EXPECT_TRUE(extensionEnabled("GL_ANGLE_webgl_compatibility"));
}
// Verify that all extension entry points are available
TEST_P(WebGLCompatibilityTest, EntryPoints)
{
if (extensionEnabled("GL_ANGLE_webgl_compatibility"))
{
EXPECT_NE(nullptr, eglGetProcAddress("glEnableExtensionANGLE"));
}
}
// WebGL 1 allows GL_DEPTH_STENCIL_ATTACHMENT as a valid binding point. Make sure it is usable,
// even in ES2 contexts.
TEST_P(WebGLCompatibilityTest, DepthStencilBindingPoint)
{
GLRenderbuffer renderbuffer;
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer.get());
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 32, 32);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.get());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
renderbuffer.get());
EXPECT_GL_NO_ERROR();
}
// Test that attempting to enable an extension that doesn't exist generates GL_INVALID_OPERATION
TEST_P(WebGLCompatibilityTest, EnableExtensionValidation)
{
EXPECT_EQ(GL_FALSE, glEnableExtensionANGLE("invalid_extension_string"));
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Test enabling the GL_OES_element_index_uint extension
TEST_P(WebGLCompatibilityTest, EnableExtensionUintIndices)
{
if (getClientMajorVersion() != 2)
{
// This test only works on ES2 where uint indices are not available by default
return;
}
EXPECT_FALSE(extensionEnabled("GL_OES_element_index_uint"));
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
GLuint data[] = {0, 1, 2, 1, 3, 2};
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
ANGLE_GL_PROGRAM(program, "void main() { gl_Position = vec4(0, 0, 0, 1); }",
"void main() { gl_FragColor = vec4(0, 1, 0, 1); }")
glUseProgram(program.get());
glDrawElements(GL_TRIANGLES, 2, GL_UNSIGNED_INT, nullptr);
EXPECT_GL_ERROR(GL_INVALID_ENUM);
if (glEnableExtensionANGLE("GL_OES_element_index_uint"))
{
EXPECT_GL_NO_ERROR();
EXPECT_TRUE(extensionEnabled("GL_OES_element_index_uint"));
glDrawElements(GL_TRIANGLES, 2, GL_UNSIGNED_INT, nullptr);
EXPECT_GL_NO_ERROR();
}
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST(WebGLCompatibilityTest,
ES2_D3D9(),
ES2_D3D11(),
ES3_D3D11(),
ES2_D3D11_FL9_3(),
ES2_OPENGL(),
ES3_OPENGL(),
ES2_OPENGLES(),
ES3_OPENGLES());
} // namespace
...@@ -643,6 +643,11 @@ void ANGLETest::setNoErrorEnabled(bool enabled) ...@@ -643,6 +643,11 @@ void ANGLETest::setNoErrorEnabled(bool enabled)
mEGLWindow->setNoErrorEnabled(enabled); mEGLWindow->setNoErrorEnabled(enabled);
} }
void ANGLETest::setWebGLCompatibilityEnabled(bool webglCompatibility)
{
mEGLWindow->setWebGLCompatibilityEnabled(webglCompatibility);
}
int ANGLETest::getClientMajorVersion() const int ANGLETest::getClientMajorVersion() const
{ {
return mEGLWindow->getClientMajorVersion(); return mEGLWindow->getClientMajorVersion();
......
...@@ -211,6 +211,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters> ...@@ -211,6 +211,7 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
void setMultisampleEnabled(bool enabled); void setMultisampleEnabled(bool enabled);
void setDebugEnabled(bool enabled); void setDebugEnabled(bool enabled);
void setNoErrorEnabled(bool enabled); void setNoErrorEnabled(bool enabled);
void setWebGLCompatibilityEnabled(bool webglCompatibility);
int getClientMajorVersion() const; int getClientMajorVersion() const;
int getClientMinorVersion() const; int getClientMinorVersion() const;
......
...@@ -110,6 +110,7 @@ EGLWindow::EGLWindow(EGLint glesMajorVersion, ...@@ -110,6 +110,7 @@ EGLWindow::EGLWindow(EGLint glesMajorVersion,
mMultisample(false), mMultisample(false),
mDebug(false), mDebug(false),
mNoError(false), mNoError(false),
mWebGLCompatibility(false),
mSwapInterval(-1) mSwapInterval(-1)
{ {
} }
...@@ -207,6 +208,14 @@ bool EGLWindow::initializeGL(OSWindow *osWindow) ...@@ -207,6 +208,14 @@ bool EGLWindow::initializeGL(OSWindow *osWindow)
return false; return false;
} }
bool hasWebGLCompatibility =
strstr(displayExtensions, "EGL_ANGLE_create_context_webgl_compatibility") != nullptr;
if (mWebGLCompatibility && !hasWebGLCompatibility)
{
destroyGL();
return false;
}
eglBindAPI(EGL_OPENGL_ES_API); eglBindAPI(EGL_OPENGL_ES_API);
if (eglGetError() != EGL_SUCCESS) if (eglGetError() != EGL_SUCCESS)
{ {
...@@ -275,6 +284,12 @@ bool EGLWindow::initializeGL(OSWindow *osWindow) ...@@ -275,6 +284,12 @@ bool EGLWindow::initializeGL(OSWindow *osWindow)
contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR); contextAttributes.push_back(EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
contextAttributes.push_back(mNoError ? EGL_TRUE : EGL_FALSE); contextAttributes.push_back(mNoError ? EGL_TRUE : EGL_FALSE);
if (hasWebGLCompatibility)
{
contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
contextAttributes.push_back(mWebGLCompatibility ? EGL_TRUE : EGL_FALSE);
}
} }
contextAttributes.push_back(EGL_NONE); contextAttributes.push_back(EGL_NONE);
......
...@@ -68,6 +68,10 @@ class ANGLE_EXPORT EGLWindow : angle::NonCopyable ...@@ -68,6 +68,10 @@ class ANGLE_EXPORT EGLWindow : angle::NonCopyable
void setMultisample(bool multisample) { mMultisample = multisample; } void setMultisample(bool multisample) { mMultisample = multisample; }
void setDebugEnabled(bool debug) { mDebug = debug; } void setDebugEnabled(bool debug) { mDebug = debug; }
void setNoErrorEnabled(bool noError) { mNoError = noError; } void setNoErrorEnabled(bool noError) { mNoError = noError; }
void setWebGLCompatibilityEnabled(bool webglCompatibility)
{
mWebGLCompatibility = webglCompatibility;
}
void setSwapInterval(EGLint swapInterval) { mSwapInterval = swapInterval; } void setSwapInterval(EGLint swapInterval) { mSwapInterval = swapInterval; }
static EGLBoolean FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config); static EGLBoolean FindEGLConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *config);
...@@ -113,6 +117,7 @@ class ANGLE_EXPORT EGLWindow : angle::NonCopyable ...@@ -113,6 +117,7 @@ class ANGLE_EXPORT EGLWindow : angle::NonCopyable
bool mMultisample; bool mMultisample;
bool mDebug; bool mDebug;
bool mNoError; bool mNoError;
bool mWebGLCompatibility;
EGLint mSwapInterval; EGLint mSwapInterval;
}; };
......
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