1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES Utilities
3  * ------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief OpenGL ES context wrapper that uses FBO as default framebuffer.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "gluFboRenderContext.hpp"
25 #include "gluContextFactory.hpp"
26 #include "gluRenderConfig.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuCommandLine.hpp"
30 #include "gluTextureUtil.hpp"
31 #include "tcuTextureUtil.hpp"
32 
33 #include <sstream>
34 
35 namespace glu
36 {
37 
getNumDepthBits(const tcu::TextureFormat & format)38 static int getNumDepthBits (const tcu::TextureFormat& format)
39 {
40 	if (format.order == tcu::TextureFormat::DS)
41 	{
42 		const tcu::TextureFormat	depthOnlyFormat		= tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_DEPTH);
43 		return tcu::getTextureFormatBitDepth(depthOnlyFormat).x();
44 	}
45 	else if (format.order == tcu::TextureFormat::D)
46 		return tcu::getTextureFormatBitDepth(format).x();
47 	else
48 		return 0;
49 }
50 
getNumStencilBits(const tcu::TextureFormat & format)51 static int getNumStencilBits (const tcu::TextureFormat& format)
52 {
53 	if (format.order == tcu::TextureFormat::DS)
54 	{
55 		const tcu::TextureFormat	stencilOnlyFormat		= tcu::getEffectiveDepthStencilTextureFormat(format, tcu::Sampler::MODE_STENCIL);
56 		return tcu::getTextureFormatBitDepth(stencilOnlyFormat).x();
57 	}
58 	else if (format.order == tcu::TextureFormat::S)
59 		return tcu::getTextureFormatBitDepth(format).x();
60 	else
61 		return 0;
62 }
63 
getPixelFormat(deUint32 colorFormat)64 static tcu::PixelFormat getPixelFormat (deUint32 colorFormat)
65 {
66 	const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(colorFormat));
67 	return tcu::PixelFormat(bits[0], bits[1], bits[2], bits[3]);
68 }
69 
getDepthStencilBits(deUint32 depthStencilFormat,int * depthBits,int * stencilBits)70 static void getDepthStencilBits (deUint32 depthStencilFormat, int* depthBits, int* stencilBits)
71 {
72 	const tcu::TextureFormat	combinedFormat	= glu::mapGLInternalFormat(depthStencilFormat);
73 
74 	*depthBits		= getNumDepthBits(combinedFormat);
75 	*stencilBits	= getNumStencilBits(combinedFormat);
76 }
77 
chooseColorFormat(const glu::RenderConfig & config)78 deUint32 chooseColorFormat (const glu::RenderConfig& config)
79 {
80 	static const deUint32 s_formats[] =
81 	{
82 		GL_RGBA8,
83 		GL_RGB8,
84 		GL_RG8,
85 		GL_R8,
86 		GL_RGBA4,
87 		GL_RGB5_A1,
88 		GL_RGB565,
89 		GL_RGB5
90 	};
91 
92 	for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
93 	{
94 		const deUint32		format	= s_formats[fmtNdx];
95 		const tcu::IVec4	bits	= tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(format));
96 
97 		if (config.redBits != glu::RenderConfig::DONT_CARE &&
98 			config.redBits != bits[0])
99 			continue;
100 
101 		if (config.greenBits != glu::RenderConfig::DONT_CARE &&
102 			config.greenBits != bits[1])
103 			continue;
104 
105 		if (config.blueBits != glu::RenderConfig::DONT_CARE &&
106 			config.blueBits != bits[2])
107 			continue;
108 
109 		if (config.alphaBits != glu::RenderConfig::DONT_CARE &&
110 			config.alphaBits != bits[3])
111 			continue;
112 
113 		return format;
114 	}
115 
116 	return 0;
117 }
118 
chooseDepthStencilFormat(const glu::RenderConfig & config)119 deUint32 chooseDepthStencilFormat (const glu::RenderConfig& config)
120 {
121 	static const deUint32 s_formats[] =
122 	{
123 		GL_DEPTH32F_STENCIL8,
124 		GL_DEPTH24_STENCIL8,
125 		GL_DEPTH_COMPONENT32F,
126 		GL_DEPTH_COMPONENT24,
127 		GL_DEPTH_COMPONENT16,
128 		GL_STENCIL_INDEX8
129 	};
130 
131 	for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
132 	{
133 		const deUint32				format			= s_formats[fmtNdx];
134 		const tcu::TextureFormat	combinedFormat	= glu::mapGLInternalFormat(format);
135 		const int					depthBits		= getNumDepthBits(combinedFormat);
136 		const int					stencilBits		= getNumStencilBits(combinedFormat);
137 
138 		if (config.depthBits != glu::RenderConfig::DONT_CARE &&
139 			config.depthBits != depthBits)
140 			continue;
141 
142 		if (config.stencilBits != glu::RenderConfig::DONT_CARE &&
143 			config.stencilBits != stencilBits)
144 			continue;
145 
146 		return format;
147 	}
148 
149 	return 0;
150 }
151 
FboRenderContext(RenderContext * context,const RenderConfig & config)152 FboRenderContext::FboRenderContext (RenderContext* context, const RenderConfig& config)
153 	: m_context				(context)
154 	, m_framebuffer			(0)
155 	, m_colorBuffer			(0)
156 	, m_depthStencilBuffer	(0)
157 	, m_renderTarget		()
158 {
159 	try
160 	{
161 		createFramebuffer(config);
162 	}
163 	catch (...)
164 	{
165 		destroyFramebuffer();
166 		throw;
167 	}
168 }
169 
FboRenderContext(const ContextFactory & factory,const RenderConfig & config,const tcu::CommandLine & cmdLine)170 FboRenderContext::FboRenderContext (const ContextFactory& factory, const RenderConfig& config, const tcu::CommandLine& cmdLine)
171 	: m_context				(DE_NULL)
172 	, m_framebuffer			(0)
173 	, m_colorBuffer			(0)
174 	, m_depthStencilBuffer	(0)
175 	, m_renderTarget		()
176 {
177 	try
178 	{
179 		RenderConfig nativeRenderConfig;
180 		nativeRenderConfig.type				= config.type;
181 		nativeRenderConfig.windowVisibility	= config.windowVisibility;
182 		// \note All other properties are defaults, mostly DONT_CARE
183 		m_context = factory.createContext(nativeRenderConfig, cmdLine, DE_NULL);
184 		createFramebuffer(config);
185 	}
186 	catch (...)
187 	{
188 		delete m_context;
189 		throw;
190 	}
191 }
192 
~FboRenderContext(void)193 FboRenderContext::~FboRenderContext (void)
194 {
195 	// \todo [2013-04-08 pyry] Do we want to destry FBO before destroying context?
196 	delete m_context;
197 }
198 
postIterate(void)199 void FboRenderContext::postIterate (void)
200 {
201 	// \todo [2012-11-27 pyry] Blit to default framebuffer in ES3?
202 	m_context->getFunctions().finish();
203 }
204 
makeCurrent(void)205 void FboRenderContext::makeCurrent(void)
206 {
207 	m_context->makeCurrent();
208 }
209 
createFramebuffer(const RenderConfig & config)210 void FboRenderContext::createFramebuffer (const RenderConfig& config)
211 {
212 	DE_ASSERT(m_framebuffer == 0 && m_colorBuffer == 0 && m_depthStencilBuffer == 0);
213 
214 	const glw::Functions&	gl					= m_context->getFunctions();
215 	const deUint32			colorFormat			= chooseColorFormat(config);
216 	const deUint32			depthStencilFormat	= chooseDepthStencilFormat(config);
217 	int						width				= config.width;
218 	int						height				= config.height;
219 	tcu::PixelFormat		pixelFormat;
220 	int						depthBits			= 0;
221 	int						stencilBits			= 0;
222 
223 	if (config.numSamples > 0 && !gl.renderbufferStorageMultisample)
224 		throw tcu::NotSupportedError("Multisample FBO is not supported");
225 
226 	if (colorFormat == 0)
227 		throw tcu::NotSupportedError("Unsupported color attachment format");
228 
229 	if (width == glu::RenderConfig::DONT_CARE || height == glu::RenderConfig::DONT_CARE)
230 	{
231 		int maxSize = 0;
232 		gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize);
233 
234 		width	= (width	== glu::RenderConfig::DONT_CARE) ? maxSize : width;
235 		height	= (height	== glu::RenderConfig::DONT_CARE) ? maxSize : height;
236 	}
237 
238 	{
239 		pixelFormat = getPixelFormat(colorFormat);
240 
241 		gl.genRenderbuffers(1, &m_colorBuffer);
242 		gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer);
243 
244 		if (config.numSamples > 0)
245 			gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, colorFormat, width, height);
246 		else
247 			gl.renderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height);
248 
249 		gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
250 		GLU_EXPECT_NO_ERROR(gl.getError(), "Creating color renderbuffer");
251 	}
252 
253 	if (depthStencilFormat != GL_NONE)
254 	{
255 		getDepthStencilBits(depthStencilFormat, &depthBits, &stencilBits);
256 
257 		gl.genRenderbuffers(1, &m_depthStencilBuffer);
258 		gl.bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
259 
260 		if (config.numSamples > 0)
261 			gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, depthStencilFormat, width, height);
262 		else
263 			gl.renderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height);
264 
265 		gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
266 		GLU_EXPECT_NO_ERROR(gl.getError(), "Creating depth / stencil renderbuffer");
267 	}
268 
269 	gl.genFramebuffers(1, &m_framebuffer);
270 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
271 
272 	if (m_colorBuffer)
273 		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorBuffer);
274 
275 	if (m_depthStencilBuffer)
276 	{
277 		if (depthBits > 0)
278 			gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
279 
280 		if (stencilBits > 0)
281 			gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
282 	}
283 
284 	GLU_EXPECT_NO_ERROR(gl.getError(), "Creating framebuffer");
285 
286 	if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
287 		throw tcu::NotSupportedError("Framebuffer is not complete");
288 
289 	// Set up correct viewport for first test case.
290 	gl.viewport(0, 0, width, height);
291 
292 	m_renderTarget = tcu::RenderTarget(width, height, pixelFormat, depthBits, stencilBits, config.numSamples);
293 }
294 
destroyFramebuffer(void)295 void FboRenderContext::destroyFramebuffer (void)
296 {
297 	const glw::Functions& gl = m_context->getFunctions();
298 
299 	if (m_framebuffer)
300 	{
301 		gl.deleteFramebuffers(1, &m_framebuffer);
302 		m_framebuffer = 0;
303 	}
304 
305 	if (m_depthStencilBuffer)
306 	{
307 		gl.deleteRenderbuffers(1, &m_depthStencilBuffer);
308 		m_depthStencilBuffer = 0;
309 	}
310 
311 	if (m_colorBuffer)
312 	{
313 		gl.deleteRenderbuffers(1, &m_colorBuffer);
314 		m_colorBuffer = 0;
315 	}
316 }
317 
318 } // glu
319