1926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/*
2926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Copyright (C) 2013 Google Inc. All rights reserved.
3926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *
4926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
5926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * modification, are permitted provided that the following conditions
6926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * are met:
7926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *
8926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * 1.  Redistributions of source code must retain the above copyright
9926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *     notice, this list of conditions and the following disclaimer.
10926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * 2.  Redistributions in binary form must reproduce the above copyright
11926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *     notice, this list of conditions and the following disclaimer in the
12926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *     documentation and/or other materials provided with the distribution.
13926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) *
14926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) */
25926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
26926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include "config.h"
27926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
285267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "core/html/canvas/WebGLDrawBuffers.h"
29926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
30c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
31926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
32d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)WebGLDrawBuffers::WebGLDrawBuffers(WebGLRenderingContextBase* context)
33926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    : WebGLExtension(context)
34926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
3509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    context->extensionsUtil()->ensureExtensionEnabled("GL_EXT_draw_buffers");
36926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
37926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
385267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)WebGLDrawBuffers::~WebGLDrawBuffers()
39926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
40926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
41926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
42d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)WebGLExtensionName WebGLDrawBuffers::name() const
43926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
44d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    return WebGLDrawBuffersName;
45926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
46926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
47c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)PassRefPtrWillBeRawPtr<WebGLDrawBuffers> WebGLDrawBuffers::create(WebGLRenderingContextBase* context)
48926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
49c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    return adoptRefWillBeNoop(new WebGLDrawBuffers(context));
50926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
51926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
52926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)// static
53d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)bool WebGLDrawBuffers::supported(WebGLRenderingContextBase* context)
54926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
5509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return (context->extensionsUtil()->supportsExtension("GL_EXT_draw_buffers")
56926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        && satisfiesWebGLRequirements(context));
57926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
58926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
5906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)const char* WebGLDrawBuffers::extensionName()
6053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles){
615267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    return "WEBGL_draw_buffers";
6253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
6353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
6409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void WebGLDrawBuffers::drawBuffersWEBGL(const Vector<GLenum>& buffers)
65926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
66521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (isLost())
67926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return;
6809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    GLsizei n = buffers.size();
6909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    const GLenum* bufs = buffers.data();
70926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (!m_context->m_framebufferBinding) {
71926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (n != 1) {
7209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            m_context->synthesizeGLError(GL_INVALID_VALUE, "drawBuffersWEBGL", "more than one buffer");
73926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            return;
74926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
7509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (bufs[0] != GL_BACK && bufs[0] != GL_NONE) {
7609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            m_context->synthesizeGLError(GL_INVALID_OPERATION, "drawBuffersWEBGL", "BACK or NONE");
77926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            return;
78926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
79926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        // Because the backbuffer is simulated on all current WebKit ports, we need to change BACK to COLOR_ATTACHMENT0.
8009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        GLenum value = (bufs[0] == GL_BACK) ? GL_COLOR_ATTACHMENT0 : GL_NONE;
81a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch        m_context->webContext()->drawBuffersEXT(1, &value);
82926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        m_context->setBackDrawBuffer(bufs[0]);
83926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    } else {
8406f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)        if (n > m_context->maxDrawBuffers()) {
8509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            m_context->synthesizeGLError(GL_INVALID_VALUE, "drawBuffersWEBGL", "more than max draw buffers");
86926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            return;
87926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
8809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        for (GLsizei i = 0; i < n; ++i) {
8909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            if (bufs[i] != GL_NONE && bufs[i] != static_cast<GLenum>(GL_COLOR_ATTACHMENT0_EXT + i)) {
9009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                m_context->synthesizeGLError(GL_INVALID_OPERATION, "drawBuffersWEBGL", "COLOR_ATTACHMENTi_EXT or NONE");
91926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                return;
92926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            }
93926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
94926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        m_context->m_framebufferBinding->drawBuffers(buffers);
95926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
96926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
97926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
98926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)// static
99d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)bool WebGLDrawBuffers::satisfiesWebGLRequirements(WebGLRenderingContextBase* webglContext)
100926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
101a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    blink::WebGraphicsContext3D* context = webglContext->webContext();
10209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    Extensions3DUtil* extensionsUtil = webglContext->extensionsUtil();
103926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
104926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    // This is called after we make sure GL_EXT_draw_buffers is supported.
10509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    GLint maxDrawBuffers = 0;
10609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    GLint maxColorAttachments = 0;
10709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    context->getIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
10809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    context->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments);
109926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (maxDrawBuffers < 4 || maxColorAttachments < 4)
110926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        return false;
111926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
112926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    Platform3DObject fbo = context->createFramebuffer();
11309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    context->bindFramebuffer(GL_FRAMEBUFFER, fbo);
114926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
115926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    const unsigned char* buffer = 0; // Chromium doesn't allow init data for depth/stencil tetxures.
11609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    bool supportsDepth = (extensionsUtil->supportsExtension("GL_CHROMIUM_depth_texture")
11709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        || extensionsUtil->supportsExtension("GL_OES_depth_texture")
11809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        || extensionsUtil->supportsExtension("GL_ARB_depth_texture"));
11909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    bool supportsDepthStencil = (extensionsUtil->supportsExtension("GL_EXT_packed_depth_stencil")
12009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        || extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil"));
121926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    Platform3DObject depthStencil = 0;
122926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (supportsDepthStencil) {
123926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        depthStencil = context->createTexture();
12409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        context->bindTexture(GL_TEXTURE_2D, depthStencil);
12509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        context->texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_OES, 1, 1, 0, GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, buffer);
126926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
127926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    Platform3DObject depth = 0;
128926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (supportsDepth) {
129926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        depth = context->createTexture();
13009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        context->bindTexture(GL_TEXTURE_2D, depth);
13109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        context->texImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer);
132926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
133926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
134926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    Vector<Platform3DObject> colors;
135926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    bool ok = true;
13609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    GLint maxAllowedBuffers = std::min(maxDrawBuffers, maxColorAttachments);
13709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    for (GLint i = 0; i < maxAllowedBuffers; ++i) {
138926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        Platform3DObject color = context->createTexture();
139926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        colors.append(color);
14009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        context->bindTexture(GL_TEXTURE_2D, color);
14109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        context->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
14209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, color, 0);
14309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
144926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            ok = false;
145926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            break;
146926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
147926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (supportsDepth) {
14809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
14909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
150926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                ok = false;
151926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                break;
152926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            }
15309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
154926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
155926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        if (supportsDepthStencil) {
15609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthStencil, 0);
15709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthStencil, 0);
15809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            if (context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
159926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                ok = false;
160926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)                break;
161926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)            }
16209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            context->framebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
16309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            context->framebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
164926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        }
165926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    }
166926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
167926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    webglContext->restoreCurrentFramebuffer();
168926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    context->deleteFramebuffer(fbo);
169926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    webglContext->restoreCurrentTexture2D();
170926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (supportsDepth)
171926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        context->deleteTexture(depth);
172926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    if (supportsDepthStencil)
173926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        context->deleteTexture(depthStencil);
174926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    for (size_t i = 0; i < colors.size(); ++i)
175926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        context->deleteTexture(colors[i]);
176926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)    return ok;
177926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
178926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
179c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
180