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