Home | History | Annotate | Download | only in opengl
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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);
    184 		createFramebuffer(config);
    185 	}
    186 	catch (...)
    187 	{
    188 		delete m_context;
    189 		throw;
    190 	}
    191 }
    192 
    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 
    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 
    205 void FboRenderContext::makeCurrent(void)
    206 {
    207 	m_context->makeCurrent();
    208 }
    209 
    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 
    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