1/* 2 * Copyright (C) 2013 Google 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 * 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 AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27 28#include "core/html/canvas/WebGLDrawBuffers.h" 29 30namespace blink { 31 32WebGLDrawBuffers::WebGLDrawBuffers(WebGLRenderingContextBase* context) 33 : WebGLExtension(context) 34{ 35 context->extensionsUtil()->ensureExtensionEnabled("GL_EXT_draw_buffers"); 36} 37 38WebGLDrawBuffers::~WebGLDrawBuffers() 39{ 40} 41 42WebGLExtensionName WebGLDrawBuffers::name() const 43{ 44 return WebGLDrawBuffersName; 45} 46 47PassRefPtrWillBeRawPtr<WebGLDrawBuffers> WebGLDrawBuffers::create(WebGLRenderingContextBase* context) 48{ 49 return adoptRefWillBeNoop(new WebGLDrawBuffers(context)); 50} 51 52// static 53bool WebGLDrawBuffers::supported(WebGLRenderingContextBase* context) 54{ 55 return (context->extensionsUtil()->supportsExtension("GL_EXT_draw_buffers") 56 && satisfiesWebGLRequirements(context)); 57} 58 59const char* WebGLDrawBuffers::extensionName() 60{ 61 return "WEBGL_draw_buffers"; 62} 63 64void WebGLDrawBuffers::drawBuffersWEBGL(const Vector<GLenum>& buffers) 65{ 66 if (isLost()) 67 return; 68 GLsizei n = buffers.size(); 69 const GLenum* bufs = buffers.data(); 70 if (!m_context->m_framebufferBinding) { 71 if (n != 1) { 72 m_context->synthesizeGLError(GL_INVALID_VALUE, "drawBuffersWEBGL", "more than one buffer"); 73 return; 74 } 75 if (bufs[0] != GL_BACK && bufs[0] != GL_NONE) { 76 m_context->synthesizeGLError(GL_INVALID_OPERATION, "drawBuffersWEBGL", "BACK or NONE"); 77 return; 78 } 79 // Because the backbuffer is simulated on all current WebKit ports, we need to change BACK to COLOR_ATTACHMENT0. 80 GLenum value = (bufs[0] == GL_BACK) ? GL_COLOR_ATTACHMENT0 : GL_NONE; 81 m_context->webContext()->drawBuffersEXT(1, &value); 82 m_context->setBackDrawBuffer(bufs[0]); 83 } else { 84 if (n > m_context->maxDrawBuffers()) { 85 m_context->synthesizeGLError(GL_INVALID_VALUE, "drawBuffersWEBGL", "more than max draw buffers"); 86 return; 87 } 88 for (GLsizei i = 0; i < n; ++i) { 89 if (bufs[i] != GL_NONE && bufs[i] != static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT + i)) { 90 m_context->synthesizeGLError(GL_INVALID_OPERATION, "drawBuffersWEBGL", "COLOR_ATTACHMENTi_EXT or NONE"); 91 return; 92 } 93 } 94 m_context->m_framebufferBinding->drawBuffers(buffers); 95 } 96} 97 98// static 99bool WebGLDrawBuffers::satisfiesWebGLRequirements(WebGLRenderingContextBase* webglContext) 100{ 101 blink::WebGraphicsContext3D* context = webglContext->webContext(); 102 Extensions3DUtil* extensionsUtil = webglContext->extensionsUtil(); 103 104 // This is called after we make sure GL_EXT_draw_buffers is supported. 105 GLint maxDrawBuffers = 0; 106 GLint maxColorAttachments = 0; 107 context->getIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); 108 context->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments); 109 if (maxDrawBuffers < 4 || maxColorAttachments < 4) 110 return false; 111 112 Platform3DObject fbo = context->createFramebuffer(); 113 context->bindFramebuffer(GL_FRAMEBUFFER, fbo); 114 115 const unsigned char* buffer = 0; // Chromium doesn't allow init data for depth/stencil tetxures. 116 bool supportsDepth = (extensionsUtil->supportsExtension("GL_CHROMIUM_depth_texture") 117 || extensionsUtil->supportsExtension("GL_OES_depth_texture") 118 || extensionsUtil->supportsExtension("GL_ARB_depth_texture")); 119 bool supportsDepthStencil = (extensionsUtil->supportsExtension("GL_EXT_packed_depth_stencil") 120 || extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil")); 121 Platform3DObject depthStencil = 0; 122 if (supportsDepthStencil) { 123 depthStencil = context->createTexture(); 124 context->bindTexture(GL_TEXTURE_2D, depthStencil); 125 context->texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_OES, 1, 1, 0, GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, buffer); 126 } 127 Platform3DObject depth = 0; 128 if (supportsDepth) { 129 depth = context->createTexture(); 130 context->bindTexture(GL_TEXTURE_2D, depth); 131 context->texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer); 132 } 133 134 Vector<Platform3DObject> colors; 135 bool ok = true; 136 GLint maxAllowedBuffers = std::min(maxDrawBuffers, maxColorAttachments); 137 for (GLint i = 0; i < maxAllowedBuffers; ++i) { 138 Platform3DObject color = context->createTexture(); 139 colors.append(color); 140 context->bindTexture(GL_TEXTURE_2D, color); 141 context->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); 142 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, color, 0); 143 if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 144 ok = false; 145 break; 146 } 147 if (supportsDepth) { 148 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); 149 if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 150 ok = false; 151 break; 152 } 153 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 154 } 155 if (supportsDepthStencil) { 156 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthStencil, 0); 157 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthStencil, 0); 158 if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 159 ok = false; 160 break; 161 } 162 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 163 context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); 164 } 165 } 166 167 webglContext->restoreCurrentFramebuffer(); 168 context->deleteFramebuffer(fbo); 169 webglContext->restoreCurrentTexture2D(); 170 if (supportsDepth) 171 context->deleteTexture(depth); 172 if (supportsDepthStencil) 173 context->deleteTexture(depthStencil); 174 for (size_t i = 0; i < colors.size(); ++i) 175 context->deleteTexture(colors[i]); 176 return ok; 177} 178 179} // namespace blink 180