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 
getPixelFormat(deUint32 colorFormat)38 static tcu::PixelFormat getPixelFormat (deUint32 colorFormat)
39 {
40 	const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(colorFormat));
41 	return tcu::PixelFormat(bits[0], bits[1], bits[2], bits[3]);
42 }
43 
getDepthStencilBits(deUint32 depthStencilFormat,int * depthBits,int * stencilBits)44 static void getDepthStencilBits (deUint32 depthStencilFormat, int* depthBits, int* stencilBits)
45 {
46 	const tcu::IVec4 bits = tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(depthStencilFormat));
47 	*depthBits		= bits[0];
48 	*stencilBits	= bits[3];
49 }
50 
chooseColorFormat(const glu::RenderConfig & config)51 deUint32 chooseColorFormat (const glu::RenderConfig& config)
52 {
53 	static const deUint32 s_formats[] =
54 	{
55 		GL_RGBA8,
56 		GL_RGB8,
57 		GL_RG8,
58 		GL_R8,
59 		GL_RGBA4,
60 		GL_RGB5_A1,
61 		GL_RGB565,
62 		GL_RGB5
63 	};
64 
65 	for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
66 	{
67 		const deUint32		format	= s_formats[fmtNdx];
68 		const tcu::IVec4	bits	= tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(format));
69 
70 		if (config.redBits != glu::RenderConfig::DONT_CARE &&
71 			config.redBits != bits[0])
72 			continue;
73 
74 		if (config.greenBits != glu::RenderConfig::DONT_CARE &&
75 			config.greenBits != bits[1])
76 			continue;
77 
78 		if (config.blueBits != glu::RenderConfig::DONT_CARE &&
79 			config.blueBits != bits[2])
80 			continue;
81 
82 		if (config.alphaBits != glu::RenderConfig::DONT_CARE &&
83 			config.alphaBits != bits[3])
84 			continue;
85 
86 		return format;
87 	}
88 
89 	return 0;
90 }
91 
chooseDepthStencilFormat(const glu::RenderConfig & config)92 deUint32 chooseDepthStencilFormat (const glu::RenderConfig& config)
93 {
94 	static const deUint32 s_formats[] =
95 	{
96 		GL_DEPTH32F_STENCIL8,
97 		GL_DEPTH24_STENCIL8,
98 		GL_DEPTH_COMPONENT32F,
99 		GL_DEPTH_COMPONENT24,
100 		GL_DEPTH_COMPONENT16,
101 		GL_STENCIL_INDEX8
102 	};
103 
104 	for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(s_formats); fmtNdx++)
105 	{
106 		const deUint32		format	= s_formats[fmtNdx];
107 		const tcu::IVec4	bits	= tcu::getTextureFormatBitDepth(glu::mapGLInternalFormat(format));
108 
109 		if (config.depthBits != glu::RenderConfig::DONT_CARE &&
110 			config.depthBits != bits[0])
111 			continue;
112 
113 		if (config.stencilBits != glu::RenderConfig::DONT_CARE &&
114 			config.stencilBits != bits[3])
115 			continue;
116 
117 		return format;
118 	}
119 
120 	return 0;
121 }
122 
FboRenderContext(RenderContext * context,const RenderConfig & config)123 FboRenderContext::FboRenderContext (RenderContext* context, const RenderConfig& config)
124 	: m_context				(context)
125 	, m_framebuffer			(0)
126 	, m_colorBuffer			(0)
127 	, m_depthStencilBuffer	(0)
128 	, m_renderTarget		()
129 {
130 	try
131 	{
132 		createFramebuffer(config);
133 	}
134 	catch (...)
135 	{
136 		destroyFramebuffer();
137 		throw;
138 	}
139 }
140 
FboRenderContext(const ContextFactory & factory,const RenderConfig & config,const tcu::CommandLine & cmdLine)141 FboRenderContext::FboRenderContext (const ContextFactory& factory, const RenderConfig& config, const tcu::CommandLine& cmdLine)
142 	: m_context				(DE_NULL)
143 	, m_framebuffer			(0)
144 	, m_colorBuffer			(0)
145 	, m_depthStencilBuffer	(0)
146 	, m_renderTarget		()
147 {
148 	try
149 	{
150 		RenderConfig nativeRenderConfig;
151 		nativeRenderConfig.type				= config.type;
152 		nativeRenderConfig.windowVisibility	= config.windowVisibility;
153 		// \note All other properties are defaults, mostly DONT_CARE
154 		m_context = factory.createContext(nativeRenderConfig, cmdLine);
155 		createFramebuffer(config);
156 	}
157 	catch (...)
158 	{
159 		delete m_context;
160 		throw;
161 	}
162 }
163 
~FboRenderContext(void)164 FboRenderContext::~FboRenderContext (void)
165 {
166 	// \todo [2013-04-08 pyry] Do we want to destry FBO before destroying context?
167 	delete m_context;
168 }
169 
postIterate(void)170 void FboRenderContext::postIterate (void)
171 {
172 	// \todo [2012-11-27 pyry] Blit to default framebuffer in ES3?
173 	m_context->getFunctions().finish();
174 }
175 
createFramebuffer(const RenderConfig & config)176 void FboRenderContext::createFramebuffer (const RenderConfig& config)
177 {
178 	DE_ASSERT(m_framebuffer == 0 && m_colorBuffer == 0 && m_depthStencilBuffer == 0);
179 
180 	const glw::Functions&	gl					= m_context->getFunctions();
181 	const deUint32			colorFormat			= chooseColorFormat(config);
182 	const deUint32			depthStencilFormat	= chooseDepthStencilFormat(config);
183 	int						width				= config.width;
184 	int						height				= config.height;
185 	tcu::PixelFormat		pixelFormat;
186 	int						depthBits			= 0;
187 	int						stencilBits			= 0;
188 
189 	if (config.numSamples > 0 && !gl.renderbufferStorageMultisample)
190 		throw tcu::NotSupportedError("Multisample FBO is not supported");
191 
192 	if (colorFormat == 0)
193 		throw tcu::NotSupportedError("Unsupported color attachment format");
194 
195 	if (width == glu::RenderConfig::DONT_CARE || height == glu::RenderConfig::DONT_CARE)
196 	{
197 		int maxSize = 0;
198 		gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize);
199 
200 		width	= (width	== glu::RenderConfig::DONT_CARE) ? maxSize : width;
201 		height	= (height	== glu::RenderConfig::DONT_CARE) ? maxSize : height;
202 	}
203 
204 	{
205 		pixelFormat = getPixelFormat(colorFormat);
206 
207 		gl.genRenderbuffers(1, &m_colorBuffer);
208 		gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer);
209 
210 		if (config.numSamples > 0)
211 			gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, colorFormat, width, height);
212 		else
213 			gl.renderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height);
214 
215 		gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
216 		GLU_EXPECT_NO_ERROR(gl.getError(), "Creating color renderbuffer");
217 	}
218 
219 	if (depthStencilFormat != GL_NONE)
220 	{
221 		getDepthStencilBits(depthStencilFormat, &depthBits, &stencilBits);
222 
223 		gl.genRenderbuffers(1, &m_depthStencilBuffer);
224 		gl.bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
225 
226 		if (config.numSamples > 0)
227 			gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, depthStencilFormat, width, height);
228 		else
229 			gl.renderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height);
230 
231 		gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
232 		GLU_EXPECT_NO_ERROR(gl.getError(), "Creating depth / stencil renderbuffer");
233 	}
234 
235 	gl.genFramebuffers(1, &m_framebuffer);
236 	gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
237 
238 	if (m_colorBuffer)
239 		gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorBuffer);
240 
241 	if (m_depthStencilBuffer)
242 	{
243 		if (depthBits > 0)
244 			gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
245 
246 		if (stencilBits > 0)
247 			gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
248 	}
249 
250 	GLU_EXPECT_NO_ERROR(gl.getError(), "Creating framebuffer");
251 
252 	if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
253 		throw tcu::NotSupportedError("Framebuffer is not complete");
254 
255 	// Set up correct viewport for first test case.
256 	gl.viewport(0, 0, width, height);
257 
258 	m_renderTarget = tcu::RenderTarget(width, height, pixelFormat, depthBits, stencilBits, config.numSamples);
259 }
260 
destroyFramebuffer(void)261 void FboRenderContext::destroyFramebuffer (void)
262 {
263 	const glw::Functions& gl = m_context->getFunctions();
264 
265 	if (m_framebuffer)
266 	{
267 		gl.deleteFramebuffers(1, &m_framebuffer);
268 		m_framebuffer = 0;
269 	}
270 
271 	if (m_depthStencilBuffer)
272 	{
273 		gl.deleteRenderbuffers(1, &m_depthStencilBuffer);
274 		m_depthStencilBuffer = 0;
275 	}
276 
277 	if (m_colorBuffer)
278 	{
279 		gl.deleteRenderbuffers(1, &m_colorBuffer);
280 		m_colorBuffer = 0;
281 	}
282 }
283 
284 } // glu
285