|
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 #include "WebGLRenderingContext.h" |
|
32 |
|
33 namespace WebCore { |
|
34 |
|
35 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx) |
|
36 { |
|
37 return adoptRef(new WebGLFramebuffer(ctx)); |
|
38 } |
|
39 |
|
40 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx) |
|
41 : CanvasObject(ctx) |
|
42 , m_colorAttachment(0) |
|
43 , m_depthAttachment(0) |
|
44 , m_stencilAttachment(0) |
|
45 , m_depthStencilAttachment(0) |
|
46 { |
|
47 setObject(context()->graphicsContext3D()->createFramebuffer()); |
|
48 } |
|
49 |
|
50 void WebGLFramebuffer::setAttachment(unsigned long attachment, CanvasObject* attachedObject) |
|
51 { |
|
52 if (!object()) |
|
53 return; |
|
54 if (attachedObject && !attachedObject->object()) |
|
55 attachedObject = 0; |
|
56 switch (attachment) { |
|
57 case GraphicsContext3D::COLOR_ATTACHMENT0: |
|
58 m_colorAttachment = attachedObject; |
|
59 break; |
|
60 case GraphicsContext3D::DEPTH_ATTACHMENT: |
|
61 m_depthAttachment = attachedObject; |
|
62 break; |
|
63 case GraphicsContext3D::STENCIL_ATTACHMENT: |
|
64 m_stencilAttachment = attachedObject; |
|
65 break; |
|
66 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: |
|
67 m_depthStencilAttachment = attachedObject; |
|
68 break; |
|
69 default: |
|
70 return; |
|
71 } |
|
72 initializeRenderbuffers(); |
|
73 } |
|
74 |
|
75 void WebGLFramebuffer::onBind() |
|
76 { |
|
77 initializeRenderbuffers(); |
|
78 } |
|
79 |
|
80 void WebGLFramebuffer::onAttachedObjectChange(CanvasObject* object) |
|
81 { |
|
82 // Currently object == 0 is not considered, but this might change if the |
|
83 // lifespan of CanvasObject changes. |
|
84 if (object |
|
85 && (object == m_colorAttachment || object == m_depthAttachment |
|
86 || object == m_stencilAttachment || object == m_depthStencilAttachment)) |
|
87 initializeRenderbuffers(); |
|
88 } |
|
89 |
|
90 unsigned long WebGLFramebuffer::getColorBufferFormat() |
|
91 { |
|
92 if (object() && m_colorAttachment && m_colorAttachment->object()) { |
|
93 if (m_colorAttachment->isRenderbuffer()) { |
|
94 unsigned long format = (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment))->getInternalFormat(); |
|
95 switch (format) { |
|
96 case GraphicsContext3D::RGBA4: |
|
97 case GraphicsContext3D::RGB5_A1: |
|
98 return GraphicsContext3D::RGBA; |
|
99 case GraphicsContext3D::RGB565: |
|
100 return GraphicsContext3D::RGB; |
|
101 } |
|
102 } else if (m_colorAttachment->isTexture()) |
|
103 return (reinterpret_cast<WebGLTexture*>(m_colorAttachment))->getInternalFormat(); |
|
104 } |
|
105 return 0; |
|
106 } |
|
107 |
|
108 void WebGLFramebuffer::_deleteObject(Platform3DObject object) |
|
109 { |
|
110 context()->graphicsContext3D()->deleteFramebuffer(object); |
|
111 } |
|
112 |
|
113 bool WebGLFramebuffer::isUninitialized(CanvasObject* attachedObject) |
|
114 { |
|
115 if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer() |
|
116 && !(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isInitialized()) |
|
117 return true; |
|
118 return false; |
|
119 } |
|
120 |
|
121 void WebGLFramebuffer::setInitialized(CanvasObject* attachedObject) |
|
122 { |
|
123 if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()) |
|
124 (reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->setInitialized(); |
|
125 } |
|
126 |
|
127 void WebGLFramebuffer::initializeRenderbuffers() |
|
128 { |
|
129 if (!object()) |
|
130 return; |
|
131 bool initColor = false, initDepth = false, initStencil = false; |
|
132 unsigned long mask = 0; |
|
133 if (isUninitialized(m_colorAttachment)) { |
|
134 initColor = true; |
|
135 mask |= GraphicsContext3D::COLOR_BUFFER_BIT; |
|
136 } |
|
137 if (isUninitialized(m_depthAttachment)) { |
|
138 initDepth = true; |
|
139 mask |= GraphicsContext3D::DEPTH_BUFFER_BIT; |
|
140 } |
|
141 if (isUninitialized(m_stencilAttachment)) { |
|
142 initStencil = true; |
|
143 mask |= GraphicsContext3D::STENCIL_BUFFER_BIT; |
|
144 } |
|
145 if (isUninitialized(m_depthStencilAttachment)) { |
|
146 initDepth = true; |
|
147 initStencil = true; |
|
148 mask |= (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT); |
|
149 } |
|
150 if (!initColor && !initDepth && !initStencil) |
|
151 return; |
|
152 |
|
153 // We only clear un-initialized renderbuffers when they are ready to be |
|
154 // read, i.e., when the framebuffer is complete. |
|
155 GraphicsContext3D* g3d = context()->graphicsContext3D(); |
|
156 if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) |
|
157 return; |
|
158 |
|
159 float colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0; |
|
160 int stencilClearValue = 0; |
|
161 unsigned char colorMask[] = {1, 1, 1, 1}, depthMask = 1, stencilMask = 1; |
|
162 bool isScissorEnabled = false; |
|
163 bool isDitherEnabled = false; |
|
164 if (initColor) { |
|
165 g3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, colorClearValue); |
|
166 g3d->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask); |
|
167 g3d->clearColor(0, 0, 0, 0); |
|
168 g3d->colorMask(true, true, true, true); |
|
169 } |
|
170 if (initDepth) { |
|
171 g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue); |
|
172 g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask); |
|
173 g3d->clearDepth(0); |
|
174 g3d->depthMask(true); |
|
175 } |
|
176 if (initStencil) { |
|
177 g3d->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &stencilClearValue); |
|
178 g3d->getBooleanv(GraphicsContext3D::STENCIL_WRITEMASK, &stencilMask); |
|
179 g3d->clearStencil(0); |
|
180 g3d->stencilMask(true); |
|
181 } |
|
182 isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST); |
|
183 g3d->disable(GraphicsContext3D::SCISSOR_TEST); |
|
184 isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER); |
|
185 g3d->disable(GraphicsContext3D::DITHER); |
|
186 |
|
187 g3d->clear(mask); |
|
188 |
|
189 if (initColor) { |
|
190 g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]); |
|
191 g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); |
|
192 } |
|
193 if (initDepth) { |
|
194 g3d->clearDepth(depthClearValue); |
|
195 g3d->depthMask(depthMask); |
|
196 } |
|
197 if (initStencil) { |
|
198 g3d->clearStencil(stencilClearValue); |
|
199 g3d->stencilMask(stencilMask); |
|
200 } |
|
201 if (isScissorEnabled) |
|
202 g3d->enable(GraphicsContext3D::SCISSOR_TEST); |
|
203 else |
|
204 g3d->disable(GraphicsContext3D::SCISSOR_TEST); |
|
205 if (isDitherEnabled) |
|
206 g3d->enable(GraphicsContext3D::DITHER); |
|
207 else |
|
208 g3d->disable(GraphicsContext3D::DITHER); |
|
209 |
|
210 if (initColor) |
|
211 setInitialized(m_colorAttachment); |
|
212 if (initDepth && initStencil && m_depthStencilAttachment) |
|
213 setInitialized(m_depthStencilAttachment); |
|
214 else { |
|
215 if (initDepth) |
|
216 setInitialized(m_depthAttachment); |
|
217 if (initStencil) |
|
218 setInitialized(m_stencilAttachment); |
|
219 } |
|
220 } |
|
221 |
|
222 } |
|
223 |
|
224 #endif // ENABLE(3D_CANVAS) |