1/* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#if USE(3D_GRAPHICS) 29 30#include "GraphicsContext3D.h" 31#if PLATFORM(IOS) 32#include "GraphicsContext3DIOS.h" 33#endif 34 35#import "BlockExceptions.h" 36 37#include "ANGLE/ShaderLang.h" 38#include "CanvasRenderingContext.h" 39#include <CoreGraphics/CGBitmapContext.h> 40#include "Extensions3DOpenGL.h" 41#include "GraphicsContext.h" 42#include "HTMLCanvasElement.h" 43#include "ImageBuffer.h" 44#if PLATFORM(IOS) 45#import <OpenGLES/ES2/glext.h> 46#import <OpenGLES/EAGL.h> 47#import <OpenGLES/EAGLDrawable.h> 48#import <QuartzCore/QuartzCore.h> 49#else 50#include <OpenGL/CGLRenderers.h> 51#include <OpenGL/gl.h> 52#endif 53#include "WebGLLayer.h" 54#include "WebGLObject.h" 55#include <runtime/ArrayBuffer.h> 56#include <runtime/ArrayBufferView.h> 57#include <runtime/Int32Array.h> 58#include <runtime/Float32Array.h> 59#include <runtime/Uint8Array.h> 60#include <wtf/text/CString.h> 61 62namespace WebCore { 63 64const int maxActiveContexts = 16; 65int GraphicsContext3D::numActiveContexts = 0; 66 67// FIXME: This class is currently empty on Mac, but will get populated as 68// the restructuring in https://bugs.webkit.org/show_bug.cgi?id=66903 is done 69class GraphicsContext3DPrivate { 70public: 71 GraphicsContext3DPrivate(GraphicsContext3D*) { } 72 73 ~GraphicsContext3DPrivate() { } 74}; 75 76#if !PLATFORM(IOS) 77static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest, bool antialias) 78{ 79 attribs.clear(); 80 81 attribs.append(kCGLPFAColorSize); 82 attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits)); 83 attribs.append(kCGLPFADepthSize); 84 attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits)); 85 86 if (accelerated) 87 attribs.append(kCGLPFAAccelerated); 88 else { 89 attribs.append(kCGLPFARendererID); 90 attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID)); 91 } 92 93 if (supersample && !antialias) 94 attribs.append(kCGLPFASupersample); 95 96 if (closest) 97 attribs.append(kCGLPFAClosestPolicy); 98 99 if (antialias) { 100 attribs.append(kCGLPFAMultisample); 101 attribs.append(kCGLPFASampleBuffers); 102 attribs.append(static_cast<CGLPixelFormatAttribute>(1)); 103 attribs.append(kCGLPFASamples); 104 attribs.append(static_cast<CGLPixelFormatAttribute>(4)); 105 } 106 107 attribs.append(static_cast<CGLPixelFormatAttribute>(0)); 108} 109#endif // !PLATFORM(IOS) 110 111PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) 112{ 113 // This implementation doesn't currently support rendering directly to the HostWindow. 114 if (renderStyle == RenderDirectlyToHostWindow) 115 return nullptr; 116 117 if (numActiveContexts >= maxActiveContexts) 118 return nullptr; 119 120 RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, renderStyle)); 121 122 if (!context->m_contextObj) 123 return nullptr; 124 125 numActiveContexts++; 126 127 return context.release(); 128} 129 130GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) 131 : m_currentWidth(0) 132 , m_currentHeight(0) 133 , m_contextObj(0) 134#if PLATFORM(IOS) 135 , m_compiler(SH_ESSL_OUTPUT) 136#endif 137 , m_attrs(attrs) 138 , m_texture(0) 139 , m_compositorTexture(0) 140 , m_fbo(0) 141 , m_depthStencilBuffer(0) 142 , m_layerComposited(false) 143 , m_internalColorFormat(0) 144 , m_multisampleFBO(0) 145 , m_multisampleDepthStencilBuffer(0) 146 , m_multisampleColorBuffer(0) 147 , m_private(std::make_unique<GraphicsContext3DPrivate>(this)) 148{ 149 UNUSED_PARAM(hostWindow); 150 UNUSED_PARAM(renderStyle); 151 152#if PLATFORM(IOS) 153 m_contextObj = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 154 makeContextCurrent(); 155#else 156 Vector<CGLPixelFormatAttribute> attribs; 157 CGLPixelFormatObj pixelFormatObj = 0; 158 GLint numPixelFormats = 0; 159 160 // If we're configured to demand the software renderer, we'll 161 // do so. We attempt to create contexts in this order: 162 // 163 // 1) 32 bit RGBA/32 bit depth/supersampled 164 // 2) 32 bit RGBA/32 bit depth 165 // 3) 32 bit RGBA/16 bit depth 166 // 167 // If we were not forced into software mode already, our final attempt is 168 // to try that: 169 // 170 // 4) closest to 32 bit RGBA/16 bit depth/software renderer 171 // 172 // If none of that works, we simply fail and set m_contextObj to 0. 173 174 bool useMultisampling = m_attrs.antialias; 175 176 setPixelFormat(attribs, 32, 32, !attrs.forceSoftwareRenderer, true, false, useMultisampling); 177 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); 178 179 if (numPixelFormats == 0) { 180 setPixelFormat(attribs, 32, 32, !attrs.forceSoftwareRenderer, false, false, useMultisampling); 181 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); 182 183 if (numPixelFormats == 0) { 184 setPixelFormat(attribs, 32, 16, !attrs.forceSoftwareRenderer, false, false, useMultisampling); 185 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); 186 187 if (!attrs.forceSoftwareRenderer && numPixelFormats == 0) { 188 setPixelFormat(attribs, 32, 16, false, false, true, false); 189 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats); 190 useMultisampling = false; 191 } 192 } 193 } 194 195 if (numPixelFormats == 0) 196 return; 197 198 CGLError err = CGLCreateContext(pixelFormatObj, 0, &m_contextObj); 199 CGLDestroyPixelFormat(pixelFormatObj); 200 201 if (err != kCGLNoError || !m_contextObj) { 202 // We were unable to create the context. 203 m_contextObj = 0; 204 return; 205 } 206 207 // Set the current context to the one given to us. 208 CGLSetCurrentContext(m_contextObj); 209 210 if (attrs.multithreaded) { 211 err = CGLEnable(m_contextObj, kCGLCEMPEngine); 212 if (err != kCGLNoError) { 213 // We could not create a multi-threaded context. 214 m_contextObj = 0; 215 return; 216 } 217 } 218#endif // !PLATFORM(IOS) 219 220 validateAttributes(); 221 222 // Create the WebGLLayer 223 BEGIN_BLOCK_OBJC_EXCEPTIONS 224 m_webGLLayer = adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:this]); 225#if PLATFORM(IOS) 226 [m_webGLLayer setOpaque:0]; 227#endif 228#ifndef NDEBUG 229 [m_webGLLayer setName:@"WebGL Layer"]; 230#endif 231 END_BLOCK_OBJC_EXCEPTIONS 232 233#if !PLATFORM(IOS) 234 if (useMultisampling) 235 ::glEnable(GL_MULTISAMPLE); 236#endif 237 238#if PLATFORM(IOS) 239 ::glGenRenderbuffers(1, &m_texture); 240#else 241 // create a texture to render into 242 ::glGenTextures(1, &m_texture); 243 ::glBindTexture(GL_TEXTURE_2D, m_texture); 244 ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 245 ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 246 ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 247 ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 248 ::glGenTextures(1, &m_compositorTexture); 249 ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); 250 ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 251 ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 252 ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 253 ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 254 ::glBindTexture(GL_TEXTURE_2D, 0); 255#endif 256 257 // create an FBO 258 ::glGenFramebuffersEXT(1, &m_fbo); 259 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); 260 261 m_state.boundFBO = m_fbo; 262 if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) 263 ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer); 264 265 // create an multisample FBO 266 if (m_attrs.antialias) { 267 ::glGenFramebuffersEXT(1, &m_multisampleFBO); 268 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); 269 m_state.boundFBO = m_multisampleFBO; 270 ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer); 271 if (m_attrs.stencil || m_attrs.depth) 272 ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); 273 } 274 275 // ANGLE initialization. 276 277 ShBuiltInResources ANGLEResources; 278 ShInitBuiltInResources(&ANGLEResources); 279 280 getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs); 281 getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors); 282 getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors); 283 getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits); 284 getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits); 285 getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits); 286 getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors); 287 288 // Always set to 1 for OpenGL ES. 289 ANGLEResources.MaxDrawBuffers = 1; 290 291 GC3Dint range[2], precision; 292 getShaderPrecisionFormat(GraphicsContext3D::FRAGMENT_SHADER, GraphicsContext3D::HIGH_FLOAT, range, &precision); 293 ANGLEResources.FragmentPrecisionHigh = (range[0] || range[1] || precision); 294 295 m_compiler.setResources(ANGLEResources); 296 297#if !PLATFORM(IOS) 298 ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); 299 ::glEnable(GL_POINT_SPRITE); 300#endif 301 302 ::glClearColor(0, 0, 0, 0); 303} 304 305GraphicsContext3D::~GraphicsContext3D() 306{ 307 if (m_contextObj) { 308#if PLATFORM(IOS) 309 makeContextCurrent(); 310 [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:nil]; 311 ::glDeleteRenderbuffers(1, &m_texture); 312 ::glDeleteRenderbuffers(1, &m_compositorTexture); 313#else 314 CGLSetCurrentContext(m_contextObj); 315 ::glDeleteTextures(1, &m_texture); 316 ::glDeleteTextures(1, &m_compositorTexture); 317#endif 318 if (m_attrs.antialias) { 319 ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer); 320 if (m_attrs.stencil || m_attrs.depth) 321 ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer); 322 ::glDeleteFramebuffersEXT(1, &m_multisampleFBO); 323 } else { 324 if (m_attrs.stencil || m_attrs.depth) 325 ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer); 326 } 327 ::glDeleteFramebuffersEXT(1, &m_fbo); 328#if PLATFORM(IOS) 329 [EAGLContext setCurrentContext:0]; 330 [static_cast<EAGLContext*>(m_contextObj) release]; 331#else 332 CGLSetCurrentContext(0); 333 CGLDestroyContext(m_contextObj); 334#endif 335 [m_webGLLayer setContext:nullptr]; 336 numActiveContexts--; 337 } 338} 339 340#if PLATFORM(IOS) 341bool GraphicsContext3D::setRenderbufferStorageFromDrawable(GC3Dsizei width, GC3Dsizei height) 342{ 343 [m_webGLLayer setBounds:CGRectMake(0, 0, width, height)]; 344 return [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:static_cast<NSObject<EAGLDrawable>*>(m_webGLLayer.get())]; 345} 346#endif 347 348bool GraphicsContext3D::makeContextCurrent() 349{ 350 if (!m_contextObj) 351 return false; 352 353#if PLATFORM(IOS) 354 if ([EAGLContext currentContext] != m_contextObj) 355 return [EAGLContext setCurrentContext:static_cast<EAGLContext*>(m_contextObj)]; 356#else 357 CGLContextObj currentContext = CGLGetCurrentContext(); 358 if (currentContext != m_contextObj) 359 return CGLSetCurrentContext(m_contextObj) == kCGLNoError; 360#endif 361 return true; 362} 363 364#if PLATFORM(IOS) 365void GraphicsContext3D::endPaint() 366{ 367 makeContextCurrent(); 368 ::glFlush(); 369 ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture); 370 [static_cast<EAGLContext*>(m_contextObj) presentRenderbuffer:GL_RENDERBUFFER]; 371 [EAGLContext setCurrentContext:nil]; 372} 373#endif 374 375bool GraphicsContext3D::isGLES2Compliant() const 376{ 377 return false; 378} 379 380void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>) 381{ 382} 383 384void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>) 385{ 386} 387 388} 389 390#endif // USE(3D_GRAPHICS) 391