OSDN Git Service

Implement a Radiance prototype.
[android-x86/external-swiftshader.git] / src / Radiance / libRAD / Framebuffer.cpp
1 // SwiftShader Software Renderer
2 //
3 // Copyright(c) 2005-2013 TransGaming Inc.
4 //
5 // All rights reserved. No part of this software may be copied, distributed, transmitted,
6 // transcribed, stored in a retrieval system, translated into any human or computer
7 // language by any means, or disclosed to third parties without the explicit written
8 // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
9 // or implied, including but not limited to any patent rights, are granted to you.
10 //
11
12 // Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer
13 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
14
15 #include "Framebuffer.h"
16
17 #include "main.h"
18 #include "Renderbuffer.h"
19 #include "Texture.h"
20 #include "utilities.h"
21
22 namespace es2
23 {
24
25 Framebuffer::Framebuffer()
26 {
27         mColorbufferType = GL_NONE;
28         mDepthbufferType = GL_NONE;
29         mStencilbufferType = GL_NONE;
30 }
31
32 Framebuffer::~Framebuffer()
33 {
34         mColorbufferPointer.set(NULL);
35         mDepthbufferPointer.set(NULL);
36         mStencilbufferPointer.set(NULL);
37 }
38
39 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
40 {
41         Context *context = getContext();
42         Renderbuffer *buffer = NULL;
43
44         if(type == GL_NONE)
45         {
46                 buffer = NULL;
47         }
48         else if(type == GL_RENDERBUFFER)
49         {
50                 buffer = context->getRenderbuffer(handle);
51         }
52         else if(IsTextureTarget(type))
53         {
54                 buffer = context->getTexture(handle)->getRenderbuffer(type);
55         }
56         else
57         {
58                 UNREACHABLE();
59         }
60
61         return buffer;
62 }
63
64 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
65 {
66         mColorbufferType = (colorbuffer != 0) ? type : GL_NONE;
67         mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
68 }
69
70 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
71 {
72         mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE;
73         mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
74 }
75
76 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
77 {
78         mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE;
79         mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
80 }
81
82 void Framebuffer::detachTexture(GLuint texture)
83 {
84         if(mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType))
85         {
86                 mColorbufferType = GL_NONE;
87                 mColorbufferPointer.set(NULL);
88         }
89
90         if(mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
91         {
92                 mDepthbufferType = GL_NONE;
93                 mDepthbufferPointer.set(NULL);
94         }
95
96         if(mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType))
97         {
98                 mStencilbufferType = GL_NONE;
99                 mStencilbufferPointer.set(NULL);
100         }
101 }
102
103 void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
104 {
105         if(mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
106         {
107                 mColorbufferType = GL_NONE;
108                 mColorbufferPointer.set(NULL);
109         }
110
111         if(mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
112         {
113                 mDepthbufferType = GL_NONE;
114                 mDepthbufferPointer.set(NULL);
115         }
116
117         if(mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
118         {
119                 mStencilbufferType = GL_NONE;
120                 mStencilbufferPointer.set(NULL);
121         }
122 }
123
124 // Increments refcount on surface.
125 // caller must Release() the returned surface
126 egl::Image *Framebuffer::getRenderTarget()
127 {
128         Renderbuffer *colorbuffer = mColorbufferPointer.get();
129
130         if(colorbuffer)
131         {
132                 return colorbuffer->getRenderTarget();
133         }
134
135         return NULL;
136 }
137
138 // Increments refcount on surface.
139 // caller must Release() the returned surface
140 egl::Image *Framebuffer::getDepthStencil()
141 {
142         Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
143         
144         if(!depthstencilbuffer)
145         {
146                 depthstencilbuffer = mStencilbufferPointer.get();
147         }
148
149         if(depthstencilbuffer)
150         {
151                 return depthstencilbuffer->getRenderTarget();
152         }
153
154         return NULL;
155 }
156
157 Renderbuffer *Framebuffer::getColorbuffer()
158 {
159         return mColorbufferPointer.get();
160 }
161
162 Renderbuffer *Framebuffer::getDepthbuffer()
163 {
164         return mDepthbufferPointer.get();
165 }
166
167 Renderbuffer *Framebuffer::getStencilbuffer()
168 {
169         return mStencilbufferPointer.get();
170 }
171
172 GLenum Framebuffer::getColorbufferType()
173 {
174         return mColorbufferType;
175 }
176
177 GLenum Framebuffer::getDepthbufferType()
178 {
179         return mDepthbufferType;
180 }
181
182 GLenum Framebuffer::getStencilbufferType()
183 {
184         return mStencilbufferType;
185 }
186
187 GLuint Framebuffer::getColorbufferHandle()
188 {
189         return mColorbufferPointer.id();
190 }
191
192 GLuint Framebuffer::getDepthbufferHandle()
193 {
194         return mDepthbufferPointer.id();
195 }
196
197 GLuint Framebuffer::getStencilbufferHandle()
198 {
199         return mStencilbufferPointer.id();
200 }
201
202 bool Framebuffer::hasStencil()
203 {
204         if(mStencilbufferType != GL_NONE)
205         {
206                 Renderbuffer *stencilbufferObject = getStencilbuffer();
207
208                 if(stencilbufferObject)
209                 {
210                         return stencilbufferObject->getStencilSize() > 0;
211                 }
212         }
213
214         return false;
215 }
216
217 GLenum Framebuffer::completeness()
218 {
219         int width;
220         int height;
221         int samples;
222
223         return completeness(width, height, samples);
224 }
225
226 GLenum Framebuffer::completeness(int &width, int &height, int &samples)
227 {
228         width = -1;
229         height = -1;
230         samples = -1;
231
232         if(mColorbufferType != GL_NONE)
233         {
234                 Renderbuffer *colorbuffer = getColorbuffer();
235
236                 if(!colorbuffer)
237                 {
238                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
239                 }
240
241                 if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
242                 {
243                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
244                 }
245
246                 if(mColorbufferType == GL_RENDERBUFFER)
247                 {
248                         if(!es2::IsColorRenderable(colorbuffer->getFormat()))
249                         {
250                                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
251                         }
252                 }
253                 else if(IsTextureTarget(mColorbufferType))
254                 {
255                         GLenum format = colorbuffer->getFormat();
256
257                         if(IsCompressed(format) ||
258                            format == GL_ALPHA ||
259                            format == GL_LUMINANCE ||
260                            format == GL_LUMINANCE_ALPHA)
261                         {
262                                 return GL_FRAMEBUFFER_UNSUPPORTED;
263                         }
264
265                         if(es2::IsDepthTexture(format) || es2::IsStencilTexture(format))
266                         {
267                                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
268                         }
269                 }
270                 else
271                 {
272                         UNREACHABLE();
273                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
274                 }
275
276                 width = colorbuffer->getWidth();
277                 height = colorbuffer->getHeight();
278                 samples = colorbuffer->getSamples();
279         }
280
281         Renderbuffer *depthbuffer = NULL;
282         Renderbuffer *stencilbuffer = NULL;
283
284         if(mDepthbufferType != GL_NONE)
285         {
286                 depthbuffer = getDepthbuffer();
287
288                 if(!depthbuffer)
289                 {
290                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
291                 }
292
293                 if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
294                 {
295                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
296                 }
297
298                 if(mDepthbufferType == GL_RENDERBUFFER)
299                 {
300                         if(!es2::IsDepthRenderable(depthbuffer->getFormat()))
301                         {
302                                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
303                         }
304                 }
305                 else if(IsTextureTarget(mDepthbufferType))
306                 {
307                         if(!es2::IsDepthTexture(depthbuffer->getFormat()))
308                         {
309                                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
310                         }
311                 }
312                 else
313                 {
314                         UNREACHABLE();
315                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
316                 }
317
318                 if(width == -1 || height == -1)
319                 {
320                         width = depthbuffer->getWidth();
321                         height = depthbuffer->getHeight();
322                         samples = depthbuffer->getSamples();
323                 }
324                 else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
325                 {
326                         return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
327                 }
328                 else if(samples != depthbuffer->getSamples())
329                 {
330                         return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
331                 }
332         }
333
334         if(mStencilbufferType != GL_NONE)
335         {
336                 stencilbuffer = getStencilbuffer();
337
338                 if(!stencilbuffer)
339                 {
340                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
341                 }
342
343                 if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
344                 {
345                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
346                 }
347
348                 if(mStencilbufferType == GL_RENDERBUFFER)
349                 {
350                         if(!es2::IsStencilRenderable(stencilbuffer->getFormat()))
351                         {
352                                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
353                         }
354                 }
355                 else if(IsTextureTarget(mStencilbufferType))
356                 {
357                         GLenum internalformat = stencilbuffer->getFormat();
358
359                         if(!es2::IsStencilTexture(internalformat))
360                         {
361                                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
362                         }
363                 }
364                 else
365                 {
366                         UNREACHABLE();
367                         return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
368                 }
369
370                 if(width == -1 || height == -1)
371                 {
372                         width = stencilbuffer->getWidth();
373                         height = stencilbuffer->getHeight();
374                         samples = stencilbuffer->getSamples();
375                 }
376                 else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
377                 {
378                         return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
379                 }
380                 else if(samples != stencilbuffer->getSamples())
381                 {
382                         return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
383                 }
384         }
385
386         // If we have both a depth and stencil buffer, they must refer to the same object
387         // since we only support packed_depth_stencil and not separate depth and stencil
388         if(depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer))
389         {
390                 return GL_FRAMEBUFFER_UNSUPPORTED;
391         }
392
393         // We need to have at least one attachment to be complete
394         if(width == -1 || height == -1)
395         {
396                 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
397         }
398
399         return GL_FRAMEBUFFER_COMPLETE;
400 }
401
402 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
403 {
404         mColorbufferPointer.set(new Renderbuffer(0, colorbuffer));
405
406         Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
407         mDepthbufferPointer.set(depthStencilRenderbuffer);
408         mStencilbufferPointer.set(depthStencilRenderbuffer);
409
410         mColorbufferType = GL_RENDERBUFFER;
411         mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
412         mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
413 }
414
415 GLenum DefaultFramebuffer::completeness()
416 {
417         // The default framebuffer should always be complete
418         ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
419
420         return GL_FRAMEBUFFER_COMPLETE;
421 }
422
423 }