1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer
16 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
17
18 #include "Framebuffer.h"
19
20 #include "main.h"
21 #include "Renderbuffer.h"
22 #include "Texture.h"
23 #include "utilities.h"
24
25 namespace es1
26 {
27
Framebuffer()28 Framebuffer::Framebuffer()
29 {
30 mColorbufferType = GL_NONE_OES;
31 mDepthbufferType = GL_NONE_OES;
32 mStencilbufferType = GL_NONE_OES;
33 }
34
~Framebuffer()35 Framebuffer::~Framebuffer()
36 {
37 mColorbufferPointer = nullptr;
38 mDepthbufferPointer = nullptr;
39 mStencilbufferPointer = nullptr;
40 }
41
lookupRenderbuffer(GLenum type,GLuint handle,GLint level) const42 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle, GLint level) const
43 {
44 Context *context = getContext();
45 Renderbuffer *buffer = nullptr;
46
47 if(type == GL_NONE_OES)
48 {
49 buffer = nullptr;
50 }
51 else if(type == GL_RENDERBUFFER_OES)
52 {
53 buffer = context->getRenderbuffer(handle);
54 }
55 else if(IsTextureTarget(type))
56 {
57 buffer = context->getTexture(handle)->getRenderbuffer(type, level);
58 }
59 else UNREACHABLE(type);
60
61 return buffer;
62 }
63
setColorbuffer(GLenum type,GLuint colorbuffer,GLint level)64 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer, GLint level)
65 {
66 mColorbufferType = (colorbuffer != 0) ? type : GL_NONE_OES;
67 mColorbufferPointer = lookupRenderbuffer(type, colorbuffer, level);
68 }
69
setDepthbuffer(GLenum type,GLuint depthbuffer,GLint level)70 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level)
71 {
72 mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE_OES;
73 mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer, level);
74 }
75
setStencilbuffer(GLenum type,GLuint stencilbuffer,GLint level)76 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level)
77 {
78 mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE_OES;
79 mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer, level);
80 }
81
detachTexture(GLuint texture)82 void Framebuffer::detachTexture(GLuint texture)
83 {
84 if(mColorbufferPointer.name() == texture && IsTextureTarget(mColorbufferType))
85 {
86 mColorbufferType = GL_NONE_OES;
87 mColorbufferPointer = nullptr;
88 }
89
90 if(mDepthbufferPointer.name() == texture && IsTextureTarget(mDepthbufferType))
91 {
92 mDepthbufferType = GL_NONE_OES;
93 mDepthbufferPointer = nullptr;
94 }
95
96 if(mStencilbufferPointer.name() == texture && IsTextureTarget(mStencilbufferType))
97 {
98 mStencilbufferType = GL_NONE_OES;
99 mStencilbufferPointer = nullptr;
100 }
101 }
102
detachRenderbuffer(GLuint renderbuffer)103 void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
104 {
105 if(mColorbufferPointer.name() == renderbuffer && mColorbufferType == GL_RENDERBUFFER_OES)
106 {
107 mColorbufferType = GL_NONE_OES;
108 mColorbufferPointer = nullptr;
109 }
110
111 if(mDepthbufferPointer.name() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER_OES)
112 {
113 mDepthbufferType = GL_NONE_OES;
114 mDepthbufferPointer = nullptr;
115 }
116
117 if(mStencilbufferPointer.name() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER_OES)
118 {
119 mStencilbufferType = GL_NONE_OES;
120 mStencilbufferPointer = nullptr;
121 }
122 }
123
124 // Increments refcount on surface.
125 // caller must Release() the returned surface
getRenderTarget()126 egl::Image *Framebuffer::getRenderTarget()
127 {
128 Renderbuffer *colorbuffer = mColorbufferPointer;
129
130 if(colorbuffer)
131 {
132 return colorbuffer->getRenderTarget();
133 }
134
135 return nullptr;
136 }
137
138 // Increments refcount on surface.
139 // caller must Release() the returned surface
getDepthBuffer()140 egl::Image *Framebuffer::getDepthBuffer()
141 {
142 Renderbuffer *depthbuffer = mDepthbufferPointer;
143
144 if(depthbuffer)
145 {
146 return depthbuffer->getRenderTarget();
147 }
148
149 return nullptr;
150 }
151
152 // Increments refcount on surface.
153 // caller must Release() the returned surface
getStencilBuffer()154 egl::Image *Framebuffer::getStencilBuffer()
155 {
156 Renderbuffer *stencilbuffer = mStencilbufferPointer;
157
158 if(stencilbuffer)
159 {
160 return stencilbuffer->getRenderTarget();
161 }
162
163 return nullptr;
164 }
165
getColorbuffer()166 Renderbuffer *Framebuffer::getColorbuffer()
167 {
168 return mColorbufferPointer;
169 }
170
getDepthbuffer()171 Renderbuffer *Framebuffer::getDepthbuffer()
172 {
173 return mDepthbufferPointer;
174 }
175
getStencilbuffer()176 Renderbuffer *Framebuffer::getStencilbuffer()
177 {
178 return mStencilbufferPointer;
179 }
180
getColorbufferType()181 GLenum Framebuffer::getColorbufferType()
182 {
183 return mColorbufferType;
184 }
185
getDepthbufferType()186 GLenum Framebuffer::getDepthbufferType()
187 {
188 return mDepthbufferType;
189 }
190
getStencilbufferType()191 GLenum Framebuffer::getStencilbufferType()
192 {
193 return mStencilbufferType;
194 }
195
getColorbufferName()196 GLuint Framebuffer::getColorbufferName()
197 {
198 return mColorbufferPointer.name();
199 }
200
getDepthbufferName()201 GLuint Framebuffer::getDepthbufferName()
202 {
203 return mDepthbufferPointer.name();
204 }
205
getStencilbufferName()206 GLuint Framebuffer::getStencilbufferName()
207 {
208 return mStencilbufferPointer.name();
209 }
210
hasStencil()211 bool Framebuffer::hasStencil()
212 {
213 if(mStencilbufferType != GL_NONE_OES)
214 {
215 Renderbuffer *stencilbufferObject = getStencilbuffer();
216
217 if(stencilbufferObject)
218 {
219 return stencilbufferObject->getStencilSize() > 0;
220 }
221 }
222
223 return false;
224 }
225
completeness()226 GLenum Framebuffer::completeness()
227 {
228 int width;
229 int height;
230 int samples;
231
232 return completeness(width, height, samples);
233 }
234
completeness(int & width,int & height,int & samples)235 GLenum Framebuffer::completeness(int &width, int &height, int &samples)
236 {
237 width = -1;
238 height = -1;
239 samples = -1;
240
241 if(mColorbufferType != GL_NONE_OES)
242 {
243 Renderbuffer *colorbuffer = getColorbuffer();
244
245 if(!colorbuffer)
246 {
247 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
248 }
249
250 if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
251 {
252 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
253 }
254
255 if(mColorbufferType == GL_RENDERBUFFER_OES)
256 {
257 if(!IsColorRenderable(colorbuffer->getFormat()))
258 {
259 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
260 }
261 }
262 else if(IsTextureTarget(mColorbufferType))
263 {
264 GLenum format = colorbuffer->getFormat();
265
266 if(!IsColorRenderable(format))
267 {
268 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
269 }
270
271 if(IsDepthTexture(format) || IsStencilTexture(format))
272 {
273 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
274 }
275 }
276 else
277 {
278 UNREACHABLE(mColorbufferType);
279 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
280 }
281
282 width = colorbuffer->getWidth();
283 height = colorbuffer->getHeight();
284 samples = colorbuffer->getSamples();
285 }
286
287 Renderbuffer *depthbuffer = nullptr;
288 Renderbuffer *stencilbuffer = nullptr;
289
290 if(mDepthbufferType != GL_NONE_OES)
291 {
292 depthbuffer = getDepthbuffer();
293
294 if(!depthbuffer)
295 {
296 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
297 }
298
299 if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
300 {
301 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
302 }
303
304 if(mDepthbufferType == GL_RENDERBUFFER_OES)
305 {
306 if(!es1::IsDepthRenderable(depthbuffer->getFormat()))
307 {
308 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
309 }
310 }
311 else if(IsTextureTarget(mDepthbufferType))
312 {
313 if(!es1::IsDepthTexture(depthbuffer->getFormat()))
314 {
315 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
316 }
317 }
318 else
319 {
320 UNREACHABLE(mDepthbufferType);
321 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
322 }
323
324 if(width == -1 || height == -1)
325 {
326 width = depthbuffer->getWidth();
327 height = depthbuffer->getHeight();
328 samples = depthbuffer->getSamples();
329 }
330 else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
331 {
332 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES;
333 }
334 else if(samples != depthbuffer->getSamples())
335 {
336 UNREACHABLE(0);
337 }
338 }
339
340 if(mStencilbufferType != GL_NONE_OES)
341 {
342 stencilbuffer = getStencilbuffer();
343
344 if(!stencilbuffer)
345 {
346 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
347 }
348
349 if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
350 {
351 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
352 }
353
354 if(mStencilbufferType == GL_RENDERBUFFER_OES)
355 {
356 if(!es1::IsStencilRenderable(stencilbuffer->getFormat()))
357 {
358 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
359 }
360 }
361 else if(IsTextureTarget(mStencilbufferType))
362 {
363 GLenum internalformat = stencilbuffer->getFormat();
364
365 if(!es1::IsStencilTexture(internalformat))
366 {
367 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
368 }
369 }
370 else
371 {
372 UNREACHABLE(mStencilbufferType);
373 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES;
374 }
375
376 if(width == -1 || height == -1)
377 {
378 width = stencilbuffer->getWidth();
379 height = stencilbuffer->getHeight();
380 samples = stencilbuffer->getSamples();
381 }
382 else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
383 {
384 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES;
385 }
386 else if(samples != stencilbuffer->getSamples())
387 {
388 UNREACHABLE(0);
389 return GL_FRAMEBUFFER_UNSUPPORTED_OES; // GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_OES;
390 }
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_OES;
397 }
398
399 return GL_FRAMEBUFFER_COMPLETE_OES;
400 }
401
getImplementationColorReadFormat()402 GLenum Framebuffer::getImplementationColorReadFormat()
403 {
404 Renderbuffer *colorbuffer = mColorbufferPointer;
405
406 if(colorbuffer)
407 {
408 switch(colorbuffer->getFormat())
409 {
410 case GL_BGRA8_EXT: return GL_BGRA_EXT;
411 case GL_RGBA4_OES: return GL_RGBA;
412 case GL_RGB5_A1_OES: return GL_RGBA;
413 case GL_RGBA8_OES: return GL_RGBA;
414 case GL_RGB565_OES: return GL_RGBA;
415 case GL_RGB8_OES: return GL_RGB;
416 default:
417 UNREACHABLE(colorbuffer->getFormat());
418 }
419 }
420
421 return GL_RGBA;
422 }
423
getImplementationColorReadType()424 GLenum Framebuffer::getImplementationColorReadType()
425 {
426 Renderbuffer *colorbuffer = mColorbufferPointer;
427
428 if(colorbuffer)
429 {
430 switch(colorbuffer->getFormat())
431 {
432 case GL_BGRA8_EXT: return GL_UNSIGNED_BYTE;
433 case GL_RGBA4_OES: return GL_UNSIGNED_SHORT_4_4_4_4;
434 case GL_RGB5_A1_OES: return GL_UNSIGNED_SHORT_5_5_5_1;
435 case GL_RGBA8_OES: return GL_UNSIGNED_BYTE;
436 case GL_RGB565_OES: return GL_UNSIGNED_SHORT_5_6_5;
437 case GL_RGB8_OES: return GL_UNSIGNED_BYTE;
438 default:
439 UNREACHABLE(colorbuffer->getFormat());
440 }
441 }
442
443 return GL_UNSIGNED_BYTE;
444 }
445
DefaultFramebuffer(Colorbuffer * colorbuffer,DepthStencilbuffer * depthStencil)446 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
447 {
448 mColorbufferPointer = new Renderbuffer(0, colorbuffer);
449
450 Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
451 mDepthbufferPointer = depthStencilRenderbuffer;
452 mStencilbufferPointer = depthStencilRenderbuffer;
453
454 mColorbufferType = GL_RENDERBUFFER_OES;
455 mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER_OES : GL_NONE_OES;
456 mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER_OES : GL_NONE_OES;
457 }
458
459 }
460