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.
17
18#include "Framebuffer.h"
19
20#include "main.h"
21#include "Renderbuffer.h"
22#include "Texture.h"
23#include "utilities.h"
24
25namespace gl
26{
27
28Framebuffer::Framebuffer()
29{
30	mColorbufferType = GL_NONE;
31	mDepthbufferType = GL_NONE;
32	mStencilbufferType = GL_NONE;
33}
34
35Framebuffer::~Framebuffer()
36{
37	mColorbufferPointer = nullptr;
38	mDepthbufferPointer = nullptr;
39	mStencilbufferPointer = nullptr;
40}
41
42Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
43{
44	Context *context = getContext();
45	Renderbuffer *buffer = nullptr;
46
47	if(type == GL_NONE)
48	{
49		buffer = nullptr;
50	}
51	else if(type == GL_RENDERBUFFER)
52	{
53		buffer = context->getRenderbuffer(handle);
54	}
55	else if(IsTextureTarget(type))
56	{
57		buffer = context->getTexture(handle)->getRenderbuffer(type);
58	}
59	else UNREACHABLE(type);
60
61	return buffer;
62}
63
64void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
65{
66	mColorbufferType = (colorbuffer != 0) ? type : GL_NONE;
67	mColorbufferPointer = lookupRenderbuffer(type, colorbuffer);
68}
69
70void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
71{
72	mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE;
73	mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer);
74}
75
76void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
77{
78	mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE;
79	mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer);
80}
81
82void Framebuffer::detachTexture(GLuint texture)
83{
84	if(mColorbufferPointer.name() == texture && IsTextureTarget(mColorbufferType))
85	{
86		mColorbufferType = GL_NONE;
87		mColorbufferPointer = nullptr;
88	}
89
90	if(mDepthbufferPointer.name() == texture && IsTextureTarget(mDepthbufferType))
91	{
92		mDepthbufferType = GL_NONE;
93		mDepthbufferPointer = nullptr;
94	}
95
96	if(mStencilbufferPointer.name() == texture && IsTextureTarget(mStencilbufferType))
97	{
98		mStencilbufferType = GL_NONE;
99		mStencilbufferPointer = nullptr;
100	}
101}
102
103void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
104{
105	if(mColorbufferPointer.name() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
106	{
107		mColorbufferType = GL_NONE;
108		mColorbufferPointer = nullptr;
109	}
110
111	if(mDepthbufferPointer.name() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
112	{
113		mDepthbufferType = GL_NONE;
114		mDepthbufferPointer = nullptr;
115	}
116
117	if(mStencilbufferPointer.name() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
118	{
119		mStencilbufferType = GL_NONE;
120		mStencilbufferPointer = nullptr;
121	}
122}
123
124// Increments refcount on surface.
125// caller must Release() the returned surface
126Image *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
140Image *Framebuffer::getDepthStencil()
141{
142	Renderbuffer *depthstencilbuffer = mDepthbufferPointer;
143
144	if(!depthstencilbuffer)
145	{
146		depthstencilbuffer = mStencilbufferPointer;
147	}
148
149	if(depthstencilbuffer)
150	{
151		return depthstencilbuffer->getRenderTarget();
152	}
153
154	return nullptr;
155}
156
157Renderbuffer *Framebuffer::getColorbuffer()
158{
159	return mColorbufferPointer;
160}
161
162Renderbuffer *Framebuffer::getDepthbuffer()
163{
164	return mDepthbufferPointer;
165}
166
167Renderbuffer *Framebuffer::getStencilbuffer()
168{
169	return mStencilbufferPointer;
170}
171
172GLenum Framebuffer::getColorbufferType()
173{
174	return mColorbufferType;
175}
176
177GLenum Framebuffer::getDepthbufferType()
178{
179	return mDepthbufferType;
180}
181
182GLenum Framebuffer::getStencilbufferType()
183{
184	return mStencilbufferType;
185}
186
187GLuint Framebuffer::getColorbufferName()
188{
189	return mColorbufferPointer.name();
190}
191
192GLuint Framebuffer::getDepthbufferName()
193{
194	return mDepthbufferPointer.name();
195}
196
197GLuint Framebuffer::getStencilbufferName()
198{
199	return mStencilbufferPointer.name();
200}
201
202bool 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
217GLenum Framebuffer::completeness()
218{
219	int width;
220	int height;
221	int samples;
222
223	return completeness(width, height, samples);
224}
225
226GLenum 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(!gl::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(gl::IsDepthTexture(format) || gl::IsStencilTexture(format))
266			{
267				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
268			}
269		}
270		else
271		{
272			UNREACHABLE(mColorbufferType);
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 = nullptr;
282	Renderbuffer *stencilbuffer = nullptr;
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(!gl::IsDepthRenderable(depthbuffer->getFormat()))
301			{
302				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
303			}
304		}
305		else if(IsTextureTarget(mDepthbufferType))
306		{
307			if(!gl::IsDepthTexture(depthbuffer->getFormat()))
308			{
309				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
310			}
311		}
312		else
313		{
314			UNREACHABLE(mDepthbufferType);
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_EXT;
327		}
328		else if(samples != depthbuffer->getSamples())
329		{
330			return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
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(!gl::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(!gl::IsStencilTexture(internalformat))
360			{
361				return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
362			}
363		}
364		else
365		{
366			UNREACHABLE(mStencilbufferType);
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_EXT;
379		}
380		else if(samples != stencilbuffer->getSamples())
381		{
382			return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT;
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
402DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil)
403{
404	mColorbufferPointer = new Renderbuffer(0, colorbuffer);
405
406	Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
407	mDepthbufferPointer = depthStencilRenderbuffer;
408	mStencilbufferPointer = 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
415GLenum 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}
424