| 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 ENABLE(GRAPHICS_CONTEXT_3D) |
| 30 | |
| 31 | #include "GraphicsContext3D.h" |
| 32 | |
| 33 | #if PLATFORM(IOS_FAMILY) |
| 34 | #include "GraphicsContext3DIOS.h" |
| 35 | #endif |
| 36 | #include "Extensions3DOpenGL.h" |
| 37 | #include "IntRect.h" |
| 38 | #include "IntSize.h" |
| 39 | #include "NotImplemented.h" |
| 40 | #include "TemporaryOpenGLSetting.h" |
| 41 | #include <algorithm> |
| 42 | #include <cstring> |
| 43 | #include <wtf/MainThread.h> |
| 44 | #include <wtf/text/CString.h> |
| 45 | |
| 46 | #if USE(ACCELERATE) |
| 47 | #include <Accelerate/Accelerate.h> |
| 48 | #endif |
| 49 | |
| 50 | #if PLATFORM(GTK) || PLATFORM(WIN) |
| 51 | #include "OpenGLShims.h" |
| 52 | #elif USE(OPENGL_ES) |
| 53 | #import <OpenGLES/ES2/glext.h> |
| 54 | // From <OpenGLES/glext.h> |
| 55 | #define GL_RGBA32F_ARB 0x8814 |
| 56 | #define GL_RGB32F_ARB 0x8815 |
| 57 | #elif USE(OPENGL) |
| 58 | #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED |
| 59 | #include <OpenGL/gl.h> |
| 60 | #include <OpenGL/gl3.h> |
| 61 | #undef GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED |
| 62 | #endif |
| 63 | |
| 64 | namespace WebCore { |
| 65 | |
| 66 | void GraphicsContext3D::releaseShaderCompiler() |
| 67 | { |
| 68 | makeContextCurrent(); |
| 69 | notImplemented(); |
| 70 | } |
| 71 | |
| 72 | #if PLATFORM(MAC) |
| 73 | static void wipeAlphaChannelFromPixels(int width, int height, unsigned char* pixels) |
| 74 | { |
| 75 | // We can assume this doesn't overflow because the calling functions |
| 76 | // use checked arithmetic. |
| 77 | int totalBytes = width * height * 4; |
| 78 | for (int i = 0; i < totalBytes; i += 4) |
| 79 | pixels[i + 3] = 255; |
| 80 | } |
| 81 | #endif |
| 82 | |
| 83 | void GraphicsContext3D::readPixelsAndConvertToBGRAIfNecessary(int x, int y, int width, int height, unsigned char* pixels) |
| 84 | { |
| 85 | // NVIDIA drivers have a bug where calling readPixels in BGRA can return the wrong values for the alpha channel when the alpha is off for the context. |
| 86 | if (!m_attrs.alpha && getExtensions().isNVIDIA()) { |
| 87 | ::glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
| 88 | #if USE(ACCELERATE) |
| 89 | vImage_Buffer src; |
| 90 | src.height = height; |
| 91 | src.width = width; |
| 92 | src.rowBytes = width * 4; |
| 93 | src.data = pixels; |
| 94 | |
| 95 | vImage_Buffer dest; |
| 96 | dest.height = height; |
| 97 | dest.width = width; |
| 98 | dest.rowBytes = width * 4; |
| 99 | dest.data = pixels; |
| 100 | |
| 101 | // Swap pixel channels from RGBA to BGRA. |
| 102 | const uint8_t map[4] = { 2, 1, 0, 3 }; |
| 103 | vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); |
| 104 | #else |
| 105 | int totalBytes = width * height * 4; |
| 106 | for (int i = 0; i < totalBytes; i += 4) |
| 107 | std::swap(pixels[i], pixels[i + 2]); |
| 108 | #endif |
| 109 | } else |
| 110 | ::glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels); |
| 111 | |
| 112 | #if PLATFORM(MAC) |
| 113 | if (!m_attrs.alpha) |
| 114 | wipeAlphaChannelFromPixels(width, height, pixels); |
| 115 | #endif |
| 116 | } |
| 117 | |
| 118 | void GraphicsContext3D::validateAttributes() |
| 119 | { |
| 120 | validateDepthStencil("GL_EXT_packed_depth_stencil" ); |
| 121 | } |
| 122 | |
| 123 | bool GraphicsContext3D::reshapeFBOs(const IntSize& size) |
| 124 | { |
| 125 | const int width = size.width(); |
| 126 | const int height = size.height(); |
| 127 | GLuint colorFormat, internalDepthStencilFormat = 0; |
| 128 | if (m_attrs.alpha) { |
| 129 | m_internalColorFormat = GL_RGBA8; |
| 130 | colorFormat = GL_RGBA; |
| 131 | } else { |
| 132 | m_internalColorFormat = GL_RGB8; |
| 133 | colorFormat = GL_RGB; |
| 134 | } |
| 135 | if (m_attrs.stencil || m_attrs.depth) { |
| 136 | // We don't allow the logic where stencil is required and depth is not. |
| 137 | // See GraphicsContext3D::validateAttributes. |
| 138 | |
| 139 | Extensions3D& extensions = getExtensions(); |
| 140 | // Use a 24 bit depth buffer where we know we have it. |
| 141 | if (extensions.supports("GL_EXT_packed_depth_stencil" )) |
| 142 | internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT; |
| 143 | else |
| 144 | #if PLATFORM(COCOA) && USE(OPENGL_ES) |
| 145 | internalDepthStencilFormat = GL_DEPTH_COMPONENT16; |
| 146 | #else |
| 147 | internalDepthStencilFormat = GL_DEPTH_COMPONENT; |
| 148 | #endif |
| 149 | } |
| 150 | |
| 151 | // Resize multisample FBO. |
| 152 | if (m_attrs.antialias) { |
| 153 | GLint maxSampleCount; |
| 154 | ::glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount); |
| 155 | // Using more than 4 samples is slow on some hardware and is unlikely to |
| 156 | // produce a significantly better result. |
| 157 | GLint sampleCount = std::min(4, maxSampleCount); |
| 158 | ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); |
| 159 | ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); |
| 160 | #if PLATFORM(COCOA) && USE(OPENGL_ES) |
| 161 | ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, GL_RGBA8_OES, width, height); |
| 162 | #else |
| 163 | ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, m_internalColorFormat, width, height); |
| 164 | #endif |
| 165 | ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); |
| 166 | if (m_attrs.stencil || m_attrs.depth) { |
| 167 | ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); |
| 168 | ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height); |
| 169 | if (m_attrs.stencil) |
| 170 | ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); |
| 171 | if (m_attrs.depth) |
| 172 | ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); |
| 173 | } |
| 174 | ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); |
| 175 | if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { |
| 176 | // FIXME: cleanup. |
| 177 | notImplemented(); |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | // resize regular FBO |
| 182 | ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); |
| 183 | ASSERT(m_texture); |
| 184 | #if PLATFORM(COCOA) |
| 185 | #if USE(OPENGL_ES) |
| 186 | ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture); |
| 187 | ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_texture); |
| 188 | setRenderbufferStorageFromDrawable(m_currentWidth, m_currentHeight); |
| 189 | #else |
| 190 | allocateIOSurfaceBackingStore(IntSize(width, height)); |
| 191 | updateFramebufferTextureBackingStoreFromLayer(); |
| 192 | ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_texture, 0); |
| 193 | #endif // !USE(OPENGL_ES)) |
| 194 | #else |
| 195 | ::glBindTexture(GL_TEXTURE_2D, m_texture); |
| 196 | ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); |
| 197 | ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); |
| 198 | |
| 199 | #if USE(COORDINATED_GRAPHICS) |
| 200 | if (m_compositorTexture) { |
| 201 | ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); |
| 202 | ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); |
| 203 | ::glBindTexture(GL_TEXTURE_2D, 0); |
| 204 | ::glBindTexture(GL_TEXTURE_2D, m_intermediateTexture); |
| 205 | ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); |
| 206 | ::glBindTexture(GL_TEXTURE_2D, 0); |
| 207 | } |
| 208 | #endif |
| 209 | #endif |
| 210 | |
| 211 | attachDepthAndStencilBufferIfNeeded(internalDepthStencilFormat, width, height); |
| 212 | |
| 213 | bool mustRestoreFBO = true; |
| 214 | if (m_attrs.antialias) { |
| 215 | ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); |
| 216 | if (m_state.boundFBO == m_multisampleFBO) |
| 217 | mustRestoreFBO = false; |
| 218 | } else { |
| 219 | if (m_state.boundFBO == m_fbo) |
| 220 | mustRestoreFBO = false; |
| 221 | } |
| 222 | |
| 223 | return mustRestoreFBO; |
| 224 | } |
| 225 | |
| 226 | void GraphicsContext3D::attachDepthAndStencilBufferIfNeeded(GLuint internalDepthStencilFormat, int width, int height) |
| 227 | { |
| 228 | if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) { |
| 229 | ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer); |
| 230 | ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height); |
| 231 | if (m_attrs.stencil) |
| 232 | ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); |
| 233 | if (m_attrs.depth) |
| 234 | ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); |
| 235 | ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); |
| 236 | } |
| 237 | |
| 238 | if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { |
| 239 | // FIXME: cleanup |
| 240 | notImplemented(); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | void GraphicsContext3D::resolveMultisamplingIfNecessary(const IntRect& rect) |
| 245 | { |
| 246 | TemporaryOpenGLSetting scopedScissor(GL_SCISSOR_TEST, GL_FALSE); |
| 247 | TemporaryOpenGLSetting scopedDither(GL_DITHER, GL_FALSE); |
| 248 | TemporaryOpenGLSetting scopedDepth(GL_DEPTH_TEST, GL_FALSE); |
| 249 | TemporaryOpenGLSetting scopedStencil(GL_STENCIL_TEST, GL_FALSE); |
| 250 | |
| 251 | #if PLATFORM(COCOA) && USE(OPENGL_ES) |
| 252 | GLint boundFrameBuffer; |
| 253 | ::glGetIntegerv(GL_FRAMEBUFFER_BINDING, &boundFrameBuffer); |
| 254 | #endif |
| 255 | |
| 256 | ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO); |
| 257 | ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo); |
| 258 | #if PLATFORM(COCOA) && USE(OPENGL_ES) |
| 259 | UNUSED_PARAM(rect); |
| 260 | ::glFlush(); |
| 261 | ::glResolveMultisampleFramebufferAPPLE(); |
| 262 | const GLenum discards[] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT }; |
| 263 | ::glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 2, discards); |
| 264 | ::glBindFramebuffer(GL_FRAMEBUFFER, boundFrameBuffer); |
| 265 | #else |
| 266 | IntRect resolveRect = rect; |
| 267 | if (rect.isEmpty()) |
| 268 | resolveRect = IntRect(0, 0, m_currentWidth, m_currentHeight); |
| 269 | |
| 270 | ::glBlitFramebufferEXT(resolveRect.x(), resolveRect.y(), resolveRect.maxX(), resolveRect.maxY(), resolveRect.x(), resolveRect.y(), resolveRect.maxX(), resolveRect.maxY(), GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| 271 | #endif |
| 272 | } |
| 273 | |
| 274 | void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) |
| 275 | { |
| 276 | makeContextCurrent(); |
| 277 | #if USE(OPENGL) |
| 278 | switch (internalformat) { |
| 279 | case DEPTH_STENCIL: |
| 280 | internalformat = GL_DEPTH24_STENCIL8_EXT; |
| 281 | break; |
| 282 | case DEPTH_COMPONENT16: |
| 283 | internalformat = GL_DEPTH_COMPONENT; |
| 284 | break; |
| 285 | case RGBA4: |
| 286 | case RGB5_A1: |
| 287 | internalformat = GL_RGBA; |
| 288 | break; |
| 289 | case RGB565: |
| 290 | internalformat = GL_RGB; |
| 291 | break; |
| 292 | } |
| 293 | #endif |
| 294 | ::glRenderbufferStorageEXT(target, internalformat, width, height); |
| 295 | } |
| 296 | |
| 297 | void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) |
| 298 | { |
| 299 | // Need to emulate MAX_FRAGMENT/VERTEX_UNIFORM_VECTORS and MAX_VARYING_VECTORS |
| 300 | // because desktop GL's corresponding queries return the number of components |
| 301 | // whereas GLES2 return the number of vectors (each vector has 4 components). |
| 302 | // Therefore, the value returned by desktop GL needs to be divided by 4. |
| 303 | makeContextCurrent(); |
| 304 | switch (pname) { |
| 305 | #if USE(OPENGL) |
| 306 | case MAX_FRAGMENT_UNIFORM_VECTORS: |
| 307 | ::glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, value); |
| 308 | *value /= 4; |
| 309 | break; |
| 310 | case MAX_VERTEX_UNIFORM_VECTORS: |
| 311 | ::glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, value); |
| 312 | *value /= 4; |
| 313 | break; |
| 314 | case MAX_VARYING_VECTORS: |
| 315 | if (isGLES2Compliant()) { |
| 316 | ASSERT(::glGetError() == GL_NO_ERROR); |
| 317 | ::glGetIntegerv(GL_MAX_VARYING_VECTORS, value); |
| 318 | if (::glGetError() == GL_INVALID_ENUM) { |
| 319 | ::glGetIntegerv(GL_MAX_VARYING_COMPONENTS, value); |
| 320 | *value /= 4; |
| 321 | } |
| 322 | } else { |
| 323 | ::glGetIntegerv(GL_MAX_VARYING_FLOATS, value); |
| 324 | *value /= 4; |
| 325 | } |
| 326 | break; |
| 327 | #endif |
| 328 | case MAX_TEXTURE_SIZE: |
| 329 | ::glGetIntegerv(MAX_TEXTURE_SIZE, value); |
| 330 | if (getExtensions().requiresRestrictedMaximumTextureSize()) |
| 331 | *value = std::min(4096, *value); |
| 332 | break; |
| 333 | case MAX_CUBE_MAP_TEXTURE_SIZE: |
| 334 | ::glGetIntegerv(MAX_CUBE_MAP_TEXTURE_SIZE, value); |
| 335 | if (getExtensions().requiresRestrictedMaximumTextureSize()) |
| 336 | *value = std::min(1024, *value); |
| 337 | break; |
| 338 | #if PLATFORM(MAC) |
| 339 | // Some older hardware advertises a larger maximum than they |
| 340 | // can actually handle. Rather than detecting such devices, simply |
| 341 | // clamp the maximum to 8192, which is big enough for a 5K display. |
| 342 | case MAX_RENDERBUFFER_SIZE: |
| 343 | ::glGetIntegerv(MAX_RENDERBUFFER_SIZE, value); |
| 344 | *value = std::min(8192, *value); |
| 345 | break; |
| 346 | case MAX_VIEWPORT_DIMS: |
| 347 | ::glGetIntegerv(MAX_VIEWPORT_DIMS, value); |
| 348 | value[0] = std::min(8192, value[0]); |
| 349 | value[1] = std::min(8192, value[1]); |
| 350 | break; |
| 351 | #endif |
| 352 | default: |
| 353 | ::glGetIntegerv(pname, value); |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | void GraphicsContext3D::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, GC3Dint* range, GC3Dint* precision) |
| 358 | { |
| 359 | UNUSED_PARAM(shaderType); |
| 360 | ASSERT(range); |
| 361 | ASSERT(precision); |
| 362 | |
| 363 | makeContextCurrent(); |
| 364 | |
| 365 | switch (precisionType) { |
| 366 | case GraphicsContext3D::LOW_INT: |
| 367 | case GraphicsContext3D::MEDIUM_INT: |
| 368 | case GraphicsContext3D::HIGH_INT: |
| 369 | // These values are for a 32-bit twos-complement integer format. |
| 370 | range[0] = 31; |
| 371 | range[1] = 30; |
| 372 | precision[0] = 0; |
| 373 | break; |
| 374 | case GraphicsContext3D::LOW_FLOAT: |
| 375 | case GraphicsContext3D::MEDIUM_FLOAT: |
| 376 | case GraphicsContext3D::HIGH_FLOAT: |
| 377 | // These values are for an IEEE single-precision floating-point format. |
| 378 | range[0] = 127; |
| 379 | range[1] = 127; |
| 380 | precision[0] = 23; |
| 381 | break; |
| 382 | default: |
| 383 | ASSERT_NOT_REACHED(); |
| 384 | break; |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels) |
| 389 | { |
| 390 | if (width && height && !pixels) { |
| 391 | synthesizeGLError(INVALID_VALUE); |
| 392 | return false; |
| 393 | } |
| 394 | |
| 395 | GC3Denum openGLFormat = format; |
| 396 | GC3Denum openGLInternalFormat = internalformat; |
| 397 | #if USE(OPENGL) |
| 398 | if (type == GL_FLOAT) { |
| 399 | if (format == GL_RGBA) |
| 400 | openGLInternalFormat = GL_RGBA32F_ARB; |
| 401 | else if (format == GL_RGB) |
| 402 | openGLInternalFormat = GL_RGB32F_ARB; |
| 403 | } else if (type == HALF_FLOAT_OES) { |
| 404 | if (format == GL_RGBA) |
| 405 | openGLInternalFormat = GL_RGBA16F_ARB; |
| 406 | else if (format == GL_RGB) |
| 407 | openGLInternalFormat = GL_RGB16F_ARB; |
| 408 | else if (format == GL_LUMINANCE) |
| 409 | openGLInternalFormat = GL_LUMINANCE16F_ARB; |
| 410 | else if (format == GL_ALPHA) |
| 411 | openGLInternalFormat = GL_ALPHA16F_ARB; |
| 412 | else if (format == GL_LUMINANCE_ALPHA) |
| 413 | openGLInternalFormat = GL_LUMINANCE_ALPHA16F_ARB; |
| 414 | type = GL_HALF_FLOAT_ARB; |
| 415 | } |
| 416 | |
| 417 | ASSERT(format != Extensions3D::SRGB8_ALPHA8_EXT); |
| 418 | if (format == Extensions3D::SRGB_ALPHA_EXT) |
| 419 | openGLFormat = GL_RGBA; |
| 420 | else if (format == Extensions3D::SRGB_EXT) |
| 421 | openGLFormat = GL_RGB; |
| 422 | #endif |
| 423 | |
| 424 | if (m_usingCoreProfile) { |
| 425 | // There are some format values used in WebGL that are deprecated when using a core profile, so we need |
| 426 | // to adapt them. |
| 427 | switch (openGLInternalFormat) { |
| 428 | case ALPHA: |
| 429 | // The format is a simple component containing an alpha value. It needs to be backed with a GL_RED plane. |
| 430 | // We change the formats to GL_RED (both need to be GL_ALPHA in WebGL) and instruct the texture to swizzle |
| 431 | // the red component values with the alpha component values. |
| 432 | openGLInternalFormat = openGLFormat = RED; |
| 433 | texParameteri(target, TEXTURE_SWIZZLE_A, RED); |
| 434 | break; |
| 435 | case LUMINANCE_ALPHA: |
| 436 | // The format has 2 components, an alpha one and a luminance one (same value for red, green and blue). |
| 437 | // It needs to be backed with a GL_RG plane, using the red component for the colors and the green component |
| 438 | // for alpha. We change the formats to GL_RG and swizzle the components. |
| 439 | openGLInternalFormat = openGLFormat = RG; |
| 440 | texParameteri(target, TEXTURE_SWIZZLE_R, RED); |
| 441 | texParameteri(target, TEXTURE_SWIZZLE_G, RED); |
| 442 | texParameteri(target, TEXTURE_SWIZZLE_B, RED); |
| 443 | texParameteri(target, TEXTURE_SWIZZLE_A, GREEN); |
| 444 | break; |
| 445 | default: |
| 446 | break; |
| 447 | } |
| 448 | } |
| 449 | |
| 450 | texImage2DDirect(target, level, openGLInternalFormat, width, height, border, openGLFormat, type, pixels); |
| 451 | return true; |
| 452 | } |
| 453 | |
| 454 | void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar) |
| 455 | { |
| 456 | makeContextCurrent(); |
| 457 | #if PLATFORM(COCOA) && USE(OPENGL_ES) |
| 458 | ::glDepthRangef(static_cast<float>(zNear), static_cast<float>(zFar)); |
| 459 | #else |
| 460 | ::glDepthRange(zNear, zFar); |
| 461 | #endif |
| 462 | } |
| 463 | |
| 464 | void GraphicsContext3D::clearDepth(GC3Dclampf depth) |
| 465 | { |
| 466 | makeContextCurrent(); |
| 467 | #if PLATFORM(COCOA) && USE(OPENGL_ES) |
| 468 | ::glClearDepthf(static_cast<float>(depth)); |
| 469 | #else |
| 470 | ::glClearDepth(depth); |
| 471 | #endif |
| 472 | } |
| 473 | |
| 474 | #if !PLATFORM(GTK) |
| 475 | Extensions3D& GraphicsContext3D::getExtensions() |
| 476 | { |
| 477 | if (!m_extensions) |
| 478 | m_extensions = std::make_unique<Extensions3DOpenGL>(this, isGLES2Compliant()); |
| 479 | return *m_extensions; |
| 480 | } |
| 481 | #endif |
| 482 | |
| 483 | void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data) |
| 484 | { |
| 485 | // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e., |
| 486 | // all previous rendering calls should be done before reading pixels. |
| 487 | makeContextCurrent(); |
| 488 | ::glFlush(); |
| 489 | if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO) { |
| 490 | resolveMultisamplingIfNecessary(IntRect(x, y, width, height)); |
| 491 | ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_fbo); |
| 492 | ::glFlush(); |
| 493 | } |
| 494 | ::glReadPixels(x, y, width, height, format, type, data); |
| 495 | if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO) |
| 496 | ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO); |
| 497 | |
| 498 | #if PLATFORM(MAC) |
| 499 | if (!m_attrs.alpha && (format == GraphicsContext3D::RGBA || format == GraphicsContext3D::BGRA) && (m_state.boundFBO == m_fbo || (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO))) |
| 500 | wipeAlphaChannelFromPixels(width, height, static_cast<unsigned char*>(data)); |
| 501 | #endif |
| 502 | } |
| 503 | |
| 504 | } |
| 505 | |
| 506 | #endif // ENABLE(GRAPHICS_CONTEXT_3D) |
| 507 | |