1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2011 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28 29#if USE(3D_GRAPHICS) 30 31#include "GraphicsContext3D.h" 32 33#include "Extensions3DOpenGL.h" 34#include "IntRect.h" 35#include "IntSize.h" 36#include "NotImplemented.h" 37 38#include <algorithm> 39#include <cstring> 40#include <wtf/MainThread.h> 41#include <wtf/text/CString.h> 42 43#if PLATFORM(MAC) 44#include <OpenGL/gl.h> 45#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(QT) 46#include "OpenGLShims.h" 47#endif 48 49namespace WebCore { 50 51void GraphicsContext3D::releaseShaderCompiler() 52{ 53 makeContextCurrent(); 54 notImplemented(); 55} 56 57void GraphicsContext3D::readPixelsAndConvertToBGRAIfNecessary(int x, int y, int width, int height, unsigned char* pixels) 58{ 59 ::glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); 60} 61 62void GraphicsContext3D::validateAttributes() 63{ 64 validateDepthStencil("GL_EXT_packed_depth_stencil"); 65} 66 67bool GraphicsContext3D::reshapeFBOs(const IntSize& size) 68{ 69 const int width = size.width(); 70 const int height = size.height(); 71 GLuint colorFormat, internalDepthStencilFormat = 0; 72 if (m_attrs.alpha) { 73 m_internalColorFormat = GL_RGBA8; 74 colorFormat = GL_RGBA; 75 } else { 76 m_internalColorFormat = GL_RGB8; 77 colorFormat = GL_RGB; 78 } 79 if (m_attrs.stencil || m_attrs.depth) { 80 // We don't allow the logic where stencil is required and depth is not. 81 // See GraphicsContext3D::validateAttributes. 82 83 Extensions3D* extensions = getExtensions(); 84 // Use a 24 bit depth buffer where we know we have it. 85 if (extensions->supports("GL_EXT_packed_depth_stencil")) 86 internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT; 87 else 88 internalDepthStencilFormat = GL_DEPTH_COMPONENT; 89 } 90 91 bool mustRestoreFBO = false; 92 93 // Resize multisample FBO. 94 if (m_attrs.antialias) { 95 GLint maxSampleCount; 96 ::glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount); 97 GLint sampleCount = std::min(8, maxSampleCount); 98 if (sampleCount > maxSampleCount) 99 sampleCount = maxSampleCount; 100 if (m_state.boundFBO != m_multisampleFBO) { 101 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); 102 mustRestoreFBO = true; 103 } 104 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); 105 ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, m_internalColorFormat, width, height); 106 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); 107 if (m_attrs.stencil || m_attrs.depth) { 108 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); 109 ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height); 110 if (m_attrs.stencil) 111 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); 112 if (m_attrs.depth) 113 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); 114 } 115 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 116 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { 117 // FIXME: cleanup. 118 notImplemented(); 119 } 120 } 121 122 // resize regular FBO 123 if (m_state.boundFBO != m_fbo) { 124 mustRestoreFBO = true; 125 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); 126 } 127 ::glBindTexture(GL_TEXTURE_2D, m_texture); 128 ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); 129 ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); 130 ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); 131 ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); 132 ::glBindTexture(GL_TEXTURE_2D, 0); 133 if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) { 134 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer); 135 ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height); 136 if (m_attrs.stencil) 137 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); 138 if (m_attrs.depth) 139 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); 140 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 141 } 142 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { 143 // FIXME: cleanup 144 notImplemented(); 145 } 146 147 if (m_attrs.antialias) { 148 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); 149 if (m_state.boundFBO == m_multisampleFBO) 150 mustRestoreFBO = false; 151 } 152 153 return mustRestoreFBO; 154} 155 156void GraphicsContext3D::resolveMultisamplingIfNecessary(const IntRect& rect) 157{ 158 ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); 159 ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); 160 161 IntRect resolveRect = rect; 162 if (rect.isEmpty()) 163 resolveRect = IntRect(0, 0, m_currentWidth, m_currentHeight); 164 165 ::glBlitFramebufferEXT(resolveRect.x(), resolveRect.y(), resolveRect.maxX(), resolveRect.maxY(), resolveRect.x(), resolveRect.y(), resolveRect.maxX(), resolveRect.maxY(), GL_COLOR_BUFFER_BIT, GL_LINEAR); 166} 167 168void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) 169{ 170 makeContextCurrent(); 171 switch (internalformat) { 172 case DEPTH_STENCIL: 173 internalformat = GL_DEPTH24_STENCIL8_EXT; 174 break; 175 case DEPTH_COMPONENT16: 176 internalformat = GL_DEPTH_COMPONENT; 177 break; 178 case RGBA4: 179 case RGB5_A1: 180 internalformat = GL_RGBA; 181 break; 182 case RGB565: 183 internalformat = GL_RGB; 184 break; 185 } 186 ::glRenderbufferStorageEXT(target, internalformat, width, height); 187} 188 189void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) 190{ 191 // Need to emulate MAX_FRAGMENT/VERTEX_UNIFORM_VECTORS and MAX_VARYING_VECTORS 192 // because desktop GL's corresponding queries return the number of components 193 // whereas GLES2 return the number of vectors (each vector has 4 components). 194 // Therefore, the value returned by desktop GL needs to be divided by 4. 195 makeContextCurrent(); 196 switch (pname) { 197 case MAX_FRAGMENT_UNIFORM_VECTORS: 198 ::glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, value); 199 *value /= 4; 200 break; 201 case MAX_VERTEX_UNIFORM_VECTORS: 202 ::glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, value); 203 *value /= 4; 204 break; 205 case MAX_VARYING_VECTORS: 206 ::glGetIntegerv(GL_MAX_VARYING_FLOATS, value); 207 *value /= 4; 208 break; 209 default: 210 ::glGetIntegerv(pname, value); 211 } 212} 213 214void GraphicsContext3D::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, GC3Dint* range, GC3Dint* precision) 215{ 216 UNUSED_PARAM(shaderType); 217 ASSERT(range); 218 ASSERT(precision); 219 220 makeContextCurrent(); 221 222 switch (precisionType) { 223 case GraphicsContext3D::LOW_INT: 224 case GraphicsContext3D::MEDIUM_INT: 225 case GraphicsContext3D::HIGH_INT: 226 // These values are for a 32-bit twos-complement integer format. 227 range[0] = 31; 228 range[1] = 30; 229 precision[0] = 0; 230 break; 231 case GraphicsContext3D::LOW_FLOAT: 232 case GraphicsContext3D::MEDIUM_FLOAT: 233 case GraphicsContext3D::HIGH_FLOAT: 234 // These values are for an IEEE single-precision floating-point format. 235 range[0] = 127; 236 range[1] = 127; 237 precision[0] = 23; 238 break; 239 default: 240 ASSERT_NOT_REACHED(); 241 break; 242 } 243} 244 245bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels) 246{ 247 if (width && height && !pixels) { 248 synthesizeGLError(INVALID_VALUE); 249 return false; 250 } 251 252 GC3Denum openGLInternalFormat = internalformat; 253 if (type == GL_FLOAT) { 254 if (format == GL_RGBA) 255 openGLInternalFormat = GL_RGBA32F_ARB; 256 else if (format == GL_RGB) 257 openGLInternalFormat = GL_RGB32F_ARB; 258 } else if (type == HALF_FLOAT_OES) { 259 if (format == GL_RGBA) 260 openGLInternalFormat = GL_RGBA16F_ARB; 261 else if (format == GL_RGB) 262 openGLInternalFormat = GL_RGB16F_ARB; 263 else if (format == GL_LUMINANCE) 264 openGLInternalFormat = GL_LUMINANCE16F_ARB; 265 else if (format == GL_ALPHA) 266 openGLInternalFormat = GL_ALPHA16F_ARB; 267 else if (format == GL_LUMINANCE_ALPHA) 268 openGLInternalFormat = GL_LUMINANCE_ALPHA16F_ARB; 269 type = GL_HALF_FLOAT_ARB; 270 } 271 texImage2DDirect(target, level, openGLInternalFormat, width, height, border, format, type, pixels); 272 return true; 273} 274 275void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar) 276{ 277 makeContextCurrent(); 278 ::glDepthRange(zNear, zFar); 279} 280 281void GraphicsContext3D::clearDepth(GC3Dclampf depth) 282{ 283 makeContextCurrent(); 284 ::glClearDepth(depth); 285} 286 287Extensions3D* GraphicsContext3D::getExtensions() 288{ 289 if (!m_extensions) 290 m_extensions = adoptPtr(new Extensions3DOpenGL(this)); 291 return m_extensions.get(); 292} 293 294void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data) 295{ 296 // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e., 297 // all previous rendering calls should be done before reading pixels. 298 makeContextCurrent(); 299 ::glFlush(); 300 if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO) { 301 resolveMultisamplingIfNecessary(IntRect(x, y, width, height)); 302 ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_fbo); 303 ::glFlush(); 304 } 305 ::glReadPixels(x, y, width, height, format, type, data); 306 if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO) 307 ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); 308} 309 310} 311 312#endif // USE(3D_GRAPHICS) 313