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.
getInternalFormat(WebGLObject * buffer)40 GC3Denum getInternalFormat(WebGLObject* buffer)
41 {
42 ASSERT(buffer && buffer->isRenderbuffer());
43 return (reinterpret_cast<WebGLRenderbuffer*>(buffer))->getInternalFormat();
44 }
45
isUninitialized(WebGLObject * attachedObject)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
setInitialized(WebGLObject * attachedObject)54 void setInitialized(WebGLObject* attachedObject)
55 {
56 if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer())
57 (reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->setInitialized();
58 }
59
isValid(WebGLObject * attachedObject)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
create(WebGLRenderingContext * ctx)71 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx)
72 {
73 return adoptRef(new WebGLFramebuffer(ctx));
74 }
75
WebGLFramebuffer(WebGLRenderingContext * ctx)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
setAttachment(GC3Denum attachment,GC3Denum texTarget,WebGLTexture * texture,GC3Dint level)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
setAttachment(GC3Denum attachment,WebGLRenderbuffer * renderbuffer)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
getAttachment(GC3Denum attachment) const137 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
removeAttachment(WebGLObject * attachment)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
getWidth() const171 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
getHeight() const183 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
getColorBufferFormat() const195 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
isIncomplete(bool checkInternalFormat) const216 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
onAccess(bool needToInitializeRenderbuffers)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
deleteObjectImpl(Platform3DObject object)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
initializeRenderbuffers()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)
358