1/* 2 * Copyright (C) 2010, 2013 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 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 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#if PLATFORM(IOS) 33#include "GraphicsContext3DIOS.h" 34#endif 35 36#include "Extensions3DOpenGL.h" 37#include "IntRect.h" 38#include "IntSize.h" 39#include "NotImplemented.h" 40#include "TemporaryOpenGLSetting.h" 41 42#include <algorithm> 43#include <cstring> 44#include <wtf/MainThread.h> 45#include <wtf/text/CString.h> 46 47#if PLATFORM(IOS) 48#import <OpenGLES/ES2/glext.h> 49// From <OpenGLES/glext.h> 50#define GL_RGBA32F_ARB 0x8814 51#define GL_RGB32F_ARB 0x8815 52#elif PLATFORM(MAC) 53#include <OpenGL/gl.h> 54#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) 55#include "OpenGLShims.h" 56#endif 57 58namespace WebCore { 59 60void GraphicsContext3D::releaseShaderCompiler() 61{ 62 makeContextCurrent(); 63 notImplemented(); 64} 65 66void GraphicsContext3D::readPixelsAndConvertToBGRAIfNecessary(int x, int y, int width, int height, unsigned char* pixels) 67{ 68 ::glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); 69} 70 71void GraphicsContext3D::validateAttributes() 72{ 73 validateDepthStencil("GL_EXT_packed_depth_stencil"); 74} 75 76bool GraphicsContext3D::reshapeFBOs(const IntSize& size) 77{ 78 const int width = size.width(); 79 const int height = size.height(); 80 GLuint colorFormat, internalDepthStencilFormat = 0; 81 if (m_attrs.alpha) { 82 m_internalColorFormat = GL_RGBA8; 83 colorFormat = GL_RGBA; 84 } else { 85 m_internalColorFormat = GL_RGB8; 86 colorFormat = GL_RGB; 87 } 88 if (m_attrs.stencil || m_attrs.depth) { 89 // We don't allow the logic where stencil is required and depth is not. 90 // See GraphicsContext3D::validateAttributes. 91 92 Extensions3D* extensions = getExtensions(); 93 // Use a 24 bit depth buffer where we know we have it. 94 if (extensions->supports("GL_EXT_packed_depth_stencil")) 95 internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT; 96 else 97#if PLATFORM(IOS) 98 internalDepthStencilFormat = GL_DEPTH_COMPONENT16; 99#else 100 internalDepthStencilFormat = GL_DEPTH_COMPONENT; 101#endif 102 } 103 104 // Resize multisample FBO. 105 if (m_attrs.antialias) { 106 GLint maxSampleCount; 107 ::glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount); 108 GLint sampleCount = std::min(8, maxSampleCount); 109 if (sampleCount > maxSampleCount) 110 sampleCount = maxSampleCount; 111 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); 112 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); 113 ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, m_internalColorFormat, width, height); 114 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); 115 if (m_attrs.stencil || m_attrs.depth) { 116 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); 117 ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height); 118 if (m_attrs.stencil) 119 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); 120 if (m_attrs.depth) 121 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); 122 } 123 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 124 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { 125 // FIXME: cleanup. 126 notImplemented(); 127 } 128 } 129 130 // resize regular FBO 131 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); 132 ASSERT(m_texture); 133#if PLATFORM(IOS) 134 ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture); 135 ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_texture); 136 setRenderbufferStorageFromDrawable(m_currentWidth, m_currentHeight); 137#else 138 ::glBindTexture(GL_TEXTURE_2D, m_texture); 139 ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); 140 ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); 141 142 if (m_compositorTexture) { 143 ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); 144 ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); 145 ::glBindTexture(GL_TEXTURE_2D, 0); 146 } 147#endif 148 149 if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) { 150 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer); 151 ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height); 152 if (m_attrs.stencil) 153 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); 154 if (m_attrs.depth) 155 ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); 156 ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); 157 } 158 159 if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { 160 // FIXME: cleanup 161 notImplemented(); 162 } 163 164 bool mustRestoreFBO = true; 165 if (m_attrs.antialias) { 166 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); 167 if (m_state.boundFBO == m_multisampleFBO) 168 mustRestoreFBO = false; 169 } else { 170 if (m_state.boundFBO == m_fbo) 171 mustRestoreFBO = false; 172 } 173 174 return mustRestoreFBO; 175} 176 177void GraphicsContext3D::resolveMultisamplingIfNecessary(const IntRect& rect) 178{ 179 TemporaryOpenGLSetting scopedScissor(GL_SCISSOR_TEST, GL_FALSE); 180 TemporaryOpenGLSetting scopedDither(GL_DITHER, GL_FALSE); 181 TemporaryOpenGLSetting scopedDepth(GL_DEPTH_TEST, GL_FALSE); 182 TemporaryOpenGLSetting scopedStencil(GL_STENCIL_TEST, GL_FALSE); 183 184 ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); 185 ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); 186#if PLATFORM(IOS) 187 UNUSED_PARAM(rect); 188 ::glResolveMultisampleFramebufferAPPLE(); 189#else 190 IntRect resolveRect = rect; 191 if (rect.isEmpty()) 192 resolveRect = IntRect(0, 0, m_currentWidth, m_currentHeight); 193 194 ::glBlitFramebufferEXT(resolveRect.x(), resolveRect.y(), resolveRect.maxX(), resolveRect.maxY(), resolveRect.x(), resolveRect.y(), resolveRect.maxX(), resolveRect.maxY(), GL_COLOR_BUFFER_BIT, GL_LINEAR); 195#endif 196} 197 198void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) 199{ 200 makeContextCurrent(); 201#if !PLATFORM(IOS) 202 switch (internalformat) { 203 case DEPTH_STENCIL: 204 internalformat = GL_DEPTH24_STENCIL8_EXT; 205 break; 206 case DEPTH_COMPONENT16: 207 internalformat = GL_DEPTH_COMPONENT; 208 break; 209 case RGBA4: 210 case RGB5_A1: 211 internalformat = GL_RGBA; 212 break; 213 case RGB565: 214 internalformat = GL_RGB; 215 break; 216 } 217#endif 218 ::glRenderbufferStorageEXT(target, internalformat, width, height); 219} 220 221void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) 222{ 223 // Need to emulate MAX_FRAGMENT/VERTEX_UNIFORM_VECTORS and MAX_VARYING_VECTORS 224 // because desktop GL's corresponding queries return the number of components 225 // whereas GLES2 return the number of vectors (each vector has 4 components). 226 // Therefore, the value returned by desktop GL needs to be divided by 4. 227 makeContextCurrent(); 228 switch (pname) { 229#if !PLATFORM(IOS) 230 case MAX_FRAGMENT_UNIFORM_VECTORS: 231 ::glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, value); 232 *value /= 4; 233 break; 234 case MAX_VERTEX_UNIFORM_VECTORS: 235 ::glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, value); 236 *value /= 4; 237 break; 238 case MAX_VARYING_VECTORS: 239 ::glGetIntegerv(GL_MAX_VARYING_FLOATS, value); 240 *value /= 4; 241 break; 242#endif 243 case MAX_TEXTURE_SIZE: 244 ::glGetIntegerv(MAX_TEXTURE_SIZE, value); 245 if (getExtensions()->requiresRestrictedMaximumTextureSize()) 246 *value = std::min(4096, *value); 247 break; 248 case MAX_CUBE_MAP_TEXTURE_SIZE: 249 ::glGetIntegerv(MAX_CUBE_MAP_TEXTURE_SIZE, value); 250 if (getExtensions()->requiresRestrictedMaximumTextureSize()) 251 *value = std::min(1024, *value); 252 break; 253 default: 254 ::glGetIntegerv(pname, value); 255 } 256} 257 258void GraphicsContext3D::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, GC3Dint* range, GC3Dint* precision) 259{ 260 UNUSED_PARAM(shaderType); 261 ASSERT(range); 262 ASSERT(precision); 263 264 makeContextCurrent(); 265 266 switch (precisionType) { 267 case GraphicsContext3D::LOW_INT: 268 case GraphicsContext3D::MEDIUM_INT: 269 case GraphicsContext3D::HIGH_INT: 270 // These values are for a 32-bit twos-complement integer format. 271 range[0] = 31; 272 range[1] = 30; 273 precision[0] = 0; 274 break; 275 case GraphicsContext3D::LOW_FLOAT: 276 case GraphicsContext3D::MEDIUM_FLOAT: 277 case GraphicsContext3D::HIGH_FLOAT: 278 // These values are for an IEEE single-precision floating-point format. 279 range[0] = 127; 280 range[1] = 127; 281 precision[0] = 23; 282 break; 283 default: 284 ASSERT_NOT_REACHED(); 285 break; 286 } 287} 288 289bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels) 290{ 291 if (width && height && !pixels) { 292 synthesizeGLError(INVALID_VALUE); 293 return false; 294 } 295 296 GC3Denum openGLInternalFormat = internalformat; 297#if !PLATFORM(IOS) 298 if (type == GL_FLOAT) { 299 if (format == GL_RGBA) 300 openGLInternalFormat = GL_RGBA32F_ARB; 301 else if (format == GL_RGB) 302 openGLInternalFormat = GL_RGB32F_ARB; 303 } else if (type == HALF_FLOAT_OES) { 304 if (format == GL_RGBA) 305 openGLInternalFormat = GL_RGBA16F_ARB; 306 else if (format == GL_RGB) 307 openGLInternalFormat = GL_RGB16F_ARB; 308 else if (format == GL_LUMINANCE) 309 openGLInternalFormat = GL_LUMINANCE16F_ARB; 310 else if (format == GL_ALPHA) 311 openGLInternalFormat = GL_ALPHA16F_ARB; 312 else if (format == GL_LUMINANCE_ALPHA) 313 openGLInternalFormat = GL_LUMINANCE_ALPHA16F_ARB; 314 type = GL_HALF_FLOAT_ARB; 315 } 316#endif 317 texImage2DDirect(target, level, openGLInternalFormat, width, height, border, format, type, pixels); 318 return true; 319} 320 321void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar) 322{ 323 makeContextCurrent(); 324#if PLATFORM(IOS) 325 ::glDepthRangef(static_cast<float>(zNear), static_cast<float>(zFar)); 326#else 327 ::glDepthRange(zNear, zFar); 328#endif 329} 330 331void GraphicsContext3D::clearDepth(GC3Dclampf depth) 332{ 333 makeContextCurrent(); 334#if PLATFORM(IOS) 335 ::glClearDepthf(static_cast<float>(depth)); 336#else 337 ::glClearDepth(depth); 338#endif 339} 340 341Extensions3D* GraphicsContext3D::getExtensions() 342{ 343 if (!m_extensions) 344 m_extensions = adoptPtr(new Extensions3DOpenGL(this)); 345 return m_extensions.get(); 346} 347 348void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data) 349{ 350 // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e., 351 // all previous rendering calls should be done before reading pixels. 352 makeContextCurrent(); 353 ::glFlush(); 354 if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO) { 355 resolveMultisamplingIfNecessary(IntRect(x, y, width, height)); 356 ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_fbo); 357 ::glFlush(); 358 } 359 ::glReadPixels(x, y, width, height, format, type, data); 360 if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO) 361 ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); 362} 363 364} 365 366#endif // USE(3D_GRAPHICS) 367