initial import
[vuplus_webkit] / Source / 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(WEBGL)
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     GC3Denum 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     , m_hasEverBeenBound(false)
79     , m_texTarget(0)
80     , m_texLevel(-1)
81 {
82     setObject(context()->graphicsContext3D()->createFramebuffer());
83 }
84
85 void WebGLFramebuffer::setAttachment(GC3Denum attachment, GC3Denum texTarget, WebGLTexture* texture, GC3Dint level)
86 {
87     if (!object())
88         return;
89     if (texture && !texture->object())
90         texture = 0;
91     switch (attachment) {
92     case GraphicsContext3D::COLOR_ATTACHMENT0:
93         m_colorAttachment = texture;
94         if (texture) {
95             m_texTarget = texTarget;
96             m_texLevel = level;
97         }
98         break;
99     case GraphicsContext3D::DEPTH_ATTACHMENT:
100         m_depthAttachment = texture;
101         break;
102     case GraphicsContext3D::STENCIL_ATTACHMENT:
103         m_stencilAttachment = texture;
104         break;
105     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
106         m_depthStencilAttachment = texture;
107         break;
108     default:
109         return;
110     }
111 }
112
113 void WebGLFramebuffer::setAttachment(GC3Denum attachment, WebGLRenderbuffer* renderbuffer)
114 {
115     if (!object())
116         return;
117     if (renderbuffer && !renderbuffer->object())
118         renderbuffer = 0;
119     switch (attachment) {
120     case GraphicsContext3D::COLOR_ATTACHMENT0:
121         m_colorAttachment = renderbuffer;
122         break;
123     case GraphicsContext3D::DEPTH_ATTACHMENT:
124         m_depthAttachment = renderbuffer;
125         break;
126     case GraphicsContext3D::STENCIL_ATTACHMENT:
127         m_stencilAttachment = renderbuffer;
128         break;
129     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
130         m_depthStencilAttachment = renderbuffer;
131         break;
132     default:
133         return;
134     }
135 }
136
137 WebGLObject* WebGLFramebuffer::getAttachment(GC3Denum attachment) const
138 {
139     if (!object())
140         return 0;
141     switch (attachment) {
142     case GraphicsContext3D::COLOR_ATTACHMENT0:
143         return m_colorAttachment.get();
144     case GraphicsContext3D::DEPTH_ATTACHMENT:
145         return m_depthAttachment.get();
146     case GraphicsContext3D::STENCIL_ATTACHMENT:
147         return m_stencilAttachment.get();
148     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
149         return m_depthStencilAttachment.get();
150     default:
151         return 0;
152     }
153 }
154
155 void WebGLFramebuffer::removeAttachment(WebGLObject* attachment)
156 {
157     if (!object())
158         return;
159     if (attachment == m_colorAttachment.get())
160         m_colorAttachment = 0;
161     else if (attachment == m_depthAttachment.get())
162         m_depthAttachment = 0;
163     else if (attachment == m_stencilAttachment.get())
164         m_stencilAttachment = 0;
165     else if (attachment == m_depthStencilAttachment.get())
166         m_depthStencilAttachment = 0;
167     else
168         return;
169 }
170
171 GC3Dsizei WebGLFramebuffer::getWidth() const
172 {
173     if (!object() || !isColorAttached())
174         return 0;
175     if (m_colorAttachment->isRenderbuffer())
176         return (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getWidth();
177     if (m_colorAttachment->isTexture())
178         return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getWidth(m_texTarget, m_texLevel);
179     ASSERT_NOT_REACHED();
180     return 0;
181 }
182
183 GC3Dsizei WebGLFramebuffer::getHeight() const
184 {
185     if (!object() || !isColorAttached())
186         return 0;
187     if (m_colorAttachment->isRenderbuffer())
188         return (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getHeight();
189     if (m_colorAttachment->isTexture())
190         return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getHeight(m_texTarget, m_texLevel);
191     ASSERT_NOT_REACHED();
192     return 0;
193 }
194
195 GC3Denum WebGLFramebuffer::getColorBufferFormat() const
196 {
197     if (!object() || !isColorAttached())
198         return 0;
199     if (m_colorAttachment->isRenderbuffer()) {
200         unsigned long format = (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getInternalFormat();
201         switch (format) {
202         case GraphicsContext3D::RGBA4:
203         case GraphicsContext3D::RGB5_A1:
204             return GraphicsContext3D::RGBA;
205         case GraphicsContext3D::RGB565:
206             return GraphicsContext3D::RGB;
207         }
208         return 0;
209     }
210     if (m_colorAttachment->isTexture())
211         return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getInternalFormat(m_texTarget, m_texLevel);
212     ASSERT_NOT_REACHED();
213     return 0;
214 }
215
216 bool WebGLFramebuffer::isIncomplete(bool checkInternalFormat) const
217 {
218     unsigned int count = 0;
219     if (isDepthAttached()) {
220         if (checkInternalFormat && getInternalFormat(m_depthAttachment.get()) != GraphicsContext3D::DEPTH_COMPONENT16)
221             return true;
222         count++;
223     }
224     if (isStencilAttached()) {
225         if (checkInternalFormat && getInternalFormat(m_stencilAttachment.get()) != GraphicsContext3D::STENCIL_INDEX8)
226             return true;
227         count++;
228     }
229     if (isDepthStencilAttached()) {
230         if (checkInternalFormat && getInternalFormat(m_depthStencilAttachment.get()) != GraphicsContext3D::DEPTH_STENCIL)
231             return true;
232         if (!isValid(m_depthStencilAttachment.get()))
233             return true;
234         count++;
235     }
236     if (count > 1)
237         return true;
238     return false;
239 }
240
241 bool WebGLFramebuffer::onAccess(bool needToInitializeRenderbuffers)
242 {
243     if (isIncomplete(true))
244         return false;
245     if (needToInitializeRenderbuffers)
246         return initializeRenderbuffers();
247     return true;
248 }
249
250 void WebGLFramebuffer::deleteObjectImpl(Platform3DObject object)
251 {
252     context()->graphicsContext3D()->deleteFramebuffer(object);
253     m_colorAttachment = 0;
254     m_depthAttachment = 0;
255     m_stencilAttachment = 0;
256     m_depthStencilAttachment = 0;
257 }
258
259 bool WebGLFramebuffer::initializeRenderbuffers()
260 {
261     ASSERT(object());
262     bool initColor = false, initDepth = false, initStencil = false;
263     GC3Dbitfield mask = 0;
264     if (isUninitialized(m_colorAttachment.get())) {
265         initColor = true;
266         mask |= GraphicsContext3D::COLOR_BUFFER_BIT;
267     }
268     if (isUninitialized(m_depthAttachment.get())) {
269         initDepth = true;
270         mask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
271     }
272     if (isUninitialized(m_stencilAttachment.get())) {
273         initStencil = true;
274         mask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
275     }
276     if (isUninitialized(m_depthStencilAttachment.get())) {
277         initDepth = true;
278         initStencil = true;
279         mask |= (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT);
280     }
281     if (!initColor && !initDepth && !initStencil)
282         return true;
283
284     // We only clear un-initialized renderbuffers when they are ready to be
285     // read, i.e., when the framebuffer is complete.
286     GraphicsContext3D* g3d = context()->graphicsContext3D();
287     if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
288         return false;
289
290     GC3Dfloat colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0;
291     GC3Dint stencilClearValue = 0;
292     GC3Dboolean colorMask[] = {0, 0, 0, 0}, depthMask = 0;
293     GC3Duint stencilMask = 0xffffffff;
294     GC3Dboolean isScissorEnabled = 0;
295     GC3Dboolean isDitherEnabled = 0;
296     if (initColor) {
297         g3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, colorClearValue);
298         g3d->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask);
299         g3d->clearColor(0, 0, 0, 0);
300         g3d->colorMask(true, true, true, true);
301     }
302     if (initDepth) {
303         g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue);
304         g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
305         g3d->clearDepth(0);
306         g3d->depthMask(true);
307     }
308     if (initStencil) {
309         g3d->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &stencilClearValue);
310         g3d->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<GC3Dint*>(&stencilMask));
311         g3d->clearStencil(0);
312         g3d->stencilMask(0xffffffff);
313     }
314     isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST);
315     g3d->disable(GraphicsContext3D::SCISSOR_TEST);
316     isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER);
317     g3d->disable(GraphicsContext3D::DITHER);
318
319     g3d->clear(mask);
320
321     if (initColor) {
322         g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]);
323         g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
324     }
325     if (initDepth) {
326         g3d->clearDepth(depthClearValue);
327         g3d->depthMask(depthMask);
328     }
329     if (initStencil) {
330         g3d->clearStencil(stencilClearValue);
331         g3d->stencilMask(stencilMask);
332     }
333     if (isScissorEnabled)
334         g3d->enable(GraphicsContext3D::SCISSOR_TEST);
335     else
336         g3d->disable(GraphicsContext3D::SCISSOR_TEST);
337     if (isDitherEnabled)
338         g3d->enable(GraphicsContext3D::DITHER);
339     else
340         g3d->disable(GraphicsContext3D::DITHER);
341
342     if (initColor)
343         setInitialized(m_colorAttachment.get());
344     if (initDepth && initStencil && m_depthStencilAttachment)
345         setInitialized(m_depthStencilAttachment.get());
346     else {
347         if (initDepth)
348             setInitialized(m_depthAttachment.get());
349         if (initStencil)
350             setInitialized(m_stencilAttachment.get());
351     }
352     return true;
353 }
354
355 }
356
357 #endif // ENABLE(WEBGL)