OSDN Git Service

Merge WebKit at r71558: Initial merge by git.
[android-x86/external-webkit.git] / WebCore / html / canvas / WebGLFramebuffer.cpp
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 COMPUTER, 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 COMPUTER, 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 ENABLE(3D_CANVAS)
29
30 #include "WebGLFramebuffer.h"
31
32 #include "WebGLRenderingContext.h"
33
34 namespace WebCore {
35
36 namespace {
37
38     // This function is only for depth/stencil/depth_stencil attachment.
39     // Currently we assume these attachments are all renderbuffers.
40     unsigned long getInternalFormat(WebGLObject* buffer)
41     {
42         ASSERT(buffer && buffer->isRenderbuffer());
43         return (reinterpret_cast<WebGLRenderbuffer*>(buffer))->getInternalFormat();
44     }
45
46     bool isUninitialized(WebGLObject* attachedObject)
47     {
48         if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()
49             && !(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isInitialized())
50             return true;
51         return false;
52     }
53
54     void setInitialized(WebGLObject* attachedObject)
55     {
56         if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer())
57             (reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->setInitialized();
58     }
59
60     bool isValid(WebGLObject* attachedObject)
61     {
62         if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()) {
63             if (!(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isValid())
64                 return false;
65         }
66         return true;
67     }
68
69 } // anonymous namespace
70
71 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx)
72 {
73     return adoptRef(new WebGLFramebuffer(ctx));
74 }
75
76 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx)
77     : WebGLObject(ctx)
78 {
79     setObject(context()->graphicsContext3D()->createFramebuffer());
80 }
81
82 void WebGLFramebuffer::setAttachment(unsigned long attachment, WebGLObject* attachedObject)
83 {
84     if (!object())
85         return;
86     if (attachedObject && !attachedObject->object())
87         attachedObject = 0;
88     switch (attachment) {
89     case GraphicsContext3D::COLOR_ATTACHMENT0:
90         m_colorAttachment = attachedObject;
91         break;
92     case GraphicsContext3D::DEPTH_ATTACHMENT:
93         m_depthAttachment = attachedObject;
94         break;
95     case GraphicsContext3D::STENCIL_ATTACHMENT:
96         m_stencilAttachment = attachedObject;
97         break;
98     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
99         m_depthStencilAttachment = attachedObject;
100         break;
101     default:
102         return;
103     }
104 }
105
106 WebGLObject* WebGLFramebuffer::getAttachment(unsigned long attachment) const
107 {
108     if (!object())
109         return 0;
110     switch (attachment) {
111     case GraphicsContext3D::COLOR_ATTACHMENT0:
112         return m_colorAttachment.get();
113     case GraphicsContext3D::DEPTH_ATTACHMENT:
114         return m_depthAttachment.get();
115     case GraphicsContext3D::STENCIL_ATTACHMENT:
116         return m_stencilAttachment.get();
117     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
118         return m_depthStencilAttachment.get();
119     default:
120         return 0;
121     }
122 }
123
124 void WebGLFramebuffer::removeAttachment(WebGLObject* attachment)
125 {
126     if (!object())
127         return;
128     if (attachment == m_colorAttachment.get())
129         m_colorAttachment = 0;
130     else if (attachment == m_depthAttachment.get())
131         m_depthAttachment = 0;
132     else if (attachment == m_stencilAttachment.get())
133         m_stencilAttachment = 0;
134     else if (attachment == m_depthStencilAttachment.get())
135         m_depthStencilAttachment = 0;
136     else
137         return;
138 }
139
140 unsigned long WebGLFramebuffer::getColorBufferFormat() const
141 {
142     if (object() && m_colorAttachment && m_colorAttachment->object()) {
143         if (m_colorAttachment->isRenderbuffer()) {
144             unsigned long format = (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getInternalFormat();
145             switch (format) {
146             case GraphicsContext3D::RGBA4:
147             case GraphicsContext3D::RGB5_A1:
148                 return GraphicsContext3D::RGBA;
149             case GraphicsContext3D::RGB565:
150                 return GraphicsContext3D::RGB;
151             }
152         } else if (m_colorAttachment->isTexture())
153             return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getInternalFormat(0);
154     }
155     return 0;
156 }
157
158 bool WebGLFramebuffer::isIncomplete(bool checkInternalFormat) const
159 {
160     unsigned int count = 0;
161     if (isDepthAttached()) {
162         if (checkInternalFormat && getInternalFormat(m_depthAttachment.get()) != GraphicsContext3D::DEPTH_COMPONENT16)
163             return true;
164         count++;
165     }
166     if (isStencilAttached()) {
167         if (checkInternalFormat && getInternalFormat(m_stencilAttachment.get()) != GraphicsContext3D::STENCIL_INDEX8)
168             return true;
169         count++;
170     }
171     if (isDepthStencilAttached()) {
172         if (checkInternalFormat && getInternalFormat(m_depthStencilAttachment.get()) != GraphicsContext3D::DEPTH_STENCIL)
173             return true;
174         if (!isValid(m_depthStencilAttachment.get()))
175             return true;
176         count++;
177     }
178     if (count > 1)
179         return true;
180     return false;
181 }
182
183 bool WebGLFramebuffer::onAccess()
184 {
185     if (isIncomplete(true))
186         return false;
187     return initializeRenderbuffers();
188 }
189
190 void WebGLFramebuffer::deleteObjectImpl(Platform3DObject object)
191 {
192     if (!isDeleted())
193         context()->graphicsContext3D()->deleteFramebuffer(object);
194     m_colorAttachment = 0;
195     m_depthAttachment = 0;
196     m_stencilAttachment = 0;
197     m_depthStencilAttachment = 0;
198 }
199
200 bool WebGLFramebuffer::initializeRenderbuffers()
201 {
202     ASSERT(object());
203     if (!isColorAttached())
204         return false;
205     bool initColor = false, initDepth = false, initStencil = false;
206     unsigned long mask = 0;
207     if (isUninitialized(m_colorAttachment.get())) {
208         initColor = true;
209         mask |= GraphicsContext3D::COLOR_BUFFER_BIT;
210     }
211     if (isUninitialized(m_depthAttachment.get())) {
212         initDepth = true;
213         mask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
214     }
215     if (isUninitialized(m_stencilAttachment.get())) {
216         initStencil = true;
217         mask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
218     }
219     if (isUninitialized(m_depthStencilAttachment.get())) {
220         initDepth = true;
221         initStencil = true;
222         mask |= (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT);
223     }
224     if (!initColor && !initDepth && !initStencil)
225         return true;
226
227     // We only clear un-initialized renderbuffers when they are ready to be
228     // read, i.e., when the framebuffer is complete.
229     GraphicsContext3D* g3d = context()->graphicsContext3D();
230     if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
231         return false;
232
233     float colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0;
234     int stencilClearValue = 0;
235     unsigned char colorMask[] = {1, 1, 1, 1}, depthMask = 1;
236     unsigned int stencilMask = 0xffffffff;
237     bool isScissorEnabled = false;
238     bool isDitherEnabled = false;
239     if (initColor) {
240         g3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, colorClearValue);
241         g3d->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask);
242         g3d->clearColor(0, 0, 0, 0);
243         g3d->colorMask(true, true, true, true);
244     }
245     if (initDepth) {
246         g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue);
247         g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
248         g3d->clearDepth(0);
249         g3d->depthMask(true);
250     }
251     if (initStencil) {
252         g3d->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &stencilClearValue);
253         g3d->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask));
254         g3d->clearStencil(0);
255         g3d->stencilMask(0xffffffff);
256     }
257     isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST);
258     g3d->disable(GraphicsContext3D::SCISSOR_TEST);
259     isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER);
260     g3d->disable(GraphicsContext3D::DITHER);
261
262     g3d->clear(mask);
263
264     if (initColor) {
265         g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]);
266         g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
267     }
268     if (initDepth) {
269         g3d->clearDepth(depthClearValue);
270         g3d->depthMask(depthMask);
271     }
272     if (initStencil) {
273         g3d->clearStencil(stencilClearValue);
274         g3d->stencilMask(stencilMask);
275     }
276     if (isScissorEnabled)
277         g3d->enable(GraphicsContext3D::SCISSOR_TEST);
278     else
279         g3d->disable(GraphicsContext3D::SCISSOR_TEST);
280     if (isDitherEnabled)
281         g3d->enable(GraphicsContext3D::DITHER);
282     else
283         g3d->disable(GraphicsContext3D::DITHER);
284
285     if (initColor)
286         setInitialized(m_colorAttachment.get());
287     if (initDepth && initStencil && m_depthStencilAttachment)
288         setInitialized(m_depthStencilAttachment.get());
289     else {
290         if (initDepth)
291             setInitialized(m_depthAttachment.get());
292         if (initStencil)
293             setInitialized(m_stencilAttachment.get());
294     }
295     return true;
296 }
297
298 }
299
300 #endif // ENABLE(3D_CANVAS)