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