2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "WebGLFramebuffer.h"
32 #include "WebGLRenderingContext.h"
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)
42 ASSERT(buffer && buffer->isRenderbuffer());
43 return (reinterpret_cast<WebGLRenderbuffer*>(buffer))->getInternalFormat();
46 bool isUninitialized(WebGLObject* attachedObject)
48 if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()
49 && !(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isInitialized())
54 void setInitialized(WebGLObject* attachedObject)
56 if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer())
57 (reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->setInitialized();
60 bool isValid(WebGLObject* attachedObject)
62 if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()) {
63 if (!(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isValid())
69 } // anonymous namespace
71 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx)
73 return adoptRef(new WebGLFramebuffer(ctx));
76 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx)
79 setObject(context()->graphicsContext3D()->createFramebuffer());
82 void WebGLFramebuffer::setAttachment(unsigned long attachment, WebGLObject* attachedObject)
86 if (attachedObject && !attachedObject->object())
89 case GraphicsContext3D::COLOR_ATTACHMENT0:
90 m_colorAttachment = attachedObject;
92 case GraphicsContext3D::DEPTH_ATTACHMENT:
93 m_depthAttachment = attachedObject;
95 case GraphicsContext3D::STENCIL_ATTACHMENT:
96 m_stencilAttachment = attachedObject;
98 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
99 m_depthStencilAttachment = attachedObject;
106 WebGLObject* WebGLFramebuffer::getAttachment(unsigned long attachment) const
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();
124 void WebGLFramebuffer::removeAttachment(WebGLObject* attachment)
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;
140 unsigned long WebGLFramebuffer::getColorBufferFormat() const
142 if (object() && m_colorAttachment && m_colorAttachment->object()) {
143 if (m_colorAttachment->isRenderbuffer()) {
144 unsigned long format = (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getInternalFormat();
146 case GraphicsContext3D::RGBA4:
147 case GraphicsContext3D::RGB5_A1:
148 return GraphicsContext3D::RGBA;
149 case GraphicsContext3D::RGB565:
150 return GraphicsContext3D::RGB;
152 } else if (m_colorAttachment->isTexture())
153 return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getInternalFormat(0);
158 bool WebGLFramebuffer::isIncomplete(bool checkInternalFormat) const
160 unsigned int count = 0;
161 if (isDepthAttached()) {
162 if (checkInternalFormat && getInternalFormat(m_depthAttachment.get()) != GraphicsContext3D::DEPTH_COMPONENT16)
166 if (isStencilAttached()) {
167 if (checkInternalFormat && getInternalFormat(m_stencilAttachment.get()) != GraphicsContext3D::STENCIL_INDEX8)
171 if (isDepthStencilAttached()) {
172 if (checkInternalFormat && getInternalFormat(m_depthStencilAttachment.get()) != GraphicsContext3D::DEPTH_STENCIL)
174 if (!isValid(m_depthStencilAttachment.get()))
183 bool WebGLFramebuffer::onAccess()
185 if (isIncomplete(true))
187 return initializeRenderbuffers();
190 void WebGLFramebuffer::deleteObjectImpl(Platform3DObject object)
193 context()->graphicsContext3D()->deleteFramebuffer(object);
194 m_colorAttachment = 0;
195 m_depthAttachment = 0;
196 m_stencilAttachment = 0;
197 m_depthStencilAttachment = 0;
200 bool WebGLFramebuffer::initializeRenderbuffers()
203 if (!isColorAttached())
205 bool initColor = false, initDepth = false, initStencil = false;
206 unsigned long mask = 0;
207 if (isUninitialized(m_colorAttachment.get())) {
209 mask |= GraphicsContext3D::COLOR_BUFFER_BIT;
211 if (isUninitialized(m_depthAttachment.get())) {
213 mask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
215 if (isUninitialized(m_stencilAttachment.get())) {
217 mask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
219 if (isUninitialized(m_depthStencilAttachment.get())) {
222 mask |= (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT);
224 if (!initColor && !initDepth && !initStencil)
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)
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;
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);
246 g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue);
247 g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
249 g3d->depthMask(true);
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);
257 isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST);
258 g3d->disable(GraphicsContext3D::SCISSOR_TEST);
259 isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER);
260 g3d->disable(GraphicsContext3D::DITHER);
265 g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]);
266 g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
269 g3d->clearDepth(depthClearValue);
270 g3d->depthMask(depthMask);
273 g3d->clearStencil(stencilClearValue);
274 g3d->stencilMask(stencilMask);
276 if (isScissorEnabled)
277 g3d->enable(GraphicsContext3D::SCISSOR_TEST);
279 g3d->disable(GraphicsContext3D::SCISSOR_TEST);
281 g3d->enable(GraphicsContext3D::DITHER);
283 g3d->disable(GraphicsContext3D::DITHER);
286 setInitialized(m_colorAttachment.get());
287 if (initDepth && initStencil && m_depthStencilAttachment)
288 setInitialized(m_depthStencilAttachment.get());
291 setInitialized(m_depthAttachment.get());
293 setInitialized(m_stencilAttachment.get());
300 #endif // ENABLE(3D_CANVAS)