blob: 303229deb90c3651f8e80038c1c206e15dfb3020 [file] [log] [blame]
/*
* Copyright (C) 2010, 2014 Apple Inc. All rights reserved.
* Copyright (C) 2011 Google Inc. All rights reserved.
* Copyright (C) 2012 ChangSeok Oh <shivamidow@gmail.com>
* Copyright (C) 2012 Research In Motion Limited. 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 INC. ``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 INC. OR
* 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"
#include "GraphicsContextGLOpenGL.h"
#if ENABLE(WEBGL) && !USE(ANGLE)
#include "ANGLEWebKitBridge.h"
#include "GLContext.h"
#include "GraphicsContext.h"
#include "ImageBuffer.h"
#include "IntRect.h"
#include "IntSize.h"
#include "Logging.h"
#include "PixelBuffer.h"
#include "TemporaryOpenGLSetting.h"
#include "WebGLRenderingContextBase.h"
#include <JavaScriptCore/RegularExpression.h>
#include <cstring>
#include <wtf/HexNumber.h>
#include <wtf/MainThread.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/UniqueArray.h>
#include <wtf/Vector.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>
#if USE(OPENGL_ES)
#include "ExtensionsGLOpenGLES.h"
#else
#include "ExtensionsGLOpenGL.h"
#endif
#if USE(LIBEPOXY)
#include "EpoxyShims.h"
#elif USE(OPENGL_ES)
#include "OpenGLESShims.h"
#elif PLATFORM(GTK) || PLATFORM(WIN)
#include "OpenGLShims.h"
#endif
#if USE(NICOSIA)
#include "NicosiaGCGLLayer.h"
#endif
namespace WebCore {
static ThreadSpecific<ShaderNameHash*>& getCurrentNameHashMapForShader()
{
static std::once_flag onceFlag;
static ThreadSpecific<ShaderNameHash*>* sharedNameHash;
std::call_once(onceFlag, [] {
sharedNameHash = new ThreadSpecific<ShaderNameHash*>;
});
return *sharedNameHash;
}
static void setCurrentNameHashMapForShader(ShaderNameHash* shaderNameHash)
{
*getCurrentNameHashMapForShader() = shaderNameHash;
}
// Hash function used by the ANGLE translator/compiler to do
// symbol name mangling. Since this is a static method, before
// calling compileShader we set currentNameHashMapForShader
// to point to the map kept by the current instance of GraphicsContextGLOpenGL.
static uint64_t nameHashForShader(const char* name, size_t length)
{
if (!length)
return 0;
CString nameAsCString = CString(name);
// Look up name in our local map.
ShaderNameHash*& currentNameHashMapForShader = *getCurrentNameHashMapForShader();
ShaderNameHash::iterator findResult = currentNameHashMapForShader->find(nameAsCString);
if (findResult != currentNameHashMapForShader->end())
return findResult->value;
unsigned hashValue = nameAsCString.hash();
// Convert the 32-bit hash from CString::hash into a 64-bit result
// by shifting then adding the size of our table. Overflow would
// only be a problem if we're already hashing to the same value (and
// we're hoping that over the lifetime of the context we
// don't have that many symbols).
uint64_t result = hashValue;
result = (result << 32) + (currentNameHashMapForShader->size() + 1);
currentNameHashMapForShader->set(nameAsCString, result);
return result;
}
GraphicsContextGLOpenGL::GraphicsContextGLOpenGL(GraphicsContextGLAttributes attributes)
: GraphicsContextGL(attributes)
{
#if USE(NICOSIA)
m_nicosiaLayer = makeUnique<Nicosia::GCGLLayer>(*this);
#else
m_texmapLayer = makeUnique<TextureMapperGCGLPlatformLayer>(*this);
#endif
bool success = makeContextCurrent();
ASSERT_UNUSED(success, success);
validateAttributes();
attributes = contextAttributes(); // They may have changed during validation.
// Create a texture to render into.
::glGenTextures(1, &m_texture);
::glBindTexture(GL_TEXTURE_2D, m_texture);
::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
::glBindTexture(GL_TEXTURE_2D, 0);
// Create an FBO.
::glGenFramebuffers(1, &m_fbo);
::glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
#if USE(COORDINATED_GRAPHICS)
::glGenTextures(1, &m_compositorTexture);
::glBindTexture(GL_TEXTURE_2D, m_compositorTexture);
::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
::glGenTextures(1, &m_intermediateTexture);
::glBindTexture(GL_TEXTURE_2D, m_intermediateTexture);
::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
::glBindTexture(GL_TEXTURE_2D, 0);
#endif
// Create a multisample FBO.
ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO);
if (attributes.antialias) {
::glGenFramebuffers(1, &m_multisampleFBO);
::glBindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
m_state.boundDrawFBO = m_state.boundReadFBO = m_multisampleFBO;
::glGenRenderbuffers(1, &m_multisampleColorBuffer);
if (attributes.stencil || attributes.depth)
::glGenRenderbuffers(1, &m_multisampleDepthStencilBuffer);
} else {
// Bind canvas FBO.
glBindFramebuffer(GraphicsContextGLOpenGL::FRAMEBUFFER, m_fbo);
m_state.boundDrawFBO = m_state.boundReadFBO = m_fbo;
#if USE(OPENGL_ES)
if (attributes.depth)
glGenRenderbuffers(1, &m_depthBuffer);
if (attributes.stencil)
glGenRenderbuffers(1, &m_stencilBuffer);
#endif
if (attributes.stencil || attributes.depth)
glGenRenderbuffers(1, &m_depthStencilBuffer);
}
#if !USE(OPENGL_ES)
::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
if (GLContext::current()->version() >= 320) {
m_usingCoreProfile = true;
// From version 3.2 on we use the OpenGL Core profile, so request that ouput to the shader compiler.
// OpenGL version 3.2 uses GLSL version 1.50.
m_compiler = ANGLEWebKitBridge(SH_GLSL_150_CORE_OUTPUT);
// From version 3.2 on we use the OpenGL Core profile, and we need a VAO for rendering.
// A VAO could be created and bound by each component using GL rendering (TextureMapper, WebGL, etc). This is
// a simpler solution: the first GraphicsContextGLOpenGL created on a GLContext will create and bind a VAO for that context.
GCGLint currentVAO = getInteger(GraphicsContextGLOpenGL::VERTEX_ARRAY_BINDING);
if (!currentVAO) {
m_vao = createVertexArray();
bindVertexArray(m_vao);
}
} else {
// For lower versions request the compatibility output to the shader compiler.
m_compiler = ANGLEWebKitBridge(SH_GLSL_COMPATIBILITY_OUTPUT);
// GL_POINT_SPRITE is needed in lower versions.
::glEnable(GL_POINT_SPRITE);
}
#else
// Adjust the shader specification depending on whether GLES3 (i.e. WebGL2 support) was requested.
#if ENABLE(WEBGL2)
m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT, (attributes.webGLVersion == GraphicsContextGLWebGLVersion::WebGL2) ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC);
#else
m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT, SH_WEBGL_SPEC);
#endif
#endif
// ANGLE initialization.
ShBuiltInResources ANGLEResources;
sh::InitBuiltInResources(&ANGLEResources);
ANGLEResources.MaxVertexAttribs = getInteger(GraphicsContextGLOpenGL::MAX_VERTEX_ATTRIBS);
ANGLEResources.MaxVertexUniformVectors = getInteger(GraphicsContextGLOpenGL::MAX_VERTEX_UNIFORM_VECTORS);
ANGLEResources.MaxVaryingVectors = getInteger(GraphicsContextGLOpenGL::MAX_VARYING_VECTORS);
ANGLEResources.MaxVertexTextureImageUnits = getInteger(GraphicsContextGLOpenGL::MAX_VERTEX_TEXTURE_IMAGE_UNITS);
ANGLEResources.MaxCombinedTextureImageUnits = getInteger(GraphicsContextGLOpenGL::MAX_COMBINED_TEXTURE_IMAGE_UNITS);
ANGLEResources.MaxTextureImageUnits = getInteger(GraphicsContextGLOpenGL::MAX_TEXTURE_IMAGE_UNITS);
ANGLEResources.MaxFragmentUniformVectors = getInteger(GraphicsContextGLOpenGL::MAX_FRAGMENT_UNIFORM_VECTORS);
// Always set to 1 for OpenGL ES.
ANGLEResources.MaxDrawBuffers = 1;
GCGLint range[2] { };
GCGLint precision = 0;
getShaderPrecisionFormat(GraphicsContextGLOpenGL::FRAGMENT_SHADER, GraphicsContextGLOpenGL::HIGH_FLOAT, range, &precision);
ANGLEResources.FragmentPrecisionHigh = (range[0] || range[1] || precision);
m_compiler.setResources(ANGLEResources);
::glClearColor(0, 0, 0, 0);
}
GraphicsContextGLOpenGL::~GraphicsContextGLOpenGL()
{
bool success = makeContextCurrent();
ASSERT_UNUSED(success, success);
if (m_texture)
::glDeleteTextures(1, &m_texture);
#if USE(COORDINATED_GRAPHICS)
if (m_compositorTexture)
::glDeleteTextures(1, &m_compositorTexture);
#endif
auto attributes = contextAttributes();
if (attributes.antialias) {
::glDeleteRenderbuffers(1, &m_multisampleColorBuffer);
if (attributes.stencil || attributes.depth)
::glDeleteRenderbuffers(1, &m_multisampleDepthStencilBuffer);
::glDeleteFramebuffers(1, &m_multisampleFBO);
} else if (attributes.stencil || attributes.depth) {
#if USE(OPENGL_ES)
if (m_depthBuffer)
glDeleteRenderbuffers(1, &m_depthBuffer);
if (m_stencilBuffer)
glDeleteRenderbuffers(1, &m_stencilBuffer);
#endif
if (m_depthStencilBuffer)
::glDeleteRenderbuffers(1, &m_depthStencilBuffer);
}
::glDeleteFramebuffers(1, &m_fbo);
#if USE(COORDINATED_GRAPHICS)
::glDeleteTextures(1, &m_intermediateTexture);
#endif
#if USE(CAIRO)
if (m_vao)
deleteVertexArray(m_vao);
#endif
}
bool GraphicsContextGLOpenGL::initialize()
{
return platformInitialize();
}
bool GraphicsContextGLOpenGL::makeContextCurrent()
{
#if USE(NICOSIA)
return m_nicosiaLayer->makeContextCurrent();
#else
return m_texmapLayer->makeContextCurrent();
#endif
}
void GraphicsContextGLOpenGL::checkGPUStatus()
{
}
bool GraphicsContextGLOpenGL::isGLES2Compliant() const
{
#if USE(OPENGL_ES)
return true;
#else
return false;
#endif
}
#if PLATFORM(GTK) && USE(OPENGL_ES)
ExtensionsGLOpenGLES& GraphicsContextGLOpenGL::getExtensions()
{
// glGetStringi is not available on GLES2.
if (!m_extensions)
m_extensions = makeUnique<ExtensionsGLOpenGLES>(this, false);
return *m_extensions;
}
#elif PLATFORM(GTK)
ExtensionsGLOpenGL& GraphicsContextGLOpenGL::getExtensions()
{
// From OpenGL 3.2 on we use the Core profile, and there we must use glGetStringi.
if (!m_extensions)
m_extensions = makeUnique<ExtensionsGLOpenGL>(this, GLContext::current()->version() >= 320);
return *m_extensions;
}
#endif
void GraphicsContextGLOpenGL::setContextVisibility(bool)
{
}
void GraphicsContextGLOpenGL::simulateEventForTesting(SimulatedEventForTesting event)
{
if (event == SimulatedEventForTesting::GPUStatusFailure)
m_failNextStatusCheck = true;
}
void GraphicsContextGLOpenGL::prepareForDisplay()
{
}
RefPtr<PixelBuffer> GraphicsContextGLOpenGL::readCompositedResults()
{
return readRenderingResults();
}
void GraphicsContextGLOpenGL::validateDepthStencil(ASCIILiteral packedDepthStencilExtension)
{
auto attrs = contextAttributes();
if (attrs.stencil) {
String packedDepthStencilExtensionString { packedDepthStencilExtension };
if (supportsExtension(packedDepthStencilExtensionString)) {
ensureExtensionEnabled(packedDepthStencilExtensionString);
// Force depth if stencil is true.
attrs.depth = true;
} else
attrs.stencil = false;
setContextAttributes(attrs);
}
if (attrs.antialias && !m_isForWebGL2) {
if (!supportsExtension("GL_ANGLE_framebuffer_multisample"_s)) {
attrs.antialias = false;
setContextAttributes(attrs);
} else
ensureExtensionEnabled("GL_ANGLE_framebuffer_multisample"_s);
}
}
void GraphicsContextGLOpenGL::prepareTexture()
{
if (m_layerComposited)
return;
if (!makeContextCurrent())
return;
#if !USE(COORDINATED_GRAPHICS)
TemporaryOpenGLSetting scopedScissor(GL_SCISSOR_TEST, GL_FALSE);
TemporaryOpenGLSetting scopedDither(GL_DITHER, GL_FALSE);
#endif
if (contextAttributes().antialias)
resolveMultisamplingIfNecessary();
#if USE(COORDINATED_GRAPHICS)
std::swap(m_texture, m_compositorTexture);
std::swap(m_texture, m_intermediateTexture);
::glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0);
glFlush();
ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO);
if (m_state.boundDrawFBO != m_fbo)
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_state.boundDrawFBO);
else
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_fbo);
return;
#endif
::glActiveTexture(GL_TEXTURE0);
::glBindTexture(GL_TEXTURE_2D, m_state.boundTarget(GL_TEXTURE0) == GL_TEXTURE_2D ? m_state.boundTexture(GL_TEXTURE0) : 0);
::glActiveTexture(m_state.activeTextureUnit);
ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO);
if (m_state.boundDrawFBO != m_fbo)
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_state.boundDrawFBO);
::glFlush();
}
RefPtr<PixelBuffer> GraphicsContextGLOpenGL::readRenderingResults()
{
bool mustRestoreFBO = false;
if (contextAttributes().antialias) {
resolveMultisamplingIfNecessary();
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_fbo);
mustRestoreFBO = true;
} else {
ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO);
if (m_state.boundDrawFBO != m_fbo) {
mustRestoreFBO = true;
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_fbo);
}
}
auto result = readPixelsForPaintResults();
if (mustRestoreFBO)
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_state.boundDrawFBO);
return result;
}
void GraphicsContextGLOpenGL::reshape(int width, int height)
{
if (width == m_currentWidth && height == m_currentHeight)
return;
ASSERT(width >= 0 && height >= 0);
if (width < 0 || height < 0)
return;
if (!makeContextCurrent())
return;
markContextChanged();
m_currentWidth = width;
m_currentHeight = height;
validateAttributes();
TemporaryOpenGLSetting scopedScissor(GL_SCISSOR_TEST, GL_FALSE);
TemporaryOpenGLSetting scopedDither(GL_DITHER, GL_FALSE);
bool mustRestoreFBO = reshapeFBOs(IntSize(width, height));
// Initialize renderbuffers to 0.
GLfloat clearColor[] = { 0, 0, 0, 0 }, clearDepth = 0;
GLint clearStencil = 0;
GLboolean colorMask[] = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE }, depthMask = GL_TRUE;
GLuint stencilMask = 0xffffffff, stencilMaskBack = 0xffffffff;
GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
::glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
::glClearColor(0, 0, 0, 0);
::glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
::glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
auto attrs = contextAttributes();
if (attrs.depth) {
::glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth);
GraphicsContextGLOpenGL::clearDepth(1);
::glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask);
::glDepthMask(GL_TRUE);
clearMask |= GL_DEPTH_BUFFER_BIT;
}
if (attrs.stencil) {
::glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &clearStencil);
::glClearStencil(0);
::glGetIntegerv(GL_STENCIL_WRITEMASK, reinterpret_cast<GLint*>(&stencilMask));
::glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, reinterpret_cast<GLint*>(&stencilMaskBack));
::glStencilMaskSeparate(GL_FRONT, 0xffffffff);
::glStencilMaskSeparate(GL_BACK, 0xffffffff);
clearMask |= GL_STENCIL_BUFFER_BIT;
}
::glClear(clearMask);
::glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
::glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
if (attrs.depth) {
GraphicsContextGLOpenGL::clearDepth(clearDepth);
::glDepthMask(depthMask);
}
if (attrs.stencil) {
::glClearStencil(clearStencil);
::glStencilMaskSeparate(GL_FRONT, stencilMask);
::glStencilMaskSeparate(GL_BACK, stencilMaskBack);
}
if (mustRestoreFBO)
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_state.boundDrawFBO);
auto error = ::glGetError();
if (error != GL_NO_ERROR) {
RELEASE_LOG(WebGL, "Fatal: OpenGL error during GraphicsContextGL buffer initialization (%d).", error);
forceContextLost();
return;
}
::glFlush();
}
bool GraphicsContextGLOpenGL::checkVaryingsPacking(PlatformGLObject vertexShader, PlatformGLObject fragmentShader) const
{
ASSERT(m_shaderSourceMap.contains(vertexShader));
ASSERT(m_shaderSourceMap.contains(fragmentShader));
const auto& vertexEntry = m_shaderSourceMap.find(vertexShader)->value;
const auto& fragmentEntry = m_shaderSourceMap.find(fragmentShader)->value;
HashMap<String, sh::ShaderVariable> combinedVaryings;
for (const auto& vertexSymbol : vertexEntry.varyingMap) {
const String& symbolName = vertexSymbol.key;
// The varying map includes variables for each index of an array variable.
// We only want a single variable to represent the array.
if (symbolName.endsWith(']'))
continue;
// Don't count built in varyings.
if (symbolName == "gl_FragCoord"_s || symbolName == "gl_FrontFacing"_s || symbolName == "gl_PointCoord"_s)
continue;
const auto& fragmentSymbol = fragmentEntry.varyingMap.find(symbolName);
if (fragmentSymbol != fragmentEntry.varyingMap.end())
combinedVaryings.add(symbolName, fragmentSymbol->value);
}
size_t numVaryings = combinedVaryings.size();
if (!numVaryings)
return true;
std::vector<sh::ShaderVariable> variables;
variables.reserve(combinedVaryings.size());
for (const auto& varyingSymbol : combinedVaryings.values())
variables.push_back(varyingSymbol);
GCGLint maxVaryingVectors = 0;
#if USE(OPENGL_ES)
::glGetIntegerv(MAX_VARYING_VECTORS, &maxVaryingVectors);
#else
if (m_isForWebGL2)
::glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryingVectors);
else {
GCGLint maxVaryingFloats = 0;
::glGetIntegerv(GL_MAX_VARYING_FLOATS, &maxVaryingFloats);
maxVaryingVectors = maxVaryingFloats / 4;
}
#endif
return sh::CheckVariablesWithinPackingLimits(maxVaryingVectors, variables);
}
bool GraphicsContextGLOpenGL::precisionsMatch(PlatformGLObject vertexShader, PlatformGLObject fragmentShader) const
{
ASSERT(m_shaderSourceMap.contains(vertexShader));
ASSERT(m_shaderSourceMap.contains(fragmentShader));
const auto& vertexEntry = m_shaderSourceMap.find(vertexShader)->value;
const auto& fragmentEntry = m_shaderSourceMap.find(fragmentShader)->value;
HashMap<String, sh::GLenum> vertexSymbolPrecisionMap;
for (const auto& entry : vertexEntry.uniformMap) {
const std::string& mappedName = entry.value.get().mappedName;
vertexSymbolPrecisionMap.add(String(mappedName.c_str(), mappedName.length()), entry.value.get().precision);
}
for (const auto& entry : fragmentEntry.uniformMap) {
const std::string& mappedName = entry.value.get().mappedName;
const auto& vertexSymbol = vertexSymbolPrecisionMap.find(String(mappedName.c_str(), mappedName.length()));
if (vertexSymbol != vertexSymbolPrecisionMap.end() && vertexSymbol->value != entry.value.get().precision)
return false;
}
return true;
}
void GraphicsContextGLOpenGL::activeTexture(GCGLenum texture)
{
if (!makeContextCurrent())
return;
m_state.activeTextureUnit = texture;
::glActiveTexture(texture);
}
void GraphicsContextGLOpenGL::attachShader(PlatformGLObject program, PlatformGLObject shader)
{
ASSERT(program);
ASSERT(shader);
if (!makeContextCurrent())
return;
m_shaderProgramSymbolCountMap.remove(program);
::glAttachShader(program, shader);
}
void GraphicsContextGLOpenGL::bindAttribLocation(PlatformGLObject program, GCGLuint index, const String& name)
{
ASSERT(program);
if (!makeContextCurrent())
return;
String mappedName = mappedSymbolName(program, SHADER_SYMBOL_TYPE_ATTRIBUTE, name);
LOG(WebGL, "::bindAttribLocation is mapping %s to %s", name.utf8().data(), mappedName.utf8().data());
::glBindAttribLocation(program, index, mappedName.utf8().data());
}
void GraphicsContextGLOpenGL::bindBuffer(GCGLenum target, PlatformGLObject buffer)
{
if (!makeContextCurrent())
return;
::glBindBuffer(target, buffer);
}
void GraphicsContextGLOpenGL::bindFramebuffer(GCGLenum target, PlatformGLObject buffer)
{
if (!makeContextCurrent())
return;
GLuint fbo;
if (buffer)
fbo = buffer;
else
fbo = (contextAttributes().antialias ? m_multisampleFBO : m_fbo);
ASSERT(target == GL_FRAMEBUFFER);
ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO);
if (fbo != m_state.boundDrawFBO) {
::glBindFramebufferEXT(target, fbo);
m_state.boundDrawFBO = m_state.boundReadFBO = fbo;
}
}
void GraphicsContextGLOpenGL::bindRenderbuffer(GCGLenum target, PlatformGLObject renderbuffer)
{
if (!makeContextCurrent())
return;
::glBindRenderbufferEXT(target, renderbuffer);
}
void GraphicsContextGLOpenGL::bindTexture(GCGLenum target, PlatformGLObject texture)
{
if (!makeContextCurrent())
return;
m_state.setBoundTexture(m_state.activeTextureUnit, texture, target);
::glBindTexture(target, texture);
}
void GraphicsContextGLOpenGL::blendColor(GCGLclampf red, GCGLclampf green, GCGLclampf blue, GCGLclampf alpha)
{
if (!makeContextCurrent())
return;
::glBlendColor(red, green, blue, alpha);
}
void GraphicsContextGLOpenGL::blendEquation(GCGLenum mode)
{
if (!makeContextCurrent())
return;
::glBlendEquation(mode);
}
void GraphicsContextGLOpenGL::blendEquationSeparate(GCGLenum modeRGB, GCGLenum modeAlpha)
{
if (!makeContextCurrent())
return;
::glBlendEquationSeparate(modeRGB, modeAlpha);
}
void GraphicsContextGLOpenGL::blendFunc(GCGLenum sfactor, GCGLenum dfactor)
{
if (!makeContextCurrent())
return;
::glBlendFunc(sfactor, dfactor);
}
void GraphicsContextGLOpenGL::blendFuncSeparate(GCGLenum srcRGB, GCGLenum dstRGB, GCGLenum srcAlpha, GCGLenum dstAlpha)
{
if (!makeContextCurrent())
return;
::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
}
void GraphicsContextGLOpenGL::bufferData(GCGLenum target, GCGLsizeiptr size, GCGLenum usage)
{
if (!makeContextCurrent())
return;
::glBufferData(target, size, 0, usage);
}
void GraphicsContextGLOpenGL::bufferData(GCGLenum target, GCGLSpan<const void> data, GCGLenum usage)
{
if (!makeContextCurrent())
return;
::glBufferData(target, data.bufSize, data.data, usage);
}
void GraphicsContextGLOpenGL::bufferSubData(GCGLenum target, GCGLintptr offset, GCGLSpan<const GCGLvoid> data)
{
if (!makeContextCurrent())
return;
::glBufferSubData(target, offset, data.bufSize, data.data);
}
GCGLenum GraphicsContextGLOpenGL::checkFramebufferStatus(GCGLenum target)
{
if (!makeContextCurrent())
return GL_INVALID_OPERATION;
return ::glCheckFramebufferStatusEXT(target);
}
void GraphicsContextGLOpenGL::clearColor(GCGLclampf r, GCGLclampf g, GCGLclampf b, GCGLclampf a)
{
if (!makeContextCurrent())
return;
::glClearColor(r, g, b, a);
}
void GraphicsContextGLOpenGL::clear(GCGLbitfield mask)
{
if (!makeContextCurrent())
return;
::glClear(mask);
checkGPUStatus();
}
void GraphicsContextGLOpenGL::clearStencil(GCGLint s)
{
if (!makeContextCurrent())
return;
::glClearStencil(s);
}
void GraphicsContextGLOpenGL::colorMask(GCGLboolean red, GCGLboolean green, GCGLboolean blue, GCGLboolean alpha)
{
if (!makeContextCurrent())
return;
::glColorMask(red, green, blue, alpha);
}
void GraphicsContextGLOpenGL::compileShader(PlatformGLObject shader)
{
ASSERT(shader);
if (!makeContextCurrent())
return;
// Turn on name mapping. Due to the way ANGLE name hashing works, we
// point a global hashmap to the map owned by this context.
ShBuiltInResources ANGLEResources = m_compiler.getResources();
ShHashFunction64 previousHashFunction = ANGLEResources.HashFunction;
ANGLEResources.HashFunction = nameHashForShader;
if (!nameHashMapForShaders)
nameHashMapForShaders = makeUnique<ShaderNameHash>();
setCurrentNameHashMapForShader(nameHashMapForShaders.get());
m_compiler.setResources(ANGLEResources);
String translatedShaderSource = m_extensions->getTranslatedShaderSourceANGLE(shader);
ANGLEResources.HashFunction = previousHashFunction;
m_compiler.setResources(ANGLEResources);
setCurrentNameHashMapForShader(nullptr);
if (!translatedShaderSource.length())
return;
const CString& translatedShaderCString = translatedShaderSource.utf8();
const char* translatedShaderPtr = translatedShaderCString.data();
int translatedShaderLength = translatedShaderCString.length();
LOG(WebGL, "--- begin original shader source ---\n%s\n--- end original shader source ---\n", getShaderSource(shader).utf8().data());
LOG(WebGL, "--- begin translated shader source ---\n%s\n--- end translated shader source ---", translatedShaderPtr);
::glShaderSource(shader, 1, &translatedShaderPtr, &translatedShaderLength);
::glCompileShader(shader);
int compileStatus;
::glGetShaderiv(shader, COMPILE_STATUS, &compileStatus);
ShaderSourceMap::iterator result = m_shaderSourceMap.find(shader);
ShaderSourceEntry& entry = result->value;
// Populate the shader log
GLint length = 0;
::glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (length) {
GLsizei size = 0;
Vector<GLchar> info(length);
::glGetShaderInfoLog(shader, length, &size, info.data());
PlatformGLObject shaders[2] = { shader, 0 };
entry.log = getUnmangledInfoLog(shaders, 1, String(info.data(), size));
}
if (compileStatus != GL_TRUE) {
entry.isValid = false;
LOG(WebGL, "Error: shader translator produced a shader that OpenGL would not compile.");
}
}
void GraphicsContextGLOpenGL::compileShaderDirect(PlatformGLObject shader)
{
ASSERT(shader);
if (!makeContextCurrent())
return;
HashMap<PlatformGLObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader);
if (result == m_shaderSourceMap.end())
return;
ShaderSourceEntry& entry = result->value;
const CString& shaderSourceCString = entry.source.utf8();
const char* shaderSourcePtr = shaderSourceCString.data();
int shaderSourceLength = shaderSourceCString.length();
LOG(WebGL, "--- begin direct shader source ---\n%s\n--- end direct shader source ---\n", shaderSourcePtr);
::glShaderSource(shader, 1, &shaderSourcePtr, &shaderSourceLength);
::glCompileShader(shader);
int compileStatus;
::glGetShaderiv(shader, COMPILE_STATUS, &compileStatus);
if (compileStatus == GL_TRUE) {
entry.isValid = true;
LOG(WebGL, "Direct compilation of shader succeeded.");
} else {
entry.isValid = false;
LOG(WebGL, "Error: direct compilation of shader failed.");
}
}
void GraphicsContextGLOpenGL::copyTexImage2D(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height, GCGLint border)
{
if (!makeContextCurrent())
return;
auto attrs = contextAttributes();
ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO);
if (attrs.antialias && m_state.boundDrawFBO == m_multisampleFBO) {
resolveMultisamplingIfNecessary(IntRect(x, y, width, height));
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_fbo);
}
::glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
if (attrs.antialias && m_state.boundDrawFBO == m_multisampleFBO)
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_multisampleFBO);
}
void GraphicsContextGLOpenGL::copyTexSubImage2D(GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset, GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height)
{
if (!makeContextCurrent())
return;
auto attrs = contextAttributes();
ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO);
if (attrs.antialias && m_state.boundDrawFBO == m_multisampleFBO) {
resolveMultisamplingIfNecessary(IntRect(x, y, width, height));
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_fbo);
}
::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
if (attrs.antialias && m_state.boundDrawFBO == m_multisampleFBO)
::glBindFramebufferEXT(GraphicsContextGL::FRAMEBUFFER, m_multisampleFBO);
}
void GraphicsContextGLOpenGL::cullFace(GCGLenum mode)
{
if (!makeContextCurrent())
return;
::glCullFace(mode);
}
void GraphicsContextGLOpenGL::depthFunc(GCGLenum func)
{
if (!makeContextCurrent())
return;
::glDepthFunc(func);
}
void GraphicsContextGLOpenGL::depthMask(GCGLboolean flag)
{
if (!makeContextCurrent())
return;
::glDepthMask(flag);
}
void GraphicsContextGLOpenGL::detachShader(PlatformGLObject program, PlatformGLObject shader)
{
ASSERT(program);
ASSERT(shader);
if (!makeContextCurrent())
return;
m_shaderProgramSymbolCountMap.remove(program);
::glDetachShader(program, shader);
}
void GraphicsContextGLOpenGL::disable(GCGLenum cap)
{
if (!makeContextCurrent())
return;
::glDisable(cap);
}
void GraphicsContextGLOpenGL::disableVertexAttribArray(GCGLuint index)
{
if (!makeContextCurrent())
return;
::glDisableVertexAttribArray(index);
}
void GraphicsContextGLOpenGL::drawArrays(GCGLenum mode, GCGLint first, GCGLsizei count)
{
if (!makeContextCurrent())
return;
::glDrawArrays(mode, first, count);
checkGPUStatus();
}
void GraphicsContextGLOpenGL::drawElements(GCGLenum mode, GCGLsizei count, GCGLenum type, GCGLintptr offset)
{
if (!makeContextCurrent())
return;
::glDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)));
checkGPUStatus();
}
void GraphicsContextGLOpenGL::enable(GCGLenum cap)
{
if (!makeContextCurrent())
return;
::glEnable(cap);
}
void GraphicsContextGLOpenGL::enableVertexAttribArray(GCGLuint index)
{
if (!makeContextCurrent())
return;
::glEnableVertexAttribArray(index);
}
void GraphicsContextGLOpenGL::finish()
{
if (!makeContextCurrent())
return;
::glFinish();
}
void GraphicsContextGLOpenGL::flush()
{
if (!makeContextCurrent())
return;
::glFlush();
}
void GraphicsContextGLOpenGL::framebufferRenderbuffer(GCGLenum target, GCGLenum attachment, GCGLenum renderbuffertarget, PlatformGLObject buffer)
{
if (!makeContextCurrent())
return;
::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer);
}
void GraphicsContextGLOpenGL::framebufferTexture2D(GCGLenum target, GCGLenum attachment, GCGLenum textarget, PlatformGLObject texture, GCGLint level)
{
if (!makeContextCurrent())
return;
::glFramebufferTexture2DEXT(target, attachment, textarget, texture, level);
}
void GraphicsContextGLOpenGL::frontFace(GCGLenum mode)
{
if (!makeContextCurrent())
return;
::glFrontFace(mode);
}
void GraphicsContextGLOpenGL::generateMipmap(GCGLenum target)
{
if (!makeContextCurrent())
return;
::glGenerateMipmap(target);
}
bool GraphicsContextGLOpenGL::getActiveAttribImpl(PlatformGLObject program, GCGLuint index, ActiveInfo& info)
{
if (!program) {
synthesizeGLError(INVALID_VALUE);
return false;
}
if (!makeContextCurrent())
return false;
GLint maxAttributeSize = 0;
::glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize);
Vector<GLchar> name(maxAttributeSize); // GL_ACTIVE_ATTRIBUTE_MAX_LENGTH includes null termination.
GLsizei nameLength = 0;
GLint size = 0;
GLenum type = 0;
::glGetActiveAttrib(program, index, maxAttributeSize, &nameLength, &size, &type, name.data());
if (!nameLength)
return false;
String originalName = originalSymbolName(program, SHADER_SYMBOL_TYPE_ATTRIBUTE, String(name.data(), nameLength));
#ifndef NDEBUG
String uniformName(name.data(), nameLength);
LOG(WebGL, "Program %d is mapping active attribute %d from '%s' to '%s'", program, index, uniformName.utf8().data(), originalName.utf8().data());
#endif
info.name = originalName;
info.type = type;
info.size = size;
return true;
}
bool GraphicsContextGLOpenGL::getActiveAttrib(PlatformGLObject program, GCGLuint index, ActiveInfo& info)
{
GCGLint symbolCount;
auto result = m_shaderProgramSymbolCountMap.find(program);
if (result == m_shaderProgramSymbolCountMap.end()) {
getNonBuiltInActiveSymbolCount(program, GraphicsContextGL::ACTIVE_ATTRIBUTES, &symbolCount);
result = m_shaderProgramSymbolCountMap.find(program);
}
ActiveShaderSymbolCounts& symbolCounts = result->value;
GCGLuint rawIndex = (index < symbolCounts.filteredToActualAttributeIndexMap.size()) ? symbolCounts.filteredToActualAttributeIndexMap[index] : -1;
return getActiveAttribImpl(program, rawIndex, info);
}
bool GraphicsContextGLOpenGL::getActiveUniformImpl(PlatformGLObject program, GCGLuint index, ActiveInfo& info)
{
if (!program) {
synthesizeGLError(INVALID_VALUE);
return false;
}
if (!makeContextCurrent())
return false;
GLint maxUniformSize = 0;
::glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize);
Vector<GLchar> name(maxUniformSize); // GL_ACTIVE_UNIFORM_MAX_LENGTH includes null termination.
GLsizei nameLength = 0;
GLint size = 0;
GLenum type = 0;
::glGetActiveUniform(program, index, maxUniformSize, &nameLength, &size, &type, name.data());
if (!nameLength)
return false;
String originalName = originalSymbolName(program, SHADER_SYMBOL_TYPE_UNIFORM, String(name.data(), nameLength));
#ifndef NDEBUG
String uniformName(name.data(), nameLength);
LOG(WebGL, "Program %d is mapping active uniform %d from '%s' to '%s'", program, index, uniformName.utf8().data(), originalName.utf8().data());
#endif
info.name = originalName;
info.type = type;
info.size = size;
return true;
}
bool GraphicsContextGLOpenGL::getActiveUniform(PlatformGLObject program, GCGLuint index, ActiveInfo& info)
{
GCGLint symbolCount;
auto result = m_shaderProgramSymbolCountMap.find(program);
if (result == m_shaderProgramSymbolCountMap.end()) {
getNonBuiltInActiveSymbolCount(program, GraphicsContextGL::ACTIVE_UNIFORMS, &symbolCount);
result = m_shaderProgramSymbolCountMap.find(program);
}
ActiveShaderSymbolCounts& symbolCounts = result->value;
GCGLuint rawIndex = (index < symbolCounts.filteredToActualUniformIndexMap.size()) ? symbolCounts.filteredToActualUniformIndexMap[index] : -1;
return getActiveUniformImpl(program, rawIndex, info);
}
void GraphicsContextGLOpenGL::getAttachedShaders(PlatformGLObject program, GCGLsizei maxCount, GCGLsizei* count, PlatformGLObject* shaders)
{
if (!program) {
synthesizeGLError(INVALID_VALUE);
return;
}
if (!makeContextCurrent())
return;
::glGetAttachedShaders(program, maxCount, count, shaders);
}
static String generateHashedName(const String& name)
{
if (name.isEmpty())
return name;
uint64_t number = nameHashForShader(name.utf8().data(), name.length());
return makeString("webgl_", hex(number, Lowercase));
}
std::optional<String> GraphicsContextGLOpenGL::mappedSymbolInShaderSourceMap(PlatformGLObject shader, ANGLEShaderSymbolType symbolType, const String& name)
{
auto result = m_shaderSourceMap.find(shader);
if (result == m_shaderSourceMap.end())
return std::nullopt;
const auto& symbolMap = result->value.symbolMap(symbolType);
auto symbolEntry = symbolMap.find(name);
if (symbolEntry == symbolMap.end())
return std::nullopt;
auto& mappedName = symbolEntry->value.get().mappedName;
return String(mappedName.c_str(), mappedName.length());
}
String GraphicsContextGLOpenGL::mappedSymbolName(PlatformGLObject program, ANGLEShaderSymbolType symbolType, const String& name)
{
GCGLsizei count = 0;
PlatformGLObject shaders[2] = { };
getAttachedShaders(program, 2, &count, shaders);
for (GCGLsizei i = 0; i < count; ++i) {
auto mappedName = mappedSymbolInShaderSourceMap(shaders[i], symbolType, name);
if (mappedName)
return mappedName.value();
}
// We might have detached or deleted the shaders after linking.
auto result = m_linkedShaderMap.find(program);
if (result != m_linkedShaderMap.end()) {
auto linkedShaders = result->value;
auto mappedName = mappedSymbolInShaderSourceMap(linkedShaders.first, symbolType, name);
if (mappedName)
return mappedName.value();
mappedName = mappedSymbolInShaderSourceMap(linkedShaders.second, symbolType, name);
if (mappedName)
return mappedName.value();
}
if (symbolType == SHADER_SYMBOL_TYPE_ATTRIBUTE && !name.isEmpty()) {
// Attributes are a special case: they may be requested before any shaders have been compiled,
// and aren't even required to be used in any shader program.
if (!nameHashMapForShaders)
nameHashMapForShaders = makeUnique<ShaderNameHash>();
setCurrentNameHashMapForShader(nameHashMapForShaders.get());
auto generatedName = generateHashedName(name);
setCurrentNameHashMapForShader(nullptr);
m_possiblyUnusedAttributeMap.set(generatedName, name);
return generatedName;
}
return name;
}
std::optional<String> GraphicsContextGLOpenGL::originalSymbolInShaderSourceMap(PlatformGLObject shader, ANGLEShaderSymbolType symbolType, const String& name)
{
auto result = m_shaderSourceMap.find(shader);
if (result == m_shaderSourceMap.end())
return std::nullopt;
const auto& symbolMap = result->value.symbolMap(symbolType);
for (const auto& symbolEntry : symbolMap) {
if (name == StringView::fromLatin1(symbolEntry.value.get().mappedName.c_str()))
return symbolEntry.key;
}
return std::nullopt;
}
String GraphicsContextGLOpenGL::originalSymbolName(PlatformGLObject program, ANGLEShaderSymbolType symbolType, const String& name)
{
GCGLsizei count;
PlatformGLObject shaders[2];
getAttachedShaders(program, 2, &count, shaders);
for (GCGLsizei i = 0; i < count; ++i) {
auto originalName = originalSymbolInShaderSourceMap(shaders[i], symbolType, name);
if (originalName)
return originalName.value();
}
// We might have detached or deleted the shaders after linking.
auto result = m_linkedShaderMap.find(program);
if (result != m_linkedShaderMap.end()) {
auto linkedShaders = result->value;
auto originalName = originalSymbolInShaderSourceMap(linkedShaders.first, symbolType, name);
if (originalName)
return originalName.value();
originalName = originalSymbolInShaderSourceMap(linkedShaders.second, symbolType, name);
if (originalName)
return originalName.value();
}
if (symbolType == SHADER_SYMBOL_TYPE_ATTRIBUTE && !name.isEmpty()) {
// Attributes are a special case: they may be requested before any shaders have been compiled,
// and aren't even required to be used in any shader program.
const auto& cached = m_possiblyUnusedAttributeMap.find(name);
if (cached != m_possiblyUnusedAttributeMap.end())
return cached->value;
}
return name;
}
String GraphicsContextGLOpenGL::mappedSymbolName(PlatformGLObject shaders[2], size_t count, const String& name)
{
for (size_t symbolType = 0; symbolType <= static_cast<size_t>(SHADER_SYMBOL_TYPE_VARYING); ++symbolType) {
for (size_t i = 0; i < count; ++i) {
ShaderSourceMap::iterator result = m_shaderSourceMap.find(shaders[i]);
if (result == m_shaderSourceMap.end())
continue;
const ShaderSymbolMap& symbolMap = result->value.symbolMap(static_cast<enum ANGLEShaderSymbolType>(symbolType));
for (const auto& symbolEntry : symbolMap) {
if (name == StringView::fromLatin1(symbolEntry.value.get().mappedName.c_str()))
return symbolEntry.key;
}
}
}
return name;
}
int GraphicsContextGLOpenGL::getAttribLocation(PlatformGLObject program, const String& name)
{
if (!program)
return -1;
if (!makeContextCurrent())
return -1;
String mappedName = mappedSymbolName(program, SHADER_SYMBOL_TYPE_ATTRIBUTE, name);
LOG(WebGL, "::glGetAttribLocation is mapping %s to %s", name.utf8().data(), mappedName.utf8().data());
return ::glGetAttribLocation(program, mappedName.utf8().data());
}
int GraphicsContextGLOpenGL::getAttribLocationDirect(PlatformGLObject program, const String& name)
{
if (!program)
return -1;
if (!makeContextCurrent())
return -1;
return ::glGetAttribLocation(program, name.utf8().data());
}
bool GraphicsContextGLOpenGL::moveErrorsToSyntheticErrorList()
{
if (!makeContextCurrent())
return false;
bool movedAnError = false;
// Set an arbitrary limit of 100 here to avoid creating a hang if
// a problem driver has a bug that causes it to never clear the error.
// Otherwise, we would just loop until we got NO_ERROR.
for (unsigned i = 0; i < 100; ++i) {
GCGLenum error = glGetError();
if (error == NO_ERROR)
break;
m_syntheticErrors.add(error);
movedAnError = true;
}
return movedAnError;
}
GCGLenum GraphicsContextGLOpenGL::getError()
{
if (!m_syntheticErrors.isEmpty()) {
// Need to move the current errors to the synthetic error list in case
// that error is already there, since the expected behavior of both
// glGetError and getError is to only report each error code once.
moveErrorsToSyntheticErrorList();
return m_syntheticErrors.takeFirst();
}
if (!makeContextCurrent())
return GL_INVALID_OPERATION;
return ::glGetError();
}
String GraphicsContextGLOpenGL::getString(GCGLenum name)
{
if (!makeContextCurrent())
return String();
return String::fromLatin1(reinterpret_cast<const char*>(::glGetString(name)));
}
void GraphicsContextGLOpenGL::hint(GCGLenum target, GCGLenum mode)
{
if (!makeContextCurrent())
return;
::glHint(target, mode);
}
GCGLboolean GraphicsContextGLOpenGL::isBuffer(PlatformGLObject buffer)
{
if (!buffer)
return GL_FALSE;
if (!makeContextCurrent())
return GL_FALSE;
return ::glIsBuffer(buffer);
}
GCGLboolean GraphicsContextGLOpenGL::isEnabled(GCGLenum cap)
{
if (!makeContextCurrent())
return GL_FALSE;
return ::glIsEnabled(cap);
}
GCGLboolean GraphicsContextGLOpenGL::isFramebuffer(PlatformGLObject framebuffer)
{
if (!framebuffer)
return GL_FALSE;
if (!makeContextCurrent())
return GL_FALSE;
return ::glIsFramebufferEXT(framebuffer);
}
GCGLboolean GraphicsContextGLOpenGL::isProgram(PlatformGLObject program)
{
if (!program)
return GL_FALSE;
if (!makeContextCurrent())
return GL_FALSE;
return ::glIsProgram(program);
}
GCGLboolean GraphicsContextGLOpenGL::isRenderbuffer(PlatformGLObject renderbuffer)
{
if (!renderbuffer)
return GL_FALSE;
if (!makeContextCurrent())
return GL_FALSE;
return ::glIsRenderbufferEXT(renderbuffer);
}
GCGLboolean GraphicsContextGLOpenGL::isShader(PlatformGLObject shader)
{
if (!shader)
return GL_FALSE;
if (!makeContextCurrent())
return GL_FALSE;
return ::glIsShader(shader);
}
GCGLboolean GraphicsContextGLOpenGL::isTexture(PlatformGLObject texture)
{
if (!texture)
return GL_FALSE;
if (!makeContextCurrent())
return GL_FALSE;
return ::glIsTexture(texture);
}
void GraphicsContextGLOpenGL::lineWidth(GCGLfloat width)
{
if (!makeContextCurrent())
return;
::glLineWidth(width);
}
void GraphicsContextGLOpenGL::linkProgram(PlatformGLObject program)
{
ASSERT(program);
if (!makeContextCurrent())
return;
GCGLsizei count = 0;
PlatformGLObject shaders[2] = { };
getAttachedShaders(program, 2, &count, shaders);
if (count == 2)
m_linkedShaderMap.set(program, std::make_pair(shaders[0], shaders[1]));
::glLinkProgram(program);
}
void GraphicsContextGLOpenGL::pixelStorei(GCGLenum pname, GCGLint param)
{
if (!makeContextCurrent())
return;
::glPixelStorei(pname, param);
}
void GraphicsContextGLOpenGL::polygonOffset(GCGLfloat factor, GCGLfloat units)
{
if (!makeContextCurrent())
return;
::glPolygonOffset(factor, units);
}
void GraphicsContextGLOpenGL::sampleCoverage(GCGLclampf value, GCGLboolean invert)
{
if (!makeContextCurrent())
return;
::glSampleCoverage(value, invert);
}
void GraphicsContextGLOpenGL::scissor(GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height)
{
if (!makeContextCurrent())
return;
::glScissor(x, y, width, height);
}
void GraphicsContextGLOpenGL::shaderSource(PlatformGLObject shader, const String& string)
{
ASSERT(shader);
if (!makeContextCurrent())
return;
ShaderSourceEntry entry;
entry.source = string;
m_shaderSourceMap.set(shader, WTFMove(entry));
}
void GraphicsContextGLOpenGL::stencilFunc(GCGLenum func, GCGLint ref, GCGLuint mask)
{
if (!makeContextCurrent())
return;
::glStencilFunc(func, ref, mask);
}
void GraphicsContextGLOpenGL::stencilFuncSeparate(GCGLenum face, GCGLenum func, GCGLint ref, GCGLuint mask)
{
if (!makeContextCurrent())
return;
::glStencilFuncSeparate(face, func, ref, mask);
}
void GraphicsContextGLOpenGL::stencilMask(GCGLuint mask)
{
if (!makeContextCurrent())
return;
::glStencilMask(mask);
}
void GraphicsContextGLOpenGL::stencilMaskSeparate(GCGLenum face, GCGLuint mask)
{
if (!makeContextCurrent())
return;
::glStencilMaskSeparate(face, mask);
}
void GraphicsContextGLOpenGL::stencilOp(GCGLenum fail, GCGLenum zfail, GCGLenum zpass)
{
if (!makeContextCurrent())
return;
::glStencilOp(fail, zfail, zpass);
}
void GraphicsContextGLOpenGL::stencilOpSeparate(GCGLenum face, GCGLenum fail, GCGLenum zfail, GCGLenum zpass)
{
if (!makeContextCurrent())
return;
::glStencilOpSeparate(face, fail, zfail, zpass);
}
void GraphicsContextGLOpenGL::texParameterf(GCGLenum target, GCGLenum pname, GCGLfloat value)
{
if (!makeContextCurrent())
return;
::glTexParameterf(target, pname, value);
}
void GraphicsContextGLOpenGL::texParameteri(GCGLenum target, GCGLenum pname, GCGLint value)
{
if (!makeContextCurrent())
return;
::glTexParameteri(target, pname, value);
}
void GraphicsContextGLOpenGL::uniform1f(GCGLint location, GCGLfloat v0)
{
if (!makeContextCurrent())
return;
::glUniform1f(location, v0);
}
void GraphicsContextGLOpenGL::uniform1fv(GCGLint location, GCGLSpan<const GCGLfloat> array)
{
if (!makeContextCurrent())
return;
::glUniform1fv(location, array.bufSize, array.data);
}
void GraphicsContextGLOpenGL::uniform2f(GCGLint location, GCGLfloat v0, GCGLfloat v1)
{
if (!makeContextCurrent())
return;
::glUniform2f(location, v0, v1);
}
void GraphicsContextGLOpenGL::uniform2fv(GCGLint location, GCGLSpan<const GCGLfloat> array)
{
ASSERT(!(array.bufSize % 2));
if (!makeContextCurrent())
return;
::glUniform2fv(location, array.bufSize / 2, array.data);
}
void GraphicsContextGLOpenGL::uniform3f(GCGLint location, GCGLfloat v0, GCGLfloat v1, GCGLfloat v2)
{
if (!makeContextCurrent())
return;
::glUniform3f(location, v0, v1, v2);
}
void GraphicsContextGLOpenGL::uniform3fv(GCGLint location, GCGLSpan<const GCGLfloat> array)
{
ASSERT(!(array.bufSize % 3));
if (!makeContextCurrent())
return;
::glUniform3fv(location, array.bufSize / 3, array.data);
}
void GraphicsContextGLOpenGL::uniform4f(GCGLint location, GCGLfloat v0, GCGLfloat v1, GCGLfloat v2, GCGLfloat v3)
{
if (!makeContextCurrent())
return;
::glUniform4f(location, v0, v1, v2, v3);
}
void GraphicsContextGLOpenGL::uniform4fv(GCGLint location, GCGLSpan<const GCGLfloat> array)
{
ASSERT(!(array.bufSize % 4));
if (!makeContextCurrent())
return;
::glUniform4fv(location, array.bufSize / 4, array.data);
}
void GraphicsContextGLOpenGL::uniform1i(GCGLint location, GCGLint v0)
{
if (!makeContextCurrent())
return;
::glUniform1i(location, v0);
}
void GraphicsContextGLOpenGL::uniform1iv(GCGLint location, GCGLSpan<const GCGLint> array)
{
if (!makeContextCurrent())
return;
::glUniform1iv(location, array.bufSize, array.data);
}
void GraphicsContextGLOpenGL::uniform2i(GCGLint location, GCGLint v0, GCGLint v1)
{
if (!makeContextCurrent())
return;
::glUniform2i(location, v0, v1);
}
void GraphicsContextGLOpenGL::uniform2iv(GCGLint location, GCGLSpan<const GCGLint> array)
{
ASSERT(!(array.bufSize % 2));
if (!makeContextCurrent())
return;
::glUniform2iv(location, array.bufSize / 2, array.data);
}
void GraphicsContextGLOpenGL::uniform3i(GCGLint location, GCGLint v0, GCGLint v1, GCGLint v2)
{
if (!makeContextCurrent())
return;
::glUniform3i(location, v0, v1, v2);
}
void GraphicsContextGLOpenGL::uniform3iv(GCGLint location, GCGLSpan<const GCGLint> array)
{
ASSERT(!(array.bufSize % 3));
if (!makeContextCurrent())
return;
::glUniform3iv(location, array.bufSize / 3, array.data);
}
void GraphicsContextGLOpenGL::uniform4i(GCGLint location, GCGLint v0, GCGLint v1, GCGLint v2, GCGLint v3)
{
if (!makeContextCurrent())
return;
::glUniform4i(location, v0, v1, v2, v3);
}
void GraphicsContextGLOpenGL::uniform4iv(GCGLint location, GCGLSpan<const GCGLint> array)
{
ASSERT(!(array.bufSize % 4));
if (!makeContextCurrent())
return;
::glUniform4iv(location, array.bufSize / 4, array.data);
}
void GraphicsContextGLOpenGL::uniformMatrix2fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> array)
{
ASSERT(!(array.bufSize % 4));
if (!makeContextCurrent())
return;
::glUniformMatrix2fv(location, array.bufSize / 4, transpose, array.data);
}
void GraphicsContextGLOpenGL::uniformMatrix3fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> array)
{
ASSERT(!(array.bufSize % 9));
if (!makeContextCurrent())
return;
::glUniformMatrix3fv(location, array.bufSize / 9, transpose, array.data);
}
void GraphicsContextGLOpenGL::uniformMatrix4fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> array)
{
ASSERT(!(array.bufSize % 16));
if (!makeContextCurrent())
return;
::glUniformMatrix4fv(location, array.bufSize / 16, transpose, array.data);
}
void GraphicsContextGLOpenGL::useProgram(PlatformGLObject program)
{
if (!makeContextCurrent())
return;
::glUseProgram(program);
}
void GraphicsContextGLOpenGL::validateProgram(PlatformGLObject program)
{
ASSERT(program);
if (!makeContextCurrent())
return;
::glValidateProgram(program);
}
void GraphicsContextGLOpenGL::vertexAttrib1f(GCGLuint index, GCGLfloat v0)
{
if (!makeContextCurrent())
return;
::glVertexAttrib1f(index, v0);
}
void GraphicsContextGLOpenGL::vertexAttrib1fv(GCGLuint index, GCGLSpan<const GCGLfloat, 1> array)
{
if (!makeContextCurrent())
return;
::glVertexAttrib1fv(index, array.data);
}
void GraphicsContextGLOpenGL::vertexAttrib2f(GCGLuint index, GCGLfloat v0, GCGLfloat v1)
{
if (!makeContextCurrent())
return;
::glVertexAttrib2f(index, v0, v1);
}
void GraphicsContextGLOpenGL::vertexAttrib2fv(GCGLuint index, GCGLSpan<const GCGLfloat, 2> array)
{
if (!makeContextCurrent())
return;
::glVertexAttrib2fv(index, array.data);
}
void GraphicsContextGLOpenGL::vertexAttrib3f(GCGLuint index, GCGLfloat v0, GCGLfloat v1, GCGLfloat v2)
{
if (!makeContextCurrent())
return;
::glVertexAttrib3f(index, v0, v1, v2);
}
void GraphicsContextGLOpenGL::vertexAttrib3fv(GCGLuint index, GCGLSpan<const GCGLfloat, 3> array)
{
if (!makeContextCurrent())
return;
::glVertexAttrib3fv(index, array.data);
}
void GraphicsContextGLOpenGL::vertexAttrib4f(GCGLuint index, GCGLfloat v0, GCGLfloat v1, GCGLfloat v2, GCGLfloat v3)
{
if (!makeContextCurrent())
return;
::glVertexAttrib4f(index, v0, v1, v2, v3);
}
void GraphicsContextGLOpenGL::vertexAttrib4fv(GCGLuint index, GCGLSpan<const GCGLfloat, 4> array)
{
if (!makeContextCurrent())
return;
::glVertexAttrib4fv(index, array.data);
}
void GraphicsContextGLOpenGL::vertexAttribPointer(GCGLuint index, GCGLint size, GCGLenum type, GCGLboolean normalized, GCGLsizei stride, GCGLintptr offset)
{
if (!makeContextCurrent())
return;
::glVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)));
}
void GraphicsContextGLOpenGL::viewport(GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height)
{
if (!makeContextCurrent())
return;
::glViewport(x, y, width, height);
}
PlatformGLObject GraphicsContextGLOpenGL::createVertexArray()
{
return getExtensions().createVertexArrayOES();
}
void GraphicsContextGLOpenGL::deleteVertexArray(PlatformGLObject array)
{
getExtensions().deleteVertexArrayOES(array);
}
GCGLboolean GraphicsContextGLOpenGL::isVertexArray(PlatformGLObject array)
{
return getExtensions().isVertexArrayOES(array);
}
void GraphicsContextGLOpenGL::bindVertexArray(PlatformGLObject array)
{
getExtensions().bindVertexArrayOES(array);
}
void GraphicsContextGLOpenGL::getBooleanv(GCGLenum pname, GCGLSpan<GCGLboolean> value)
{
if (!makeContextCurrent())
return;
::glGetBooleanv(pname, value.data);
}
GCGLint GraphicsContextGLOpenGL::getBufferParameteri(GCGLenum target, GCGLenum pname)
{
GCGLint value = 0;
if (!makeContextCurrent())
return value;
::glGetBufferParameteriv(target, pname, &value);
return value;
}
void GraphicsContextGLOpenGL::getFloatv(GCGLenum pname, GCGLSpan<GCGLfloat> value)
{
if (!makeContextCurrent())
return;
::glGetFloatv(pname, value.data);
}
void GraphicsContextGLOpenGL::getIntegeri_v(GCGLenum pname, GCGLuint index, GCGLSpan<GCGLint, 4> value) // NOLINT
{
UNUSED_PARAM(pname);
UNUSED_PARAM(index);
UNUSED_PARAM(value);
if (!makeContextCurrent())
return;
// FIXME 141178: Before enabling this we must first switch over to using gl3.h and creating and initialing the WebGL2 context using OpenGL ES 3.0.
// ::glGetIntegeri_v(pname, index, value.data);
}
GCGLint64 GraphicsContextGLOpenGL::getInteger64(GCGLenum pname)
{
UNUSED_PARAM(pname);
if (!makeContextCurrent())
return 0;
GCGLint64 value = 0;
// FIXME 141178: Before enabling this we must first switch over to using gl3.h and creating and initialing the WebGL2 context using OpenGL ES 3.0.
// ::glGetInteger64v(pname, value);
return value;
}
GCGLint64 GraphicsContextGLOpenGL::getInteger64i(GCGLenum pname, GCGLuint index)
{
UNUSED_PARAM(pname);
UNUSED_PARAM(index);
if (!makeContextCurrent())
return 0;
GCGLint64 value = 0;
// FIXME 141178: Before enabling this we must first switch over to using gl3.h and creating and initialing the WebGL2 context using OpenGL ES 3.0.
// ::glGetInteger64i_v(pname, index, value);
return value;
}
GCGLint GraphicsContextGLOpenGL::getFramebufferAttachmentParameteri(GCGLenum target, GCGLenum attachment, GCGLenum pname)
{
GCGLint value = 0;
if (!makeContextCurrent())
return 0;
if (attachment == DEPTH_STENCIL_ATTACHMENT)
attachment = DEPTH_ATTACHMENT; // Or STENCIL_ATTACHMENT, either works.
::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &value);
return value;
}
GCGLint GraphicsContextGLOpenGL::getProgrami(PlatformGLObject program, GCGLenum pname)
{
if (!makeContextCurrent())
return 0;
GCGLint value = 0;
::glGetProgramiv(program, pname, &value);
return value;
}
void GraphicsContextGLOpenGL::getNonBuiltInActiveSymbolCount(PlatformGLObject program, GCGLenum pname, GCGLint* value)
{
ASSERT(ACTIVE_ATTRIBUTES == pname || ACTIVE_UNIFORMS == pname);
if (!value)
return;
if (!makeContextCurrent())
return;
const auto& result = m_shaderProgramSymbolCountMap.find(program);
if (result != m_shaderProgramSymbolCountMap.end()) {
*value = result->value.countForType(pname);
return;
}
m_shaderProgramSymbolCountMap.set(program, ActiveShaderSymbolCounts());
ActiveShaderSymbolCounts& symbolCounts = m_shaderProgramSymbolCountMap.find(program)->value;
// Retrieve the active attributes, build a filtered count, and a mapping of
// our internal attributes indexes to the real unfiltered indexes inside OpenGL.
GCGLint attributeCount = 0;
::glGetProgramiv(program, ACTIVE_ATTRIBUTES, &attributeCount);
for (GCGLint i = 0; i < attributeCount; ++i) {
ActiveInfo info;
getActiveAttribImpl(program, i, info);
if (info.name.startsWith("gl_"_s))
continue;
symbolCounts.filteredToActualAttributeIndexMap.append(i);
}
// Do the same for uniforms.
GCGLint uniformCount = 0;
::glGetProgramiv(program, ACTIVE_UNIFORMS, &uniformCount);
for (GCGLint i = 0; i < uniformCount; ++i) {
ActiveInfo info;
getActiveUniformImpl(program, i, info);
if (info.name.startsWith("gl_"_s))
continue;
symbolCounts.filteredToActualUniformIndexMap.append(i);
}
*value = symbolCounts.countForType(pname);
}
String GraphicsContextGLOpenGL::getUnmangledInfoLog(PlatformGLObject shaders[2], GCGLsizei count, const String& log)
{
LOG(WebGL, "Original ShaderInfoLog:\n%s", log.utf8().data());
JSC::Yarr::RegularExpression regExp("webgl_[0123456789abcdefABCDEF]+"_s);
StringBuilder processedLog;
// ANGLE inserts a "#extension" line into the shader source that
// causes a warning in some compilers. There is no point showing
// this warning to the user since they didn't write the code that
// is causing it.
static constexpr auto angleWarning = "WARNING: 0:1: extension 'GL_ARB_gpu_shader5' is not supported\n"_s;
int startFrom = log.startsWith(angleWarning) ? angleWarning.length() : 0;
int matchedLength = 0;
do {
int start = regExp.match(log, startFrom, &matchedLength);
if (start == -1)
break;
processedLog.append(StringView(log).substring(startFrom, start - startFrom));
startFrom = start + matchedLength;
const String& mangledSymbol = log.substring(start, matchedLength);
const String& mappedSymbol = mappedSymbolName(shaders, count, mangledSymbol);
LOG(WebGL, "Demangling: %s to %s", mangledSymbol.utf8().data(), mappedSymbol.utf8().data());
processedLog.append(mappedSymbol);
} while (startFrom < static_cast<int>(log.length()));
processedLog.append(StringView(log).substring(startFrom, log.length() - startFrom));
LOG(WebGL, "Unmangled ShaderInfoLog:\n%s", processedLog.toString().utf8().data());
return processedLog.toString();
}
String GraphicsContextGLOpenGL::getProgramInfoLog(PlatformGLObject program)
{
ASSERT(program);
if (!makeContextCurrent())
return String();
GLint length = 0;
::glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
if (!length)
return String();
GLsizei size = 0;
Vector<GLchar> info(length);
::glGetProgramInfoLog(program, length, &size, info.data());
GCGLsizei count;
PlatformGLObject shaders[2];
getAttachedShaders(program, 2, &count, shaders);
return getUnmangledInfoLog(shaders, count, String(info.data(), size));
}
GCGLint GraphicsContextGLOpenGL::getRenderbufferParameteri(GCGLenum target, GCGLenum pname)
{
GCGLint value = 0;
if (!makeContextCurrent())
return value;
::glGetRenderbufferParameterivEXT(target, pname, &value);
return value;
}
GCGLint GraphicsContextGLOpenGL::getShaderi(PlatformGLObject shader, GCGLenum pname)
{
ASSERT(shader);
GCGLint value = 0;
if (!makeContextCurrent())
return value;
const auto& result = m_shaderSourceMap.find(shader);
switch (pname) {
case DELETE_STATUS:
case SHADER_TYPE:
::glGetShaderiv(shader, pname, &value);
break;
case COMPILE_STATUS:
if (result != m_shaderSourceMap.end())
value = static_cast<int>(result->value.isValid);
break;
case INFO_LOG_LENGTH:
if (result != m_shaderSourceMap.end())
value = getShaderInfoLog(shader).length();
break;
case SHADER_SOURCE_LENGTH:
value = getShaderSource(shader).length();
break;
default:
synthesizeGLError(INVALID_ENUM);
}
return value;
}
String GraphicsContextGLOpenGL::getShaderInfoLog(PlatformGLObject shader)
{
ASSERT(shader);
if (!makeContextCurrent())
return String();
const auto& result = m_shaderSourceMap.find(shader);
if (result == m_shaderSourceMap.end())
return String();
const ShaderSourceEntry& entry = result->value;
if (!entry.isValid)
return entry.log;
GLint length = 0;
::glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (!length)
return String();
GLsizei size = 0;
Vector<GLchar> info(length);
::glGetShaderInfoLog(shader, length, &size, info.data());
PlatformGLObject shaders[2] = { shader, 0 };
return getUnmangledInfoLog(shaders, 1, String(info.data(), size));
}
String GraphicsContextGLOpenGL::getShaderSource(PlatformGLObject shader)
{
ASSERT(shader);
if (!makeContextCurrent())
return String();
const auto& result = m_shaderSourceMap.find(shader);
if (result == m_shaderSourceMap.end())
return String();
return result->value.source;
}
GCGLfloat GraphicsContextGLOpenGL::getTexParameterf(GCGLenum target, GCGLenum pname)
{
GCGLfloat value = 0.f;
if (!makeContextCurrent())
return value;
::glGetTexParameterfv(target, pname, &value);
return value;
}
GCGLint GraphicsContextGLOpenGL::getTexParameteri(GCGLenum target, GCGLenum pname)
{
GCGLint value = 0;
if (!makeContextCurrent())
return value;
::glGetTexParameteriv(target, pname, &value);
return value;
}
void GraphicsContextGLOpenGL::getUniformfv(PlatformGLObject program, GCGLint location, GCGLSpan<GCGLfloat> value)
{
if (!makeContextCurrent())
return;
::glGetUniformfv(program, location, value.data);
}
void GraphicsContextGLOpenGL::getUniformiv(PlatformGLObject program, GCGLint location, GCGLSpan<GCGLint> value)
{
if (!makeContextCurrent())
return;
::glGetUniformiv(program, location, value.data);
}
void GraphicsContextGLOpenGL::getUniformuiv(PlatformGLObject program, GCGLint location, GCGLSpan<GCGLuint> value)
{
UNUSED_PARAM(program);
UNUSED_PARAM(location);
UNUSED_PARAM(value);
}
GCGLint GraphicsContextGLOpenGL::getUniformLocation(PlatformGLObject program, const String& name)
{
ASSERT(program);
if (!makeContextCurrent())
return -1;
String mappedName = mappedSymbolName(program, SHADER_SYMBOL_TYPE_UNIFORM, name);
LOG(WebGL, "::getUniformLocation is mapping %s to %s", name.utf8().data(), mappedName.utf8().data());
return ::glGetUniformLocation(program, mappedName.utf8().data());
}
GCGLsizeiptr GraphicsContextGLOpenGL::getVertexAttribOffset(GCGLuint index, GCGLenum pname)
{
if (!makeContextCurrent())
return 0;
GLvoid* pointer = 0;
::glGetVertexAttribPointerv(index, pname, &pointer);
return static_cast<GCGLsizeiptr>(reinterpret_cast<intptr_t>(pointer));
}
void GraphicsContextGLOpenGL::texSubImage2D(GCGLenum target, GCGLint level, GCGLint xoff, GCGLint yoff, GCGLsizei width, GCGLsizei height, GCGLenum format, GCGLenum type, GCGLSpan<const GCGLvoid> pixels)
{
if (!makeContextCurrent())
return;
#if !USE(OPENGL_ES)
if (type == HALF_FLOAT_OES)
type = GL_HALF_FLOAT_ARB;
#endif
if (m_usingCoreProfile) {
// There are some format values used in WebGL that are deprecated when using a core profile, so we need
// to adapt them, as we do in GraphicsContextGLOpenGL::texImage2D().
switch (format) {
case ALPHA:
// We are using GL_RED to back GL_ALPHA, so do it here as well.
format = RED;
break;
case LUMINANCE_ALPHA:
// We are using GL_RG to back GL_LUMINANCE_ALPHA, so do it here as well.
format = RG;
break;
default:
break;
}
}
// FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size.
::glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels.data);
}
void GraphicsContextGLOpenGL::compressedTexImage2D(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLsizei width, GCGLsizei height, GCGLint border, GCGLsizei imageSize, GCGLSpan<const GCGLvoid> data)
{
if (!makeContextCurrent())
return;
::glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data.data);
}
void GraphicsContextGLOpenGL::compressedTexSubImage2D(GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset, GCGLsizei width, GCGLsizei height, GCGLenum format, GCGLsizei imageSize, GCGLSpan<const GCGLvoid> data)
{
if (!makeContextCurrent())
return;
::glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data.data);
}
PlatformGLObject GraphicsContextGLOpenGL::createBuffer()
{
if (!makeContextCurrent())
return 0;
GLuint o = 0;
glGenBuffers(1, &o);
return o;
}
PlatformGLObject GraphicsContextGLOpenGL::createFramebuffer()
{
if (!makeContextCurrent())
return 0;
GLuint o = 0;
glGenFramebuffersEXT(1, &o);
return o;
}
PlatformGLObject GraphicsContextGLOpenGL::createProgram()
{
if (!makeContextCurrent())
return 0;
return glCreateProgram();
}
PlatformGLObject GraphicsContextGLOpenGL::createRenderbuffer()
{
if (!makeContextCurrent())
return 0;
GLuint o = 0;
glGenRenderbuffersEXT(1, &o);
return o;
}
PlatformGLObject GraphicsContextGLOpenGL::createShader(GCGLenum type)
{
if (!makeContextCurrent())
return 0;
return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER);
}
PlatformGLObject GraphicsContextGLOpenGL::createTexture()
{
if (!makeContextCurrent())
return 0;
GLuint o = 0;
glGenTextures(1, &o);
return o;
}
void GraphicsContextGLOpenGL::deleteBuffer(PlatformGLObject buffer)
{
if (!makeContextCurrent())
return;
glDeleteBuffers(1, &buffer);
}
void GraphicsContextGLOpenGL::deleteFramebuffer(PlatformGLObject framebuffer)
{
if (!makeContextCurrent())
return;
ASSERT(m_state.boundReadFBO == m_state.boundDrawFBO);
if (framebuffer == m_state.boundDrawFBO) {
// Make sure the framebuffer is not going to be used for drawing
// operations after it gets deleted.
bindFramebuffer(FRAMEBUFFER, 0);
}
glDeleteFramebuffersEXT(1, &framebuffer);
}
void GraphicsContextGLOpenGL::deleteProgram(PlatformGLObject program)
{
if (!makeContextCurrent())
return;
m_shaderProgramSymbolCountMap.remove(program);
glDeleteProgram(program);
}
void GraphicsContextGLOpenGL::deleteRenderbuffer(PlatformGLObject renderbuffer)
{
if (!makeContextCurrent())
return;
glDeleteRenderbuffersEXT(1, &renderbuffer);
}
void GraphicsContextGLOpenGL::deleteShader(PlatformGLObject shader)
{
if (!makeContextCurrent())
return;
glDeleteShader(shader);
}
void GraphicsContextGLOpenGL::deleteTexture(PlatformGLObject texture)
{
if (!makeContextCurrent())
return;
m_state.boundTextureMap.removeIf([texture] (auto& keyValue) {
return keyValue.value.first == texture;
});
glDeleteTextures(1, &texture);
}
void GraphicsContextGLOpenGL::synthesizeGLError(GCGLenum error)
{
// Need to move the current errors to the synthetic error list to
// preserve the order of errors, so a caller to getError will get
// any errors from glError before the error we are synthesizing.
moveErrorsToSyntheticErrorList();
m_syntheticErrors.add(error);
}
void GraphicsContextGLOpenGL::texImage2DDirect(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLsizei width, GCGLsizei height, GCGLint border, GCGLenum format, GCGLenum type, const void* pixels)
{
if (!makeContextCurrent())
return;
::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
}
void GraphicsContextGLOpenGL::drawArraysInstanced(GCGLenum mode, GCGLint first, GCGLsizei count, GCGLsizei primcount)
{
getExtensions().drawArraysInstancedANGLE(mode, first, count, primcount);
checkGPUStatus();
}
void GraphicsContextGLOpenGL::drawElementsInstanced(GCGLenum mode, GCGLsizei count, GCGLenum type, GCGLintptr offset, GCGLsizei primcount)
{
getExtensions().drawElementsInstancedANGLE(mode, count, type, offset, primcount);
checkGPUStatus();
}
void GraphicsContextGLOpenGL::vertexAttribDivisor(GCGLuint index, GCGLuint divisor)
{
getExtensions().vertexAttribDivisorANGLE(index, divisor);
}
void GraphicsContextGLOpenGL::bufferData(GCGLenum target, const void* data, GCGLenum usage, GCGLuint srcOffset, GCGLuint length)
{
UNUSED_PARAM(target);
UNUSED_PARAM(data);
UNUSED_PARAM(usage);
UNUSED_PARAM(srcOffset);
UNUSED_PARAM(length);
}
void GraphicsContextGLOpenGL::bufferSubData(GCGLenum target, GCGLintptr dstByteOffset, const void* srcData, GCGLuint srcOffset, GCGLuint length)
{
UNUSED_PARAM(target);
UNUSED_PARAM(dstByteOffset);
UNUSED_PARAM(srcData);
UNUSED_PARAM(srcOffset);
UNUSED_PARAM(length);
}
#if HAVE(OPENGL_4) || HAVE(OPENGL_ES_3)
void GraphicsContextGLOpenGL::copyBufferSubData(GCGLenum readTarget, GCGLenum writeTarget, GCGLintptr readOffset, GCGLintptr writeOffset, GCGLsizeiptr size)
{
if (!makeContextCurrent())
return;
::glCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
}
#else
void GraphicsContextGLOpenGL::copyBufferSubData(GCGLenum, GCGLenum, GCGLintptr, GCGLintptr, GCGLsizeiptr)
{
}
#endif
void GraphicsContextGLOpenGL::getBufferSubData(GCGLenum target, GCGLintptr offset, GCGLSpan<GCGLvoid> data)
{
#if HAVE(OPENGL_4) || HAVE(OPENGL_ES_3)
if (!makeContextCurrent())
return;
GCGLvoid* ptr = ::glMapBufferRange(target, offset, data.bufSize, GraphicsContextGL::MAP_READ_BIT);
if (!ptr)
return;
memcpy(data.data, ptr, data.bufSize);
if (!::glUnmapBuffer(target))
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION);
#else
UNUSED_PARAM(target);
UNUSED_PARAM(offset);
UNUSED_PARAM(data);
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION);
#endif
}
void GraphicsContextGLOpenGL::blitFramebuffer(GCGLint srcX0, GCGLint srcY0, GCGLint srcX1, GCGLint srcY1, GCGLint dstX0, GCGLint dstY0, GCGLint dstX1, GCGLint dstY1, GCGLbitfield mask, GCGLenum filter)
{
UNUSED_PARAM(srcX0);
UNUSED_PARAM(srcY0);
UNUSED_PARAM(srcX1);
UNUSED_PARAM(srcY1);
UNUSED_PARAM(dstX0);
UNUSED_PARAM(dstY0);
UNUSED_PARAM(dstX1);
UNUSED_PARAM(dstY1);
UNUSED_PARAM(mask);
UNUSED_PARAM(filter);
}
void GraphicsContextGLOpenGL::framebufferTextureLayer(GCGLenum target, GCGLenum attachment, PlatformGLObject texture, GCGLint level, GCGLint layer)
{
UNUSED_PARAM(target);
UNUSED_PARAM(attachment);
UNUSED_PARAM(texture);
UNUSED_PARAM(level);
UNUSED_PARAM(layer);
}
void GraphicsContextGLOpenGL::invalidateFramebuffer(GCGLenum target, GCGLSpan<const GCGLenum> attachments)
{
UNUSED_PARAM(target);
UNUSED_PARAM(attachments);
}
void GraphicsContextGLOpenGL::invalidateSubFramebuffer(GCGLenum target, GCGLSpan<const GCGLenum> attachments, GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height)
{
UNUSED_PARAM(target);
UNUSED_PARAM(attachments);
UNUSED_PARAM(x);
UNUSED_PARAM(y);
UNUSED_PARAM(width);
UNUSED_PARAM(height);
}
void GraphicsContextGLOpenGL::readBuffer(GCGLenum src)
{
UNUSED_PARAM(src);
}
#if HAVE(OPENGL_4) || HAVE(OPENGL_ES_3)
void GraphicsContextGLOpenGL::getInternalformativ(GCGLenum target, GCGLenum internalformat, GCGLenum pname, GCGLSpan<GCGLint> data)
{
#if USE(OPENGL_ES)
if (!makeContextCurrent())
return;
::glGetInternalformativ(target, internalformat, pname, data.bufSize, data.data);
#else
UNUSED_PARAM(target);
UNUSED_PARAM(internalformat);
UNUSED_PARAM(pname);
UNUSED_PARAM(bufSize);
UNUSED_PARAM(params);
#endif
}
void GraphicsContextGLOpenGL::renderbufferStorageMultisample(GCGLenum target, GCGLsizei samples, GCGLenum internalformat, GCGLsizei width, GCGLsizei height)
{
if (!makeContextCurrent())
return;
::glRenderbufferStorageMultisample(target, samples, internalformat, width, height);
}
void GraphicsContextGLOpenGL::texStorage2D(GCGLenum target, GCGLsizei levels, GCGLenum internalformat, GCGLsizei width, GCGLsizei height)
{
if (!makeContextCurrent())
return;
::glTexStorage2D(target, levels, internalformat, width, height);
}
void GraphicsContextGLOpenGL::texStorage3D(GCGLenum target, GCGLsizei levels, GCGLenum internalformat, GCGLsizei width, GCGLsizei height, GCGLsizei depth)
{
if (!makeContextCurrent())
return;
::glTexStorage3D(target, levels, internalformat, width, height, depth);
}
#else
void GraphicsContextGLOpenGL::getInternalformativ(GCGLenum, GCGLenum, GCGLenum, GCGLSpan<GCGLint>)
{
}
void GraphicsContextGLOpenGL::renderbufferStorageMultisample(GCGLenum, GCGLsizei, GCGLenum, GCGLsizei, GCGLsizei)
{
}
void GraphicsContextGLOpenGL::texStorage2D(GCGLenum, GCGLsizei, GCGLenum, GCGLsizei, GCGLsizei)
{
}
void GraphicsContextGLOpenGL::texStorage3D(GCGLenum, GCGLsizei, GCGLenum, GCGLsizei, GCGLsizei, GCGLsizei)
{
}
#endif
void GraphicsContextGLOpenGL::copyTexSubImage3D(GCGLenum target, GCGLint level, GCGLint xoffset, GCGLint yoffset, GCGLint zoffset, GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height)
{
UNUSED_PARAM(target);
UNUSED_PARAM(level);
UNUSED_PARAM(xoffset);
UNUSED_PARAM(yoffset);
UNUSED_PARAM(zoffset);
UNUSED_PARAM(x);
UNUSED_PARAM(y);
UNUSED_PARAM(width);
UNUSED_PARAM(height);
}
GCGLint GraphicsContextGLOpenGL::getFragDataLocation(PlatformGLObject program, const String& name)
{
UNUSED_PARAM(program);
UNUSED_PARAM(name);
return 0;
}
void GraphicsContextGLOpenGL::uniform1ui(GCGLint location, GCGLuint v0)
{
UNUSED_PARAM(location);
UNUSED_PARAM(v0);
}
void GraphicsContextGLOpenGL::uniform2ui(GCGLint location, GCGLuint v0, GCGLuint v1)
{
UNUSED_PARAM(location);
UNUSED_PARAM(v0);
UNUSED_PARAM(v1);
}
void GraphicsContextGLOpenGL::uniform3ui(GCGLint location, GCGLuint v0, GCGLuint v1, GCGLuint v2)
{
UNUSED_PARAM(location);
UNUSED_PARAM(v0);
UNUSED_PARAM(v1);
UNUSED_PARAM(v2);
}
void GraphicsContextGLOpenGL::uniform4ui(GCGLint location, GCGLuint v0, GCGLuint v1, GCGLuint v2, GCGLuint v3)
{
UNUSED_PARAM(location);
UNUSED_PARAM(v0);
UNUSED_PARAM(v1);
UNUSED_PARAM(v2);
UNUSED_PARAM(v3);
}
void GraphicsContextGLOpenGL::uniform1uiv(GCGLint location, GCGLSpan<const GCGLuint> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniform2uiv(GCGLint location, GCGLSpan<const GCGLuint> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniform3uiv(GCGLint location, GCGLSpan<const GCGLuint> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniform4uiv(GCGLint location, GCGLSpan<const GCGLuint> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniformMatrix2x3fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(transpose);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniformMatrix3x2fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(transpose);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniformMatrix2x4fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(transpose);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniformMatrix4x2fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(transpose);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniformMatrix3x4fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(transpose);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::uniformMatrix4x3fv(GCGLint location, GCGLboolean transpose, GCGLSpan<const GCGLfloat> data)
{
UNUSED_PARAM(location);
UNUSED_PARAM(transpose);
UNUSED_PARAM(data);
}
void GraphicsContextGLOpenGL::vertexAttribI4i(GCGLuint index, GCGLint x, GCGLint y, GCGLint z, GCGLint w)
{
UNUSED_PARAM(index);
UNUSED_PARAM(x);
UNUSED_PARAM(y);
UNUSED_PARAM(z);
UNUSED_PARAM(w);
}
void GraphicsContextGLOpenGL::vertexAttribI4iv(GCGLuint index, GCGLSpan<const GCGLint, 4> values)
{
UNUSED_PARAM(index);
UNUSED_PARAM(values);
}
void GraphicsContextGLOpenGL::vertexAttribI4ui(GCGLuint index, GCGLuint x, GCGLuint y, GCGLuint z, GCGLuint w)
{
UNUSED_PARAM(index);
UNUSED_PARAM(x);
UNUSED_PARAM(y);
UNUSED_PARAM(z);
UNUSED_PARAM(w);
}
void GraphicsContextGLOpenGL::vertexAttribI4uiv(GCGLuint index, GCGLSpan<const GCGLuint, 4> values)
{
UNUSED_PARAM(index);
UNUSED_PARAM(values);
}
void GraphicsContextGLOpenGL::vertexAttribIPointer(GCGLuint index, GCGLint size, GCGLenum type, GCGLsizei stride, GCGLintptr offset)
{
UNUSED_PARAM(index);
UNUSED_PARAM(size);
UNUSED_PARAM(type);
UNUSED_PARAM(stride);
UNUSED_PARAM(offset);
}
void GraphicsContextGLOpenGL::drawRangeElements(GCGLenum mode, GCGLuint start, GCGLuint end, GCGLsizei count, GCGLenum type, GCGLintptr offset)
{
UNUSED_PARAM(mode);
UNUSED_PARAM(start);
UNUSED_PARAM(end);
UNUSED_PARAM(count);
UNUSED_PARAM(type);
UNUSED_PARAM(offset);
}
void GraphicsContextGLOpenGL::drawBuffers(GCGLSpan<const GCGLenum> bufs)
{
UNUSED_PARAM(bufs);
}
void GraphicsContextGLOpenGL::clearBufferiv(GCGLenum buffer, GCGLint drawbuffer, GCGLSpan<const GCGLint> values)
{
UNUSED_PARAM(buffer);
UNUSED_PARAM(drawbuffer);
UNUSED_PARAM(values);
}
void GraphicsContextGLOpenGL::clearBufferuiv(GCGLenum buffer, GCGLint drawbuffer, GCGLSpan<const GCGLuint> values)
{
UNUSED_PARAM(buffer);
UNUSED_PARAM(drawbuffer);
UNUSED_PARAM(values);
}
void GraphicsContextGLOpenGL::clearBufferfv(GCGLenum buffer, GCGLint drawbuffer, GCGLSpan<const GCGLfloat> values)
{
UNUSED_PARAM(buffer);
UNUSED_PARAM(drawbuffer);
UNUSED_PARAM(values);
}
void GraphicsContextGLOpenGL::clearBufferfi(GCGLenum buffer, GCGLint drawbuffer, GCGLfloat depth, GCGLint stencil)
{
UNUSED_PARAM(buffer);
UNUSED_PARAM(drawbuffer);
UNUSED_PARAM(depth);
UNUSED_PARAM(stencil);
}
PlatformGLObject GraphicsContextGLOpenGL::createQuery()
{
return 0;
}
void GraphicsContextGLOpenGL::deleteQuery(PlatformGLObject query)
{
UNUSED_PARAM(query);
}
GCGLboolean GraphicsContextGLOpenGL::isQuery(PlatformGLObject query)
{
UNUSED_PARAM(query);
return false;
}
void GraphicsContextGLOpenGL::beginQuery(GCGLenum target, PlatformGLObject query)
{
UNUSED_PARAM(target);
UNUSED_PARAM(query);
}
void GraphicsContextGLOpenGL::endQuery(GCGLenum target)
{
UNUSED_PARAM(target);
}
PlatformGLObject GraphicsContextGLOpenGL::getQuery(GCGLenum target, GCGLenum pname)
{
UNUSED_PARAM(target);
UNUSED_PARAM(pname);
return 0;
}
GCGLuint GraphicsContextGLOpenGL::getQueryObjectui(PlatformGLObject query, GCGLenum pname)
{
UNUSED_PARAM(query);
UNUSED_PARAM(pname);
return 0;
}
PlatformGLObject GraphicsContextGLOpenGL::createSampler()
{
return 0;
}
void GraphicsContextGLOpenGL::deleteSampler(PlatformGLObject sampler)
{
UNUSED_PARAM(sampler);
}
GCGLboolean GraphicsContextGLOpenGL::isSampler(PlatformGLObject sampler)
{
UNUSED_PARAM(sampler);
return false;
}
void GraphicsContextGLOpenGL::bindSampler(GCGLuint unit, PlatformGLObject sampler)
{
UNUSED_PARAM(unit);
UNUSED_PARAM(sampler);
}
void GraphicsContextGLOpenGL::samplerParameteri(PlatformGLObject sampler, GCGLenum pname, GCGLint param)
{
UNUSED_PARAM(sampler);
UNUSED_PARAM(pname);
UNUSED_PARAM(param);
}
void GraphicsContextGLOpenGL::samplerParameterf(PlatformGLObject sampler, GCGLenum pname, GCGLfloat param)
{
UNUSED_PARAM(sampler);
UNUSED_PARAM(pname);
UNUSED_PARAM(param);
}
GCGLfloat GraphicsContextGLOpenGL::getSamplerParameterf(PlatformGLObject sampler, GCGLenum pname)
{
UNUSED_PARAM(sampler);
UNUSED_PARAM(pname);
return 0.f;
}
GCGLint GraphicsContextGLOpenGL::getSamplerParameteri(PlatformGLObject sampler, GCGLenum pname)
{
UNUSED_PARAM(sampler);
UNUSED_PARAM(pname);
return 0;
}
GCGLsync GraphicsContextGLOpenGL::fenceSync(GCGLenum condition, GCGLbitfield flags)
{
UNUSED_PARAM(condition);
UNUSED_PARAM(flags);
return 0;
}
GCGLboolean GraphicsContextGLOpenGL::isSync(GCGLsync sync)
{
UNUSED_PARAM(sync);
return false;
}
void GraphicsContextGLOpenGL::deleteSync(GCGLsync sync)
{
UNUSED_PARAM(sync);
}
GCGLenum GraphicsContextGLOpenGL::clientWaitSync(GCGLsync sync, GCGLbitfield flags, GCGLuint64 timeout)
{
UNUSED_PARAM(sync);
UNUSED_PARAM(flags);
UNUSED_PARAM(timeout);
return 0;
}
void GraphicsContextGLOpenGL::waitSync(GCGLsync sync, GCGLbitfield flags, GCGLint64 timeout)
{
UNUSED_PARAM(sync);
UNUSED_PARAM(flags);
UNUSED_PARAM(timeout);
}
GCGLint GraphicsContextGLOpenGL::getSynci(GCGLsync sync, GCGLenum pname)
{
UNUSED_PARAM(sync);
UNUSED_PARAM(pname);
return 0;
}
PlatformGLObject GraphicsContextGLOpenGL::createTransformFeedback()
{
return 0;
}
void GraphicsContextGLOpenGL::deleteTransformFeedback(PlatformGLObject id)
{
UNUSED_PARAM(id);
}
GCGLboolean GraphicsContextGLOpenGL::isTransformFeedback(PlatformGLObject id)
{
UNUSED_PARAM(id);
return false;
}
void GraphicsContextGLOpenGL::bindTransformFeedback(GCGLenum target, PlatformGLObject id)
{
UNUSED_PARAM(target);
UNUSED_PARAM(id);
}
void GraphicsContextGLOpenGL::beginTransformFeedback(GCGLenum primitiveMode)
{
UNUSED_PARAM(primitiveMode);
}
void GraphicsContextGLOpenGL::endTransformFeedback()
{
}
void GraphicsContextGLOpenGL::transformFeedbackVaryings(PlatformGLObject program, const Vector<String>& varyings, GCGLenum bufferMode)
{
UNUSED_PARAM(program);
UNUSED_PARAM(varyings);
UNUSED_PARAM(bufferMode);
}
void GraphicsContextGLOpenGL::getTransformFeedbackVarying(PlatformGLObject program, GCGLuint index, ActiveInfo&)
{
UNUSED_PARAM(program);
UNUSED_PARAM(index);
}
void GraphicsContextGLOpenGL::pauseTransformFeedback()
{
}
void GraphicsContextGLOpenGL::resumeTransformFeedback()
{
}
void GraphicsContextGLOpenGL::bindBufferBase(GCGLenum target, GCGLuint index, PlatformGLObject buffer)
{
UNUSED_PARAM(target);
UNUSED_PARAM(index);
UNUSED_PARAM(buffer);
}
void GraphicsContextGLOpenGL::bindBufferRange(GCGLenum target, GCGLuint index, PlatformGLObject buffer, GCGLintptr offset, GCGLsizeiptr size)
{
UNUSED_PARAM(target);
UNUSED_PARAM(index);
UNUSED_PARAM(buffer);
UNUSED_PARAM(offset);
UNUSED_PARAM(size);
}
Vector<GCGLuint> GraphicsContextGLOpenGL::getUniformIndices(PlatformGLObject program, const Vector<String>& uniformNames)
{
UNUSED_PARAM(program);
UNUSED_PARAM(uniformNames);
return { };
}
Vector<GCGLint> GraphicsContextGLOpenGL::getActiveUniforms(PlatformGLObject program, const Vector<GCGLuint>& uniformIndices, GCGLenum pname)
{
Vector<GCGLint> result(uniformIndices.size(), 0);
#if HAVE(OPENGL_4) || HAVE(OPENGL_ES_3)
ASSERT(program);
if (!makeContextCurrent())
return result;
::glGetActiveUniformsiv(program, uniformIndices.size(), uniformIndices.data(), pname, result.data());
#else
UNUSED_PARAM(program);
UNUSED_PARAM(pname);
#endif
return result;
}
GCGLuint GraphicsContextGLOpenGL::getUniformBlockIndex(PlatformGLObject program, const String& uniformBlockName)
{
UNUSED_PARAM(program);
UNUSED_PARAM(uniformBlockName);
return 0;
}
String GraphicsContextGLOpenGL::getActiveUniformBlockName(PlatformGLObject program, GCGLuint uniformBlockIndex)
{
UNUSED_PARAM(program);
UNUSED_PARAM(uniformBlockIndex);
return emptyString();
}
void GraphicsContextGLOpenGL::uniformBlockBinding(PlatformGLObject program, GCGLuint uniformBlockIndex, GCGLuint uniformBlockBinding)
{
UNUSED_PARAM(program);
UNUSED_PARAM(uniformBlockIndex);
UNUSED_PARAM(uniformBlockBinding);
}
void GraphicsContextGLOpenGL::readnPixels(GCGLint x, GCGLint y, GCGLsizei width, GCGLsizei height, GCGLenum format, GCGLenum type, GCGLintptr offset)
{
UNUSED_PARAM(x);
UNUSED_PARAM(y);
UNUSED_PARAM(width);
UNUSED_PARAM(height);
UNUSED_PARAM(format);
UNUSED_PARAM(type);
UNUSED_PARAM(offset);
}
void GraphicsContextGLOpenGL::getActiveUniformBlockiv(GCGLuint program, GCGLuint uniformBlockIndex, GCGLenum pname, GCGLSpan<GCGLint> params)
{
UNUSED_PARAM(program);
UNUSED_PARAM(uniformBlockIndex);
UNUSED_PARAM(pname);
UNUSED_PARAM(params);
}
void GraphicsContextGLOpenGL::texImage2D(GCGLenum, GCGLint, GCGLenum, GCGLsizei, GCGLsizei, GCGLint, GCGLenum, GCGLenum , GCGLintptr)
{
}
void GraphicsContextGLOpenGL::texSubImage2D(GCGLenum, GCGLint, GCGLint, GCGLint, GCGLsizei, GCGLsizei, GCGLenum, GCGLenum, GCGLintptr)
{
}
void GraphicsContextGLOpenGL::compressedTexImage2D(GCGLenum, GCGLint, GCGLenum, GCGLsizei, GCGLsizei, GCGLint, GCGLsizei, GCGLintptr)
{
}
void GraphicsContextGLOpenGL::compressedTexSubImage2D(GCGLenum, GCGLint, GCGLint, GCGLint, GCGLsizei, GCGLsizei, GCGLenum, GCGLsizei, GCGLintptr)
{
}
void GraphicsContextGLOpenGL::texImage3D(GCGLenum, GCGLint, GCGLint, GCGLsizei, GCGLsizei, GCGLsizei, GCGLint, GCGLenum, GCGLenum, GCGLSpan<const GCGLvoid>)
{
}
void GraphicsContextGLOpenGL::texImage3D(GCGLenum, GCGLint, GCGLint, GCGLsizei, GCGLsizei, GCGLsizei, GCGLint, GCGLenum, GCGLenum, GCGLintptr)
{
}
void GraphicsContextGLOpenGL::texSubImage3D(GCGLenum, GCGLint, GCGLint, GCGLint, GCGLint, GCGLsizei, GCGLsizei, GCGLsizei, GCGLenum, GCGLenum, GCGLSpan<const GCGLvoid>)
{
}
void GraphicsContextGLOpenGL::texSubImage3D(GCGLenum, GCGLint, GCGLint, GCGLint, GCGLint, GCGLsizei, GCGLsizei, GCGLsizei, GCGLenum, GCGLenum, GCGLintptr)
{
}
void GraphicsContextGLOpenGL::compressedTexImage3D(GCGLenum, GCGLint, GCGLenum, GCGLsizei, GCGLsizei, GCGLsizei, GCGLint, GCGLsizei, GCGLSpan<const GCGLvoid>)
{
}
void GraphicsContextGLOpenGL::compressedTexImage3D(GCGLenum, GCGLint, GCGLenum, GCGLsizei, GCGLsizei, GCGLsizei, GCGLint, GCGLsizei, GCGLintptr)
{
}
void GraphicsContextGLOpenGL::compressedTexSubImage3D(GCGLenum, GCGLint, GCGLint, GCGLint, GCGLint, GCGLsizei, GCGLsizei, GCGLsizei, GCGLenum, GCGLsizei, GCGLSpan<const GCGLvoid>)
{
}
void GraphicsContextGLOpenGL::compressedTexSubImage3D(GCGLenum, GCGLint, GCGLint, GCGLint, GCGLint, GCGLsizei, GCGLsizei, GCGLsizei, GCGLenum, GCGLsizei, GCGLintptr)
{
}
void GraphicsContextGLOpenGL::multiDrawArraysANGLE(GCGLenum, GCGLSpanTuple<const GCGLint, const GCGLsizei>)
{
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION);
}
void GraphicsContextGLOpenGL::multiDrawArraysInstancedANGLE(GCGLenum, GCGLSpanTuple<const GCGLint, const GCGLsizei, const GCGLsizei>)
{
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION);
}
void GraphicsContextGLOpenGL::multiDrawElementsANGLE(GCGLenum, GCGLSpanTuple<const GCGLsizei, const GCGLsizei>, GCGLenum)
{
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION);
}
void GraphicsContextGLOpenGL::multiDrawElementsInstancedANGLE(GCGLenum, GCGLSpanTuple<const GCGLsizei, const GCGLsizei, const GCGLsizei>, GCGLenum)
{
synthesizeGLError(GraphicsContextGL::INVALID_OPERATION);
}
bool GraphicsContextGLOpenGL::supportsExtension(const String& name)
{
return getExtensions().supports(name);
}
void GraphicsContextGLOpenGL::ensureExtensionEnabled(const String& name)
{
getExtensions().ensureEnabled(name);
}
bool GraphicsContextGLOpenGL::isExtensionEnabled(const String& name)
{
return getExtensions().isEnabled(name);
}
void GraphicsContextGLOpenGL::drawBuffersEXT(GCGLSpan<const GCGLenum> buffers)
{
return getExtensions().drawBuffersEXT(buffers);
}
String GraphicsContextGLOpenGL::getTranslatedShaderSourceANGLE(PlatformGLObject shader)
{
return getExtensions().getTranslatedShaderSourceANGLE(shader);
}
void GraphicsContextGLOpenGL::enableiOES(GCGLenum, GCGLuint)
{
}
void GraphicsContextGLOpenGL::disableiOES(GCGLenum, GCGLuint)
{
}
void GraphicsContextGLOpenGL::blendEquationiOES(GCGLuint, GCGLenum)
{
}
void GraphicsContextGLOpenGL::blendEquationSeparateiOES(GCGLuint, GCGLenum, GCGLenum)
{
}
void GraphicsContextGLOpenGL::blendFunciOES(GCGLuint, GCGLenum, GCGLenum)
{
}
void GraphicsContextGLOpenGL::blendFuncSeparateiOES(GCGLuint, GCGLenum, GCGLenum, GCGLenum, GCGLenum)
{
}
void GraphicsContextGLOpenGL::colorMaskiOES(GCGLuint, GCGLboolean, GCGLboolean, GCGLboolean, GCGLboolean)
{
}
bool GraphicsContextGLOpenGL::texImage2DResourceSafe(GCGLenum target, GCGLint level, GCGLenum internalformat, GCGLsizei width, GCGLsizei height, GCGLint border, GCGLenum format, GCGLenum type, GCGLint unpackAlignment)
{
ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8);
UniqueArray<unsigned char> zero;
unsigned size = 0;
if (width > 0 && height > 0) {
PixelStoreParams params;
params.alignment = unpackAlignment;
GCGLenum error = computeImageSizeInBytes(format, type, width, height, 1, params, &size, nullptr, nullptr);
if (error != GraphicsContextGL::NO_ERROR) {
synthesizeGLError(error);
return false;
}
zero = makeUniqueArray<unsigned char>(size);
if (!zero) {
synthesizeGLError(GraphicsContextGL::INVALID_VALUE);
return false;
}
memset(zero.get(), 0, size);
}
texImage2D(target, level, internalformat, width, height, border, format, type, makeGCGLSpan(zero.get(), size));
return true;
}
void GraphicsContextGLOpenGL::paintRenderingResultsToCanvas(ImageBuffer& imageBuffer)
{
if (!makeContextCurrent())
return;
if (getInternalFramebufferSize().isEmpty())
return;
auto pixelBuffer = readRenderingResults();
if (!pixelBuffer)
return;
paintToCanvas(contextAttributes(), pixelBuffer.releaseNonNull(), imageBuffer.backendSize(), imageBuffer.context());
}
void GraphicsContextGLOpenGL::paintCompositedResultsToCanvas(ImageBuffer& imageBuffer)
{
if (!makeContextCurrent())
return;
if (getInternalFramebufferSize().isEmpty())
return;
auto pixelBuffer = readCompositedResults();
if (!pixelBuffer)
return;
paintToCanvas(contextAttributes(), pixelBuffer.releaseNonNull(), imageBuffer.backendSize(), imageBuffer.context());
}
RefPtr<PixelBuffer> GraphicsContextGLOpenGL::paintRenderingResultsToPixelBuffer()
{
// Reading premultiplied alpha would involve unpremultiplying, which is lossy.
if (contextAttributes().premultipliedAlpha)
return nullptr;
auto results = readRenderingResultsForPainting();
if (results && !results->size().isEmpty()) {
ASSERT(results->format().pixelFormat == PixelFormat::RGBA8 || results->format().pixelFormat == PixelFormat::BGRA8);
// FIXME: Make PixelBufferConversions support negative rowBytes and in-place conversions.
const auto size = results->size();
const size_t rowStride = size.width() * 4;
uint8_t* top = results->bytes();
uint8_t* bottom = top + (size.height() - 1) * rowStride;
std::unique_ptr<uint8_t[]> temp(new uint8_t[rowStride]);
for (; top < bottom; top += rowStride, bottom -= rowStride) {
memcpy(temp.get(), bottom, rowStride);
memcpy(bottom, top, rowStride);
memcpy(top, temp.get(), rowStride);
}
}
return results;
}
RefPtr<PixelBuffer> GraphicsContextGLOpenGL::readRenderingResultsForPainting()
{
if (!makeContextCurrent())
return nullptr;
if (getInternalFramebufferSize().isEmpty())
return nullptr;
return readRenderingResults();
}
RefPtr<PixelBuffer> GraphicsContextGLOpenGL::readCompositedResultsForPainting()
{
if (!makeContextCurrent())
return nullptr;
if (getInternalFramebufferSize().isEmpty())
return nullptr;
return readCompositedResults();
}
}
#endif // ENABLE(WEBGL) && !USE(ANGLE)