Home | History | Annotate | Download | only in canvas
      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 
     30 namespace blink {
     31 
     32 WebGLDrawBuffers::WebGLDrawBuffers(WebGLRenderingContextBase* context)
     33     : WebGLExtension(context)
     34 {
     35     context->extensionsUtil()->ensureExtensionEnabled("GL_EXT_draw_buffers");
     36 }
     37 
     38 WebGLDrawBuffers::~WebGLDrawBuffers()
     39 {
     40 }
     41 
     42 WebGLExtensionName WebGLDrawBuffers::name() const
     43 {
     44     return WebGLDrawBuffersName;
     45 }
     46 
     47 PassRefPtrWillBeRawPtr<WebGLDrawBuffers> WebGLDrawBuffers::create(WebGLRenderingContextBase* context)
     48 {
     49     return adoptRefWillBeNoop(new WebGLDrawBuffers(context));
     50 }
     51 
     52 // static
     53 bool WebGLDrawBuffers::supported(WebGLRenderingContextBase* context)
     54 {
     55     return (context->extensionsUtil()->supportsExtension("GL_EXT_draw_buffers")
     56         && satisfiesWebGLRequirements(context));
     57 }
     58 
     59 const char* WebGLDrawBuffers::extensionName()
     60 {
     61     return "WEBGL_draw_buffers";
     62 }
     63 
     64 void 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
     99 bool 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