/* * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT * OWNER 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" #if ENABLE(3D_CANVAS) #include #include #include "WebGraphicsContext3DDefaultImpl.h" #include "NotImplemented.h" #if OS(LINUX) #include #endif namespace WebKit { // Uncomment this to render to a separate window for debugging // #define RENDER_TO_DEBUGGING_WINDOW #if OS(DARWIN) #define USE_TEXTURE_RECTANGLE_FOR_FRAMEBUFFER #endif bool WebGraphicsContext3DDefaultImpl::s_initializedGLEW = false; #if OS(LINUX) WebGraphicsContext3DDefaultImpl::GLConnection* WebGraphicsContext3DDefaultImpl::s_gl = 0; WebGraphicsContext3DDefaultImpl::GLConnection* WebGraphicsContext3DDefaultImpl::GLConnection::create() { Display* dpy = XOpenDisplay(0); if (!dpy) { printf("GraphicsContext3D: error opening X display\n"); return 0; } // We use RTLD_GLOBAL semantics so that GLEW initialization works; // GLEW expects to be able to open the current process's handle // and do dlsym's of GL entry points from there. void* libGL = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); if (!libGL) { XCloseDisplay(dpy); printf("GraphicsContext3D: error opening libGL.so.1: %s\n", dlerror()); return 0; } PFNGLXCHOOSEFBCONFIGPROC chooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) dlsym(libGL, "glXChooseFBConfig"); PFNGLXCREATENEWCONTEXTPROC createNewContext = (PFNGLXCREATENEWCONTEXTPROC) dlsym(libGL, "glXCreateNewContext"); PFNGLXCREATEPBUFFERPROC createPbuffer = (PFNGLXCREATEPBUFFERPROC) dlsym(libGL, "glXCreatePbuffer"); PFNGLXDESTROYPBUFFERPROC destroyPbuffer = (PFNGLXDESTROYPBUFFERPROC) dlsym(libGL, "glXDestroyPbuffer"); PFNGLXMAKECURRENTPROC makeCurrent = (PFNGLXMAKECURRENTPROC) dlsym(libGL, "glXMakeCurrent"); PFNGLXDESTROYCONTEXTPROC destroyContext = (PFNGLXDESTROYCONTEXTPROC) dlsym(libGL, "glXDestroyContext"); PFNGLXGETCURRENTCONTEXTPROC getCurrentContext = (PFNGLXGETCURRENTCONTEXTPROC) dlsym(libGL, "glXGetCurrentContext"); if (!chooseFBConfig || !createNewContext || !createPbuffer || !destroyPbuffer || !makeCurrent || !destroyContext || !getCurrentContext) { XCloseDisplay(dpy); dlclose(libGL); printf("GraphicsContext3D: error looking up bootstrapping entry points\n"); return 0; } return new GLConnection(dpy, libGL, chooseFBConfig, createNewContext, createPbuffer, destroyPbuffer, makeCurrent, destroyContext, getCurrentContext); } WebGraphicsContext3DDefaultImpl::GLConnection::~GLConnection() { XCloseDisplay(m_display); dlclose(m_libGL); } #endif // OS(LINUX) WebGraphicsContext3DDefaultImpl::VertexAttribPointerState::VertexAttribPointerState() : enabled(false) , buffer(0) , indx(0) , size(0) , type(0) , normalized(false) , stride(0) , offset(0) { } WebGraphicsContext3DDefaultImpl::WebGraphicsContext3DDefaultImpl() : m_initialized(false) , m_texture(0) , m_fbo(0) , m_depthStencilBuffer(0) , m_multisampleFBO(0) , m_multisampleDepthStencilBuffer(0) , m_multisampleColorBuffer(0) , m_boundFBO(0) #ifdef FLIP_FRAMEBUFFER_VERTICALLY , m_scanline(0) #endif , m_boundArrayBuffer(0) #if OS(WINDOWS) , m_canvasWindow(0) , m_canvasDC(0) , m_contextObj(0) #elif PLATFORM(CG) , m_pbuffer(0) , m_contextObj(0) , m_renderOutput(0) #elif OS(LINUX) , m_contextObj(0) , m_pbuffer(0) #else #error Must port to your platform #endif { } WebGraphicsContext3DDefaultImpl::~WebGraphicsContext3DDefaultImpl() { if (m_initialized) { makeContextCurrent(); #ifndef RENDER_TO_DEBUGGING_WINDOW if (m_attributes.antialias) { glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer); if (m_attributes.depth || m_attributes.stencil) glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); glDeleteFramebuffersEXT(1, &m_multisampleFBO); } else { if (m_attributes.depth || m_attributes.stencil) glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer); } glDeleteTextures(1, &m_texture); #ifdef FLIP_FRAMEBUFFER_VERTICALLY if (m_scanline) delete[] m_scanline; #endif glDeleteFramebuffersEXT(1, &m_fbo); #endif // !RENDER_TO_DEBUGGING_WINDOW #if OS(WINDOWS) wglewMakeCurrent(0, 0); wglewDeleteContext(m_contextObj); ReleaseDC(m_canvasWindow, m_canvasDC); DestroyWindow(m_canvasWindow); #elif PLATFORM(CG) CGLSetCurrentContext(0); CGLDestroyContext(m_contextObj); CGLDestroyPBuffer(m_pbuffer); if (m_renderOutput) delete[] m_renderOutput; #elif OS(LINUX) s_gl->makeCurrent(0, 0); s_gl->destroyContext(m_contextObj); s_gl->destroyPbuffer(m_pbuffer); #else #error Must port to your platform #endif m_contextObj = 0; } } bool WebGraphicsContext3DDefaultImpl::initialize(WebGraphicsContext3D::Attributes attributes, WebView* webView) { #if OS(WINDOWS) if (!s_initializedGLEW) { // Do this only the first time through. if (!wglewInit()) { printf("WebGraphicsContext3DDefaultImpl: wglewInit failed\n"); return false; } } WNDCLASS wc; if (!GetClassInfo(GetModuleHandle(0), L"CANVASGL", &wc)) { ZeroMemory(&wc, sizeof(WNDCLASS)); wc.style = CS_OWNDC; wc.hInstance = GetModuleHandle(0); wc.lpfnWndProc = DefWindowProc; wc.lpszClassName = L"CANVASGL"; if (!RegisterClass(&wc)) { printf("WebGraphicsContext3DDefaultImpl: RegisterClass failed\n"); return false; } } m_canvasWindow = CreateWindow(L"CANVASGL", L"CANVASGL", WS_CAPTION, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0); if (!m_canvasWindow) { printf("WebGraphicsContext3DDefaultImpl: CreateWindow failed\n"); return false; } // get the device context m_canvasDC = GetDC(m_canvasWindow); if (!m_canvasDC) { printf("WebGraphicsContext3DDefaultImpl: GetDC failed\n"); return false; } // find default pixel format PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR)); pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; #ifdef RENDER_TO_DEBUGGING_WINDOW pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; #else pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; #endif int pixelformat = ChoosePixelFormat(m_canvasDC, &pfd); // set the pixel format for the dc if (!SetPixelFormat(m_canvasDC, pixelformat, &pfd)) { printf("WebGraphicsContext3DDefaultImpl: SetPixelFormat failed\n"); return false; } // create rendering context m_contextObj = wglewCreateContext(m_canvasDC); if (!m_contextObj) { printf("WebGraphicsContext3DDefaultImpl: wglCreateContext failed\n"); return false; } if (!wglewMakeCurrent(m_canvasDC, m_contextObj)) { printf("WebGraphicsContext3DDefaultImpl: wglMakeCurrent failed\n"); return false; } #ifdef RENDER_TO_DEBUGGING_WINDOW typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); PFNWGLSWAPINTERVALEXTPROC setSwapInterval = 0; setSwapInterval = (PFNWGLSWAPINTERVALEXTPROC) wglewGetProcAddress("wglSwapIntervalEXT"); if (setSwapInterval) setSwapInterval(1); #endif // RENDER_TO_DEBUGGING_WINDOW #elif PLATFORM(CG) // Create a 1x1 pbuffer and associated context to bootstrap things CGLPixelFormatAttribute attribs[] = { (CGLPixelFormatAttribute) kCGLPFAPBuffer, (CGLPixelFormatAttribute) 0 }; CGLPixelFormatObj pixelFormat; GLint numPixelFormats; if (CGLChoosePixelFormat(attribs, &pixelFormat, &numPixelFormats) != kCGLNoError) { printf("WebGraphicsContext3DDefaultImpl: error choosing pixel format\n"); return false; } if (!pixelFormat) { printf("WebGraphicsContext3DDefaultImpl: no pixel format selected\n"); return false; } CGLContextObj context; CGLError res = CGLCreateContext(pixelFormat, 0, &context); CGLDestroyPixelFormat(pixelFormat); if (res != kCGLNoError) { printf("WebGraphicsContext3DDefaultImpl: error creating context\n"); return false; } CGLPBufferObj pbuffer; if (CGLCreatePBuffer(1, 1, GL_TEXTURE_2D, GL_RGBA, 0, &pbuffer) != kCGLNoError) { CGLDestroyContext(context); printf("WebGraphicsContext3DDefaultImpl: error creating pbuffer\n"); return false; } if (CGLSetPBuffer(context, pbuffer, 0, 0, 0) != kCGLNoError) { CGLDestroyContext(context); CGLDestroyPBuffer(pbuffer); printf("WebGraphicsContext3DDefaultImpl: error attaching pbuffer to context\n"); return false; } if (CGLSetCurrentContext(context) != kCGLNoError) { CGLDestroyContext(context); CGLDestroyPBuffer(pbuffer); printf("WebGraphicsContext3DDefaultImpl: error making context current\n"); return false; } m_pbuffer = pbuffer; m_contextObj = context; #elif OS(LINUX) if (!s_gl) { s_gl = GLConnection::create(); if (!s_gl) return false; } int configAttrs[] = { GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DOUBLEBUFFER, 0, 0 }; int nelements = 0; GLXFBConfig* config = s_gl->chooseFBConfig(0, configAttrs, &nelements); if (!config) { printf("WebGraphicsContext3DDefaultImpl: glXChooseFBConfig failed\n"); return false; } if (!nelements) { printf("WebGraphicsContext3DDefaultImpl: glXChooseFBConfig returned 0 elements\n"); XFree(config); return false; } GLXContext context = s_gl->createNewContext(config[0], GLX_RGBA_TYPE, 0, True); if (!context) { printf("WebGraphicsContext3DDefaultImpl: glXCreateNewContext failed\n"); XFree(config); return false; } int pbufferAttrs[] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, 0 }; GLXPbuffer pbuffer = s_gl->createPbuffer(config[0], pbufferAttrs); XFree(config); if (!pbuffer) { printf("WebGraphicsContext3DDefaultImpl: glxCreatePbuffer failed\n"); return false; } if (!s_gl->makeCurrent(pbuffer, context)) { printf("WebGraphicsContext3DDefaultImpl: glXMakeCurrent failed\n"); return false; } m_contextObj = context; m_pbuffer = pbuffer; #else #error Must port to your platform #endif if (!s_initializedGLEW) { // Initialize GLEW and check for GL 2.0 support by the drivers. GLenum glewInitResult = glewInit(); if (glewInitResult != GLEW_OK) { printf("WebGraphicsContext3DDefaultImpl: GLEW initialization failed\n"); return false; } if (!glewIsSupported("GL_VERSION_2_0")) { printf("WebGraphicsContext3DDefaultImpl: OpenGL 2.0 not supported\n"); return false; } s_initializedGLEW = true; } m_attributes = attributes; validateAttributes(); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); m_initialized = true; return true; } void WebGraphicsContext3DDefaultImpl::validateAttributes() { const char* extensions = reinterpret_cast(glGetString(GL_EXTENSIONS)); if (m_attributes.stencil) { if (strstr(extensions, "GL_EXT_packed_depth_stencil")) { if (!m_attributes.depth) m_attributes.depth = true; } else m_attributes.stencil = false; } if (m_attributes.antialias) { bool isValidVendor = true; #if PLATFORM(CG) // Currently in Mac we only turn on antialias if vendor is NVIDIA. const char* vendor = reinterpret_cast(glGetString(GL_VENDOR)); if (!strstr(vendor, "NVIDIA")) isValidVendor = false; #endif if (!isValidVendor || !strstr(extensions, "GL_EXT_framebuffer_multisample")) m_attributes.antialias = false; } // FIXME: instead of enforcing premultipliedAlpha = true, implement the // correct behavior when premultipliedAlpha = false is requested. m_attributes.premultipliedAlpha = true; } bool WebGraphicsContext3DDefaultImpl::makeContextCurrent() { #if OS(WINDOWS) if (wglewGetCurrentContext() != m_contextObj) if (wglewMakeCurrent(m_canvasDC, m_contextObj)) return true; #elif PLATFORM(CG) if (CGLGetCurrentContext() != m_contextObj) if (CGLSetCurrentContext(m_contextObj) == kCGLNoError) return true; #elif OS(LINUX) if (s_gl->getCurrentContext() != m_contextObj) if (s_gl->makeCurrent(m_pbuffer, m_contextObj)) return true; #else #error Must port to your platform #endif return false; } int WebGraphicsContext3DDefaultImpl::width() { return m_cachedWidth; } int WebGraphicsContext3DDefaultImpl::height() { return m_cachedHeight; } int WebGraphicsContext3DDefaultImpl::sizeInBytes(int type) { switch (type) { case GL_BYTE: return sizeof(GLbyte); case GL_UNSIGNED_BYTE: return sizeof(GLubyte); case GL_SHORT: return sizeof(GLshort); case GL_UNSIGNED_SHORT: return sizeof(GLushort); case GL_INT: return sizeof(GLint); case GL_UNSIGNED_INT: return sizeof(GLuint); case GL_FLOAT: return sizeof(GLfloat); } return 0; } bool WebGraphicsContext3DDefaultImpl::isGLES2Compliant() { return false; } unsigned int WebGraphicsContext3DDefaultImpl::getPlatformTextureId() { ASSERT_NOT_REACHED(); return 0; } void WebGraphicsContext3DDefaultImpl::prepareTexture() { ASSERT_NOT_REACHED(); } static int createTextureObject(GLenum target) { GLuint texture = 0; glGenTextures(1, &texture); glBindTexture(target, texture); glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); return texture; } void WebGraphicsContext3DDefaultImpl::reshape(int width, int height) { #ifdef RENDER_TO_DEBUGGING_WINDOW SetWindowPos(m_canvasWindow, HWND_TOP, 0, 0, width, height, SWP_NOMOVE); ShowWindow(m_canvasWindow, SW_SHOW); #endif m_cachedWidth = width; m_cachedHeight = height; makeContextCurrent(); #ifndef RENDER_TO_DEBUGGING_WINDOW #ifdef USE_TEXTURE_RECTANGLE_FOR_FRAMEBUFFER // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on Mac OS X GLenum target = GL_TEXTURE_RECTANGLE_ARB; #else GLenum target = GL_TEXTURE_2D; #endif if (!m_texture) { // Generate the texture object m_texture = createTextureObject(target); // Generate the framebuffer object glGenFramebuffersEXT(1, &m_fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); m_boundFBO = m_fbo; if (m_attributes.depth || m_attributes.stencil) glGenRenderbuffersEXT(1, &m_depthStencilBuffer); // Generate the multisample framebuffer object if (m_attributes.antialias) { glGenFramebuffersEXT(1, &m_multisampleFBO); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); m_boundFBO = m_multisampleFBO; glGenRenderbuffersEXT(1, &m_multisampleColorBuffer); if (m_attributes.depth || m_attributes.stencil) glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); } } GLint internalColorFormat, colorFormat, internalDepthStencilFormat = 0; if (m_attributes.alpha) { internalColorFormat = GL_RGBA8; colorFormat = GL_RGBA; } else { internalColorFormat = GL_RGB8; colorFormat = GL_RGB; } if (m_attributes.stencil || m_attributes.depth) { // We don't allow the logic where stencil is required and depth is not. // See GraphicsContext3DInternal constructor. if (m_attributes.stencil && m_attributes.depth) internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT; else internalDepthStencilFormat = GL_DEPTH_COMPONENT; } bool mustRestoreFBO = false; // Resize multisampling FBO if (m_attributes.antialias) { GLint maxSampleCount; glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount); GLint sampleCount = std::min(8, maxSampleCount); if (m_boundFBO != m_multisampleFBO) { mustRestoreFBO = true; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); } glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalColorFormat, width, height); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); if (m_attributes.stencil || m_attributes.depth) { glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height); if (m_attributes.stencil) glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); if (m_attributes.depth) glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); } glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { printf("GraphicsContext3D: multisampling framebuffer was incomplete\n"); // FIXME: cleanup. notImplemented(); } } // Resize regular FBO if (m_boundFBO != m_fbo) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); mustRestoreFBO = true; } glBindTexture(target, m_texture); glTexImage2D(target, 0, internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, m_texture, 0); glBindTexture(target, 0); if (!m_attributes.antialias && (m_attributes.stencil || m_attributes.depth)) { glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height); if (m_attributes.stencil) glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); if (m_attributes.depth) glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { printf("WebGraphicsContext3DDefaultImpl: framebuffer was incomplete\n"); // FIXME: cleanup. notImplemented(); } if (m_attributes.antialias) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); if (m_boundFBO == m_multisampleFBO) mustRestoreFBO = false; } // Initialize renderbuffers to 0. GLboolean colorMask[] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}, depthMask = GL_TRUE, stencilMask = GL_TRUE; GLboolean isScissorEnabled = GL_FALSE; GLboolean isDitherEnabled = GL_FALSE; GLbitfield clearMask = GL_COLOR_BUFFER_BIT; glGetBooleanv(GL_COLOR_WRITEMASK, colorMask); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); if (m_attributes.depth) { glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask); glDepthMask(GL_TRUE); clearMask |= GL_DEPTH_BUFFER_BIT; } if (m_attributes.stencil) { glGetBooleanv(GL_STENCIL_WRITEMASK, &stencilMask); glStencilMask(GL_TRUE); clearMask |= GL_STENCIL_BUFFER_BIT; } isScissorEnabled = glIsEnabled(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST); isDitherEnabled = glIsEnabled(GL_DITHER); glDisable(GL_DITHER); glClear(clearMask); glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); if (m_attributes.depth) glDepthMask(depthMask); if (m_attributes.stencil) glStencilMask(stencilMask); if (isScissorEnabled) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); if (isDitherEnabled) glEnable(GL_DITHER); else glDisable(GL_DITHER); if (mustRestoreFBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); #endif // RENDER_TO_DEBUGGING_WINDOW #ifdef FLIP_FRAMEBUFFER_VERTICALLY if (m_scanline) { delete[] m_scanline; m_scanline = 0; } m_scanline = new unsigned char[width * 4]; #endif // FLIP_FRAMEBUFFER_VERTICALLY } #ifdef FLIP_FRAMEBUFFER_VERTICALLY void WebGraphicsContext3DDefaultImpl::flipVertically(unsigned char* framebuffer, unsigned int width, unsigned int height) { unsigned char* scanline = m_scanline; if (!scanline) return; unsigned int rowBytes = width * 4; unsigned int count = height / 2; for (unsigned int i = 0; i < count; i++) { unsigned char* rowA = framebuffer + i * rowBytes; unsigned char* rowB = framebuffer + (height - i - 1) * rowBytes; // FIXME: this is where the multiplication of the alpha // channel into the color buffer will need to occur if the // user specifies the "premultiplyAlpha" flag in the context // creation attributes. memcpy(scanline, rowB, rowBytes); memcpy(rowB, rowA, rowBytes); memcpy(rowA, scanline, rowBytes); } } #endif bool WebGraphicsContext3DDefaultImpl::readBackFramebuffer(unsigned char* pixels, size_t bufferSize) { if (bufferSize != static_cast(4 * width() * height())) return false; makeContextCurrent(); #ifdef RENDER_TO_DEBUGGING_WINDOW SwapBuffers(m_canvasDC); #else // Earlier versions of this code used the GPU to flip the // framebuffer vertically before reading it back for compositing // via software. This code was quite complicated, used a lot of // GPU memory, and didn't provide an obvious speedup. Since this // vertical flip is only a temporary solution anyway until Chrome // is fully GPU composited, it wasn't worth the complexity. bool mustRestoreFBO; if (m_attributes.antialias) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); glBlitFramebufferEXT(0, 0, m_cachedWidth, m_cachedHeight, 0, 0, m_cachedWidth, m_cachedHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); mustRestoreFBO = true; } else { if (m_boundFBO != m_fbo) { mustRestoreFBO = true; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); } } GLint packAlignment = 4; bool mustRestorePackAlignment = false; glGetIntegerv(GL_PACK_ALIGNMENT, &packAlignment); if (packAlignment > 4) { glPixelStorei(GL_PACK_ALIGNMENT, 4); mustRestorePackAlignment = true; } #if PLATFORM(SKIA) glReadPixels(0, 0, m_cachedWidth, m_cachedHeight, GL_BGRA, GL_UNSIGNED_BYTE, pixels); #elif PLATFORM(CG) glReadPixels(0, 0, m_cachedWidth, m_cachedHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); #else #error Must port to your platform #endif if (mustRestorePackAlignment) glPixelStorei(GL_PACK_ALIGNMENT, packAlignment); if (mustRestoreFBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); #ifdef FLIP_FRAMEBUFFER_VERTICALLY if (pixels) flipVertically(pixels, m_cachedWidth, m_cachedHeight); #endif #endif // RENDER_TO_DEBUGGING_WINDOW return true; } void WebGraphicsContext3DDefaultImpl::synthesizeGLError(unsigned long error) { m_syntheticErrors.add(error); } // Helper macros to reduce the amount of code. #define DELEGATE_TO_GL(name, glname) \ void WebGraphicsContext3DDefaultImpl::name() \ { \ makeContextCurrent(); \ gl##glname(); \ } #define DELEGATE_TO_GL_1(name, glname, t1) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1) \ { \ makeContextCurrent(); \ gl##glname(a1); \ } #define DELEGATE_TO_GL_1R(name, glname, t1, rt) \ rt WebGraphicsContext3DDefaultImpl::name(t1 a1) \ { \ makeContextCurrent(); \ return gl##glname(a1); \ } #define DELEGATE_TO_GL_2(name, glname, t1, t2) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2) \ { \ makeContextCurrent(); \ gl##glname(a1, a2); \ } #define DELEGATE_TO_GL_2R(name, glname, t1, t2, rt) \ rt WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2) \ { \ makeContextCurrent(); \ return gl##glname(a1, a2); \ } #define DELEGATE_TO_GL_3(name, glname, t1, t2, t3) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2, t3 a3) \ { \ makeContextCurrent(); \ gl##glname(a1, a2, a3); \ } #define DELEGATE_TO_GL_4(name, glname, t1, t2, t3, t4) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2, t3 a3, t4 a4) \ { \ makeContextCurrent(); \ gl##glname(a1, a2, a3, a4); \ } #define DELEGATE_TO_GL_5(name, glname, t1, t2, t3, t4, t5) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \ { \ makeContextCurrent(); \ gl##glname(a1, a2, a3, a4, a5); \ } #define DELEGATE_TO_GL_6(name, glname, t1, t2, t3, t4, t5, t6) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) \ { \ makeContextCurrent(); \ gl##glname(a1, a2, a3, a4, a5, a6); \ } #define DELEGATE_TO_GL_7(name, glname, t1, t2, t3, t4, t5, t6, t7) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7) \ { \ makeContextCurrent(); \ gl##glname(a1, a2, a3, a4, a5, a6, a7); \ } #define DELEGATE_TO_GL_8(name, glname, t1, t2, t3, t4, t5, t6, t7, t8) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8) \ { \ makeContextCurrent(); \ gl##glname(a1, a2, a3, a4, a5, a6, a7, a8); \ } #define DELEGATE_TO_GL_9(name, glname, t1, t2, t3, t4, t5, t6, t7, t8, t9) \ void WebGraphicsContext3DDefaultImpl::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8, t9 a9) \ { \ makeContextCurrent(); \ gl##glname(a1, a2, a3, a4, a5, a6, a7, a8, a9); \ } void WebGraphicsContext3DDefaultImpl::activeTexture(unsigned long texture) { // FIXME: query number of textures available. if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0+32) // FIXME: raise exception. return; makeContextCurrent(); glActiveTexture(texture); } DELEGATE_TO_GL_2(attachShader, AttachShader, WebGLId, WebGLId) DELEGATE_TO_GL_3(bindAttribLocation, BindAttribLocation, WebGLId, unsigned long, const char*) void WebGraphicsContext3DDefaultImpl::bindBuffer(unsigned long target, WebGLId buffer) { makeContextCurrent(); if (target == GL_ARRAY_BUFFER) m_boundArrayBuffer = buffer; glBindBuffer(target, buffer); } void WebGraphicsContext3DDefaultImpl::bindFramebuffer(unsigned long target, WebGLId framebuffer) { makeContextCurrent(); if (!framebuffer) framebuffer = (m_attributes.antialias ? m_multisampleFBO : m_fbo); if (framebuffer != m_boundFBO) { glBindFramebufferEXT(target, framebuffer); m_boundFBO = framebuffer; } } DELEGATE_TO_GL_2(bindRenderbuffer, BindRenderbufferEXT, unsigned long, WebGLId) DELEGATE_TO_GL_2(bindTexture, BindTexture, unsigned long, WebGLId) DELEGATE_TO_GL_4(blendColor, BlendColor, double, double, double, double) DELEGATE_TO_GL_1(blendEquation, BlendEquation, unsigned long) DELEGATE_TO_GL_2(blendEquationSeparate, BlendEquationSeparate, unsigned long, unsigned long) DELEGATE_TO_GL_2(blendFunc, BlendFunc, unsigned long, unsigned long) DELEGATE_TO_GL_4(blendFuncSeparate, BlendFuncSeparate, unsigned long, unsigned long, unsigned long, unsigned long) DELEGATE_TO_GL_4(bufferData, BufferData, unsigned long, int, const void*, unsigned long) DELEGATE_TO_GL_4(bufferSubData, BufferSubData, unsigned long, long, int, const void*) DELEGATE_TO_GL_1R(checkFramebufferStatus, CheckFramebufferStatusEXT, unsigned long, unsigned long) DELEGATE_TO_GL_1(clear, Clear, unsigned long) DELEGATE_TO_GL_4(clearColor, ClearColor, double, double, double, double) DELEGATE_TO_GL_1(clearDepth, ClearDepth, double) DELEGATE_TO_GL_1(clearStencil, ClearStencil, long) DELEGATE_TO_GL_4(colorMask, ColorMask, bool, bool, bool, bool) DELEGATE_TO_GL_1(compileShader, CompileShader, WebGLId) void WebGraphicsContext3DDefaultImpl::copyTexImage2D(unsigned long target, long level, unsigned long internalformat, long x, long y, unsigned long width, unsigned long height, long border) { makeContextCurrent(); #ifndef RENDER_TO_DEBUGGING_WINDOW if (m_attributes.antialias && m_boundFBO == m_multisampleFBO) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); } #endif glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); #ifndef RENDER_TO_DEBUGGING_WINDOW if (m_attributes.antialias && m_boundFBO == m_multisampleFBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); #endif } void WebGraphicsContext3DDefaultImpl::copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, unsigned long width, unsigned long height) { makeContextCurrent(); #ifndef RENDER_TO_DEBUGGING_WINDOW if (m_attributes.antialias && m_boundFBO == m_multisampleFBO) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); } #endif glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); #ifndef RENDER_TO_DEBUGGING_WINDOW if (m_attributes.antialias && m_boundFBO == m_multisampleFBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); #endif } DELEGATE_TO_GL_1(cullFace, CullFace, unsigned long) DELEGATE_TO_GL_1(depthFunc, DepthFunc, unsigned long) DELEGATE_TO_GL_1(depthMask, DepthMask, bool) DELEGATE_TO_GL_2(depthRange, DepthRange, double, double) DELEGATE_TO_GL_2(detachShader, DetachShader, WebGLId, WebGLId) DELEGATE_TO_GL_1(disable, Disable, unsigned long) void WebGraphicsContext3DDefaultImpl::disableVertexAttribArray(unsigned long index) { makeContextCurrent(); if (index < NumTrackedPointerStates) m_vertexAttribPointerState[index].enabled = false; glDisableVertexAttribArray(index); } DELEGATE_TO_GL_3(drawArrays, DrawArrays, unsigned long, long, long) void WebGraphicsContext3DDefaultImpl::drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset) { makeContextCurrent(); glDrawElements(mode, count, type, reinterpret_cast(static_cast(offset))); } DELEGATE_TO_GL_1(enable, Enable, unsigned long) void WebGraphicsContext3DDefaultImpl::enableVertexAttribArray(unsigned long index) { makeContextCurrent(); if (index < NumTrackedPointerStates) m_vertexAttribPointerState[index].enabled = true; glEnableVertexAttribArray(index); } DELEGATE_TO_GL(finish, Finish) DELEGATE_TO_GL(flush, Flush) void WebGraphicsContext3DDefaultImpl::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLId buffer) { makeContextCurrent(); if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { glFramebufferRenderbufferEXT(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, buffer); glFramebufferRenderbufferEXT(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, buffer); } else glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer); } DELEGATE_TO_GL_5(framebufferTexture2D, FramebufferTexture2DEXT, unsigned long, unsigned long, unsigned long, WebGLId, long) DELEGATE_TO_GL_1(frontFace, FrontFace, unsigned long) void WebGraphicsContext3DDefaultImpl::generateMipmap(unsigned long target) { makeContextCurrent(); if (glGenerateMipmapEXT) glGenerateMipmapEXT(target); // FIXME: provide alternative code path? This will be unpleasant // to implement if glGenerateMipmapEXT is not available -- it will // require a texture readback and re-upload. } bool WebGraphicsContext3DDefaultImpl::getActiveAttrib(WebGLId program, unsigned long index, ActiveInfo& info) { makeContextCurrent(); if (!program) { synthesizeGLError(GL_INVALID_VALUE); return false; } GLint maxNameLength = -1; glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength); if (maxNameLength < 0) return false; GLchar* name = 0; if (!tryFastMalloc(maxNameLength * sizeof(GLchar)).getValue(name)) { synthesizeGLError(GL_OUT_OF_MEMORY); return false; } GLsizei length = 0; GLint size = -1; GLenum type = 0; glGetActiveAttrib(program, index, maxNameLength, &length, &size, &type, name); if (size < 0) { fastFree(name); return false; } info.name = WebString::fromUTF8(name, length); info.type = type; info.size = size; fastFree(name); return true; } bool WebGraphicsContext3DDefaultImpl::getActiveUniform(WebGLId program, unsigned long index, ActiveInfo& info) { makeContextCurrent(); GLint maxNameLength = -1; glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); if (maxNameLength < 0) return false; GLchar* name = 0; if (!tryFastMalloc(maxNameLength * sizeof(GLchar)).getValue(name)) { synthesizeGLError(GL_OUT_OF_MEMORY); return false; } GLsizei length = 0; GLint size = -1; GLenum type = 0; glGetActiveUniform(program, index, maxNameLength, &length, &size, &type, name); if (size < 0) { fastFree(name); return false; } info.name = WebString::fromUTF8(name, length); info.type = type; info.size = size; fastFree(name); return true; } DELEGATE_TO_GL_4(getAttachedShaders, GetAttachedShaders, WebGLId, int, int*, unsigned int*) DELEGATE_TO_GL_2R(getAttribLocation, GetAttribLocation, WebGLId, const char*, int) DELEGATE_TO_GL_2(getBooleanv, GetBooleanv, unsigned long, unsigned char*) DELEGATE_TO_GL_3(getBufferParameteriv, GetBufferParameteriv, unsigned long, unsigned long, int*) WebGraphicsContext3D::Attributes WebGraphicsContext3DDefaultImpl::getContextAttributes() { return m_attributes; } unsigned long WebGraphicsContext3DDefaultImpl::getError() { if (m_syntheticErrors.size() > 0) { ListHashSet::iterator iter = m_syntheticErrors.begin(); unsigned long err = *iter; m_syntheticErrors.remove(iter); return err; } makeContextCurrent(); return glGetError(); } DELEGATE_TO_GL_2(getFloatv, GetFloatv, unsigned long, float*) void WebGraphicsContext3DDefaultImpl::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value) { makeContextCurrent(); if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) attachment = GL_DEPTH_ATTACHMENT; // Or GL_STENCIL_ATTACHMENT, either works. glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value); } void WebGraphicsContext3DDefaultImpl::getIntegerv(unsigned long pname, int* value) { // Need to emulate IMPLEMENTATION_COLOR_READ_FORMAT/TYPE for GL. Any valid // combination should work, but GL_RGB/GL_UNSIGNED_BYTE might be the most // useful for desktop WebGL users. makeContextCurrent(); switch (pname) { case 0x8B9B: // IMPLEMENTATION_COLOR_READ_FORMAT *value = GL_RGB; break; case 0x8B9A: // IMPLEMENTATION_COLOR_READ_TYPE *value = GL_UNSIGNED_BYTE; break; default: glGetIntegerv(pname, value); } } DELEGATE_TO_GL_3(getProgramiv, GetProgramiv, WebGLId, unsigned long, int*) WebString WebGraphicsContext3DDefaultImpl::getProgramInfoLog(WebGLId program) { makeContextCurrent(); GLint logLength; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength); if (!logLength) return WebString(); GLchar* log = 0; if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log)) return WebString(); GLsizei returnedLogLength; glGetProgramInfoLog(program, logLength, &returnedLogLength, log); ASSERT(logLength == returnedLogLength + 1); WebString res = WebString::fromUTF8(log, returnedLogLength); fastFree(log); return res; } DELEGATE_TO_GL_3(getRenderbufferParameteriv, GetRenderbufferParameterivEXT, unsigned long, unsigned long, int*) DELEGATE_TO_GL_3(getShaderiv, GetShaderiv, WebGLId, unsigned long, int*) WebString WebGraphicsContext3DDefaultImpl::getShaderInfoLog(WebGLId shader) { makeContextCurrent(); GLint logLength; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); if (!logLength) return WebString(); GLchar* log = 0; if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log)) return WebString(); GLsizei returnedLogLength; glGetShaderInfoLog(shader, logLength, &returnedLogLength, log); ASSERT(logLength == returnedLogLength + 1); WebString res = WebString::fromUTF8(log, returnedLogLength); fastFree(log); return res; } WebString WebGraphicsContext3DDefaultImpl::getShaderSource(WebGLId shader) { makeContextCurrent(); GLint logLength; glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &logLength); if (!logLength) return WebString(); GLchar* log = 0; if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log)) return WebString(); GLsizei returnedLogLength; glGetShaderSource(shader, logLength, &returnedLogLength, log); ASSERT(logLength == returnedLogLength + 1); WebString res = WebString::fromUTF8(log, returnedLogLength); fastFree(log); return res; } WebString WebGraphicsContext3DDefaultImpl::getString(unsigned long name) { makeContextCurrent(); return WebString::fromUTF8(reinterpret_cast(glGetString(name))); } DELEGATE_TO_GL_3(getTexParameterfv, GetTexParameterfv, unsigned long, unsigned long, float*) DELEGATE_TO_GL_3(getTexParameteriv, GetTexParameteriv, unsigned long, unsigned long, int*) DELEGATE_TO_GL_3(getUniformfv, GetUniformfv, WebGLId, long, float*) DELEGATE_TO_GL_3(getUniformiv, GetUniformiv, WebGLId, long, int*) DELEGATE_TO_GL_2R(getUniformLocation, GetUniformLocation, WebGLId, const char*, long) DELEGATE_TO_GL_3(getVertexAttribfv, GetVertexAttribfv, unsigned long, unsigned long, float*) DELEGATE_TO_GL_3(getVertexAttribiv, GetVertexAttribiv, unsigned long, unsigned long, int*) long WebGraphicsContext3DDefaultImpl::getVertexAttribOffset(unsigned long index, unsigned long pname) { // FIXME: implement. notImplemented(); return 0; } DELEGATE_TO_GL_2(hint, Hint, unsigned long, unsigned long) DELEGATE_TO_GL_1R(isBuffer, IsBuffer, WebGLId, bool) DELEGATE_TO_GL_1R(isEnabled, IsEnabled, unsigned long, bool) DELEGATE_TO_GL_1R(isFramebuffer, IsFramebuffer, WebGLId, bool) DELEGATE_TO_GL_1R(isProgram, IsProgram, WebGLId, bool) DELEGATE_TO_GL_1R(isRenderbuffer, IsRenderbuffer, WebGLId, bool) DELEGATE_TO_GL_1R(isShader, IsShader, WebGLId, bool) DELEGATE_TO_GL_1R(isTexture, IsTexture, WebGLId, bool) DELEGATE_TO_GL_1(lineWidth, LineWidth, double) DELEGATE_TO_GL_1(linkProgram, LinkProgram, WebGLId) DELEGATE_TO_GL_2(pixelStorei, PixelStorei, unsigned long, long) DELEGATE_TO_GL_2(polygonOffset, PolygonOffset, double, double) void WebGraphicsContext3DDefaultImpl::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* pixels) { makeContextCurrent(); // 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(); #ifndef RENDER_TO_DEBUGGING_WINDOW if (m_attributes.antialias && m_boundFBO == m_multisampleFBO) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_LINEAR); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); glFlush(); } #endif glReadPixels(x, y, width, height, format, type, pixels); #ifndef RENDER_TO_DEBUGGING_WINDOW if (m_attributes.antialias && m_boundFBO == m_multisampleFBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO); #endif } void WebGraphicsContext3DDefaultImpl::releaseShaderCompiler() { } void WebGraphicsContext3DDefaultImpl::renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height) { makeContextCurrent(); switch (internalformat) { case GL_DEPTH_STENCIL: internalformat = GL_DEPTH24_STENCIL8_EXT; break; case GL_DEPTH_COMPONENT16: internalformat = GL_DEPTH_COMPONENT; break; case GL_RGBA4: case GL_RGB5_A1: internalformat = GL_RGBA; break; case 0x8D62: // GL_RGB565 internalformat = GL_RGB; break; } glRenderbufferStorageEXT(target, internalformat, width, height); } DELEGATE_TO_GL_2(sampleCoverage, SampleCoverage, double, bool) DELEGATE_TO_GL_4(scissor, Scissor, long, long, unsigned long, unsigned long) void WebGraphicsContext3DDefaultImpl::shaderSource(WebGLId shader, const char* string) { makeContextCurrent(); GLint length = strlen(string); glShaderSource(shader, 1, &string, &length); } DELEGATE_TO_GL_3(stencilFunc, StencilFunc, unsigned long, long, unsigned long) DELEGATE_TO_GL_4(stencilFuncSeparate, StencilFuncSeparate, unsigned long, unsigned long, long, unsigned long) DELEGATE_TO_GL_1(stencilMask, StencilMask, unsigned long) DELEGATE_TO_GL_2(stencilMaskSeparate, StencilMaskSeparate, unsigned long, unsigned long) DELEGATE_TO_GL_3(stencilOp, StencilOp, unsigned long, unsigned long, unsigned long) DELEGATE_TO_GL_4(stencilOpSeparate, StencilOpSeparate, unsigned long, unsigned long, unsigned long, unsigned long) DELEGATE_TO_GL_9(texImage2D, TexImage2D, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, const void*) DELEGATE_TO_GL_3(texParameterf, TexParameterf, unsigned, unsigned, float); DELEGATE_TO_GL_3(texParameteri, TexParameteri, unsigned, unsigned, int); DELEGATE_TO_GL_9(texSubImage2D, TexSubImage2D, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, const void*) DELEGATE_TO_GL_2(uniform1f, Uniform1f, long, float) DELEGATE_TO_GL_3(uniform1fv, Uniform1fv, long, int, float*) DELEGATE_TO_GL_2(uniform1i, Uniform1i, long, int) DELEGATE_TO_GL_3(uniform1iv, Uniform1iv, long, int, int*) DELEGATE_TO_GL_3(uniform2f, Uniform2f, long, float, float) DELEGATE_TO_GL_3(uniform2fv, Uniform2fv, long, int, float*) DELEGATE_TO_GL_3(uniform2i, Uniform2i, long, int, int) DELEGATE_TO_GL_3(uniform2iv, Uniform2iv, long, int, int*) DELEGATE_TO_GL_4(uniform3f, Uniform3f, long, float, float, float) DELEGATE_TO_GL_3(uniform3fv, Uniform3fv, long, int, float*) DELEGATE_TO_GL_4(uniform3i, Uniform3i, long, int, int, int) DELEGATE_TO_GL_3(uniform3iv, Uniform3iv, long, int, int*) DELEGATE_TO_GL_5(uniform4f, Uniform4f, long, float, float, float, float) DELEGATE_TO_GL_3(uniform4fv, Uniform4fv, long, int, float*) DELEGATE_TO_GL_5(uniform4i, Uniform4i, long, int, int, int, int) DELEGATE_TO_GL_3(uniform4iv, Uniform4iv, long, int, int*) DELEGATE_TO_GL_4(uniformMatrix2fv, UniformMatrix2fv, long, int, bool, const float*) DELEGATE_TO_GL_4(uniformMatrix3fv, UniformMatrix3fv, long, int, bool, const float*) DELEGATE_TO_GL_4(uniformMatrix4fv, UniformMatrix4fv, long, int, bool, const float*) DELEGATE_TO_GL_1(useProgram, UseProgram, WebGLId) DELEGATE_TO_GL_1(validateProgram, ValidateProgram, WebGLId) DELEGATE_TO_GL_2(vertexAttrib1f, VertexAttrib1f, unsigned long, float) DELEGATE_TO_GL_2(vertexAttrib1fv, VertexAttrib1fv, unsigned long, const float*) DELEGATE_TO_GL_3(vertexAttrib2f, VertexAttrib2f, unsigned long, float, float) DELEGATE_TO_GL_2(vertexAttrib2fv, VertexAttrib2fv, unsigned long, const float*) DELEGATE_TO_GL_4(vertexAttrib3f, VertexAttrib3f, unsigned long, float, float, float) DELEGATE_TO_GL_2(vertexAttrib3fv, VertexAttrib3fv, unsigned long, const float*) DELEGATE_TO_GL_5(vertexAttrib4f, VertexAttrib4f, unsigned long, float, float, float, float) DELEGATE_TO_GL_2(vertexAttrib4fv, VertexAttrib4fv, unsigned long, const float*) void WebGraphicsContext3DDefaultImpl::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, unsigned long stride, unsigned long offset) { makeContextCurrent(); if (m_boundArrayBuffer <= 0) { // FIXME: raise exception. // LogMessagef(("bufferData: no buffer bound")); return; } if (indx < NumTrackedPointerStates) { VertexAttribPointerState& state = m_vertexAttribPointerState[indx]; state.buffer = m_boundArrayBuffer; state.indx = indx; state.size = size; state.type = type; state.normalized = normalized; state.stride = stride; state.offset = offset; } glVertexAttribPointer(indx, size, type, normalized, stride, reinterpret_cast(static_cast(offset))); } DELEGATE_TO_GL_4(viewport, Viewport, long, long, unsigned long, unsigned long) unsigned WebGraphicsContext3DDefaultImpl::createBuffer() { makeContextCurrent(); GLuint o; glGenBuffers(1, &o); return o; } unsigned WebGraphicsContext3DDefaultImpl::createFramebuffer() { makeContextCurrent(); GLuint o = 0; glGenFramebuffersEXT(1, &o); return o; } unsigned WebGraphicsContext3DDefaultImpl::createProgram() { makeContextCurrent(); return glCreateProgram(); } unsigned WebGraphicsContext3DDefaultImpl::createRenderbuffer() { makeContextCurrent(); GLuint o; glGenRenderbuffersEXT(1, &o); return o; } DELEGATE_TO_GL_1R(createShader, CreateShader, unsigned long, unsigned); unsigned WebGraphicsContext3DDefaultImpl::createTexture() { makeContextCurrent(); GLuint o; glGenTextures(1, &o); return o; } void WebGraphicsContext3DDefaultImpl::deleteBuffer(unsigned buffer) { makeContextCurrent(); glDeleteBuffers(1, &buffer); } void WebGraphicsContext3DDefaultImpl::deleteFramebuffer(unsigned framebuffer) { makeContextCurrent(); glDeleteFramebuffersEXT(1, &framebuffer); } void WebGraphicsContext3DDefaultImpl::deleteProgram(unsigned program) { makeContextCurrent(); glDeleteProgram(program); } void WebGraphicsContext3DDefaultImpl::deleteRenderbuffer(unsigned renderbuffer) { makeContextCurrent(); glDeleteRenderbuffersEXT(1, &renderbuffer); } void WebGraphicsContext3DDefaultImpl::deleteShader(unsigned shader) { makeContextCurrent(); glDeleteShader(shader); } void WebGraphicsContext3DDefaultImpl::deleteTexture(unsigned texture) { makeContextCurrent(); glDeleteTextures(1, &texture); } } // namespace WebKit #endif // ENABLE(3D_CANVAS)