blob: 1546236f8b6bdb5223d0ede37ab74f0ed6f10bcf [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
* Copyright (C) 2012 Research In Motion Limited. All rights reserved.
* Copyright (C) 2014 Collabora Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#if USE(OPENGL_ES)
#include "ExtensionsGLOpenGLES.h"
#if ENABLE(WEBGL)
#include "GraphicsContextGLOpenGL.h"
#include "NotImplemented.h"
#if USE(LIBEPOXY)
#include "EpoxyEGL.h"
#else
#include <EGL/egl.h>
#endif
namespace WebCore {
ExtensionsGLOpenGLES::ExtensionsGLOpenGLES(GraphicsContextGLOpenGL* context, bool useIndexedGetString)
: ExtensionsGLOpenGLCommon(context, useIndexedGetString)
, m_contextResetStatus(GL_NO_ERROR)
, m_supportsOESvertexArrayObject(false)
, m_supportsIMGMultisampledRenderToTexture(false)
, m_supportsANGLEinstancedArrays(false)
, m_glFramebufferTexture2DMultisampleIMG(0)
, m_glRenderbufferStorageMultisampleIMG(0)
, m_glBindVertexArrayOES(0)
, m_glDeleteVertexArraysOES(0)
, m_glGenVertexArraysOES(0)
, m_glIsVertexArrayOES(0)
, m_glGetGraphicsResetStatusEXT(0)
, m_glReadnPixelsEXT(0)
, m_glGetnUniformfvEXT(0)
, m_glGetnUniformivEXT(0)
, m_glVertexAttribDivisorANGLE(nullptr)
, m_glDrawArraysInstancedANGLE(nullptr)
, m_glDrawElementsInstancedANGLE(nullptr)
{
}
ExtensionsGLOpenGLES::~ExtensionsGLOpenGLES() = default;
bool ExtensionsGLOpenGLES::isEnabled(const String& name)
{
// Return false immediately if the extension is not supported by the drivers.
bool enabled = ExtensionsGLOpenGLCommon::isEnabled(name);
if (!enabled)
return false;
// For GL_EXT_robustness, check that the context supports robust access.
if (name == "GL_EXT_robustness")
return m_context->getInteger(ExtensionsGL::CONTEXT_ROBUST_ACCESS) == GL_TRUE;
return true;
}
void ExtensionsGLOpenGLES::framebufferTexture2DMultisampleIMG(unsigned long target, unsigned long attachment, unsigned long textarget, unsigned texture, int level, unsigned long samples)
{
if (!m_context->makeContextCurrent())
return;
if (m_glFramebufferTexture2DMultisampleIMG)
m_glFramebufferTexture2DMultisampleIMG(target, attachment, textarget, texture, level, samples);
else
m_context->synthesizeGLError(GL_INVALID_OPERATION);
}
void ExtensionsGLOpenGLES::renderbufferStorageMultisampleIMG(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height)
{
if (!m_context->makeContextCurrent())
return;
if (m_glRenderbufferStorageMultisampleIMG)
m_glRenderbufferStorageMultisampleIMG(target, samples, internalformat, width, height);
else
m_context->synthesizeGLError(GL_INVALID_OPERATION);
}
void ExtensionsGLOpenGLES::renderbufferStorageMultisampleANGLE(GCGLenum target, GCGLsizei samples, GCGLenum internalformat, GCGLsizei width, GCGLsizei height)
{
if (!m_context->makeContextCurrent())
return;
if (m_glRenderbufferStorageMultisampleIMG)
renderbufferStorageMultisampleIMG(target, samples, internalformat, width, height);
else
notImplemented();
}
PlatformGLObject ExtensionsGLOpenGLES::createVertexArrayOES()
{
if (m_glGenVertexArraysOES) {
if (!m_context->makeContextCurrent())
return 0;
GLuint array = 0;
m_glGenVertexArraysOES(1, &array);
return array;
}
m_context->synthesizeGLError(GL_INVALID_OPERATION);
return 0;
}
void ExtensionsGLOpenGLES::deleteVertexArrayOES(PlatformGLObject array)
{
if (!array)
return;
if (m_glDeleteVertexArraysOES) {
if (!m_context->makeContextCurrent())
return;
m_glDeleteVertexArraysOES(1, &array);
return;
}
m_context->synthesizeGLError(GL_INVALID_OPERATION);
}
GCGLboolean ExtensionsGLOpenGLES::isVertexArrayOES(PlatformGLObject array)
{
if (!array)
return GL_FALSE;
if (m_glIsVertexArrayOES) {
if (!m_context->makeContextCurrent())
return GL_FALSE;
return m_glIsVertexArrayOES(array);
}
m_context->synthesizeGLError(GL_INVALID_OPERATION);
return false;
}
void ExtensionsGLOpenGLES::bindVertexArrayOES(PlatformGLObject array)
{
if (m_glBindVertexArrayOES) {
if (!m_context->makeContextCurrent())
return;
m_glBindVertexArrayOES(array);
} else
m_context->synthesizeGLError(GL_INVALID_OPERATION);
}
void ExtensionsGLOpenGLES::drawBuffersEXT(GCGLSpan<const GCGLenum> /* bufs */)
{
// FIXME: implement the support.
notImplemented();
}
int ExtensionsGLOpenGLES::getGraphicsResetStatusARB()
{
// FIXME: This does not call getGraphicsResetStatusARB, but instead getGraphicsResetStatusEXT.
// The return codes from the two extensions are identical and their purpose is the same, so it
// may be best to rename getGraphicsResetStatusARB() to getGraphicsResetStatus().
if (m_contextResetStatus != GL_NO_ERROR)
return m_contextResetStatus;
if (m_glGetGraphicsResetStatusEXT) {
int reasonForReset = UNKNOWN_CONTEXT_RESET_ARB;
if (m_context->makeContextCurrent())
reasonForReset = m_glGetGraphicsResetStatusEXT();
if (reasonForReset != GL_NO_ERROR)
m_contextResetStatus = reasonForReset;
return reasonForReset;
}
m_context->synthesizeGLError(GL_INVALID_OPERATION);
return false;
}
void ExtensionsGLOpenGLES::readnPixelsEXT(int x, int y, GCGLsizei width, GCGLsizei height, GCGLenum format, GCGLenum type, GCGLsizei bufSize, void *data)
{
if (m_glReadnPixelsEXT) {
if (!m_context->makeContextCurrent())
return;
// FIXME: remove the two glFlush calls when the driver bug is fixed, i.e.,
// all previous rendering calls should be done before reading pixels.
::glFlush();
// FIXME: If non-BlackBerry platforms use this, they will need to implement
// their anti-aliasing code here.
m_glReadnPixelsEXT(x, y, width, height, format, type, bufSize, data);
return;
}
m_context->synthesizeGLError(GL_INVALID_OPERATION);
}
void ExtensionsGLOpenGLES::getnUniformfvEXT(GCGLuint program, int location, GCGLsizei bufSize, float *params)
{
if (m_glGetnUniformfvEXT) {
if (!m_context->makeContextCurrent())
return;
m_glGetnUniformfvEXT(program, location, bufSize, params);
return;
}
m_context->synthesizeGLError(GL_INVALID_OPERATION);
}
void ExtensionsGLOpenGLES::getnUniformivEXT(GCGLuint program, int location, GCGLsizei bufSize, int *params)
{
if (m_glGetnUniformivEXT) {
if (!m_context->makeContextCurrent())
return;
m_glGetnUniformivEXT(program, location, bufSize, params);
return;
}
m_context->synthesizeGLError(GL_INVALID_OPERATION);
}
void ExtensionsGLOpenGLES::drawArraysInstancedANGLE(GCGLenum mode, GCGLint first, GCGLsizei count, GCGLsizei primcount)
{
if (!m_glDrawArraysInstancedANGLE) {
m_context->synthesizeGLError(GL_INVALID_OPERATION);
return;
}
if (!m_context->makeContextCurrent())
return;
m_glDrawArraysInstancedANGLE(mode, first, count, primcount);
}
void ExtensionsGLOpenGLES::drawElementsInstancedANGLE(GCGLenum mode, GCGLsizei count, GCGLenum type, GCGLvoidptr offset, GCGLsizei primcount)
{
if (!m_glDrawElementsInstancedANGLE) {
m_context->synthesizeGLError(GL_INVALID_OPERATION);
return;
}
if (!m_context->makeContextCurrent())
return;
m_glDrawElementsInstancedANGLE(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)), primcount);
}
void ExtensionsGLOpenGLES::vertexAttribDivisorANGLE(GCGLuint index, GCGLuint divisor)
{
if (!m_glVertexAttribDivisorANGLE) {
m_context->synthesizeGLError(GL_INVALID_OPERATION);
return;
}
if (!m_context->makeContextCurrent())
return;
m_glVertexAttribDivisorANGLE(index, divisor);
}
bool ExtensionsGLOpenGLES::supportsExtension(const String& name)
{
if (name == "GL_ANGLE_instanced_arrays") {
auto majorVersion = []() {
GLint version = 0;
::glGetIntegerv(GL_MAJOR_VERSION, &version);
return version;
};
if (m_availableExtensions.contains(name)) {
m_glVertexAttribDivisorANGLE = reinterpret_cast<PFNGLVERTEXATTRIBDIVISORANGLEPROC>(eglGetProcAddress("glVertexAttribDivisorANGLE"));
m_glDrawArraysInstancedANGLE = reinterpret_cast<PFNGLDRAWARRAYSINSTANCEDANGLEPROC >(eglGetProcAddress("glDrawArraysInstancedANGLE"));
m_glDrawElementsInstancedANGLE = reinterpret_cast<PFNGLDRAWELEMENTSINSTANCEDANGLEPROC >(eglGetProcAddress("glDrawElementsInstancedANGLE"));
m_supportsANGLEinstancedArrays = true;
} else if (majorVersion() >= 3 || (m_availableExtensions.contains("GL_EXT_instanced_arrays") && m_availableExtensions.contains("GL_EXT_draw_instanced"))) {
m_glVertexAttribDivisorANGLE = ::glVertexAttribDivisor;
m_glDrawArraysInstancedANGLE = ::glDrawArraysInstanced;
m_glDrawElementsInstancedANGLE = ::glDrawElementsInstanced;
m_supportsANGLEinstancedArrays = true;
}
return m_supportsANGLEinstancedArrays;
}
if (m_availableExtensions.contains(name)) {
if (!m_supportsOESvertexArrayObject && name == "GL_OES_vertex_array_object") {
m_glBindVertexArrayOES = reinterpret_cast<PFNGLBINDVERTEXARRAYOESPROC>(eglGetProcAddress("glBindVertexArrayOES"));
m_glGenVertexArraysOES = reinterpret_cast<PFNGLGENVERTEXARRAYSOESPROC>(eglGetProcAddress("glGenVertexArraysOES"));
m_glDeleteVertexArraysOES = reinterpret_cast<PFNGLDELETEVERTEXARRAYSOESPROC>(eglGetProcAddress("glDeleteVertexArraysOES"));
m_glIsVertexArrayOES = reinterpret_cast<PFNGLISVERTEXARRAYOESPROC>(eglGetProcAddress("glIsVertexArrayOES"));
m_supportsOESvertexArrayObject = true;
} else if (!m_supportsIMGMultisampledRenderToTexture && name == "GL_IMG_multisampled_render_to_texture") {
m_glFramebufferTexture2DMultisampleIMG = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC>(eglGetProcAddress("glFramebufferTexture2DMultisampleIMG"));
m_glRenderbufferStorageMultisampleIMG = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMGPROC>(eglGetProcAddress("glRenderbufferStorageMultisampleIMG"));
m_supportsIMGMultisampledRenderToTexture = true;
} else if (!m_glGetGraphicsResetStatusEXT && name == "GL_EXT_robustness") {
m_glGetGraphicsResetStatusEXT = reinterpret_cast<PFNGLGETGRAPHICSRESETSTATUSEXTPROC>(eglGetProcAddress("glGetGraphicsResetStatusEXT"));
m_glReadnPixelsEXT = reinterpret_cast<PFNGLREADNPIXELSEXTPROC>(eglGetProcAddress("glReadnPixelsEXT"));
m_glGetnUniformfvEXT = reinterpret_cast<PFNGLGETNUNIFORMFVEXTPROC>(eglGetProcAddress("glGetnUniformfvEXT"));
m_glGetnUniformivEXT = reinterpret_cast<PFNGLGETNUNIFORMIVEXTPROC>(eglGetProcAddress("glGetnUniformivEXT"));
} else if (name == "GL_EXT_draw_buffers") {
// FIXME: implement the support.
return false;
}
return true;
}
return false;
}
String ExtensionsGLOpenGLES::getExtensions()
{
return String(reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS)));
}
} // namespace WebCore
#endif // ENABLE(WEBGL)
#endif // USE(OPENGL_ES)