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::createFramebuffer (const RenderConfig& config) 206 { 207 DE_ASSERT(m_framebuffer == 0 && m_colorBuffer == 0 && m_depthStencilBuffer == 0); 208 209 const glw::Functions& gl = m_context->getFunctions(); 210 const deUint32 colorFormat = chooseColorFormat(config); 211 const deUint32 depthStencilFormat = chooseDepthStencilFormat(config); 212 int width = config.width; 213 int height = config.height; 214 tcu::PixelFormat pixelFormat; 215 int depthBits = 0; 216 int stencilBits = 0; 217 218 if (config.numSamples > 0 && !gl.renderbufferStorageMultisample) 219 throw tcu::NotSupportedError("Multisample FBO is not supported"); 220 221 if (colorFormat == 0) 222 throw tcu::NotSupportedError("Unsupported color attachment format"); 223 224 if (width == glu::RenderConfig::DONT_CARE || height == glu::RenderConfig::DONT_CARE) 225 { 226 int maxSize = 0; 227 gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxSize); 228 229 width = (width == glu::RenderConfig::DONT_CARE) ? maxSize : width; 230 height = (height == glu::RenderConfig::DONT_CARE) ? maxSize : height; 231 } 232 233 { 234 pixelFormat = getPixelFormat(colorFormat); 235 236 gl.genRenderbuffers(1, &m_colorBuffer); 237 gl.bindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer); 238 239 if (config.numSamples > 0) 240 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, colorFormat, width, height); 241 else 242 gl.renderbufferStorage(GL_RENDERBUFFER, colorFormat, width, height); 243 244 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 245 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating color renderbuffer"); 246 } 247 248 if (depthStencilFormat != GL_NONE) 249 { 250 getDepthStencilBits(depthStencilFormat, &depthBits, &stencilBits); 251 252 gl.genRenderbuffers(1, &m_depthStencilBuffer); 253 gl.bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer); 254 255 if (config.numSamples > 0) 256 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, config.numSamples, depthStencilFormat, width, height); 257 else 258 gl.renderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height); 259 260 gl.bindRenderbuffer(GL_RENDERBUFFER, 0); 261 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating depth / stencil renderbuffer"); 262 } 263 264 gl.genFramebuffers(1, &m_framebuffer); 265 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); 266 267 if (m_colorBuffer) 268 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorBuffer); 269 270 if (m_depthStencilBuffer) 271 { 272 if (depthBits > 0) 273 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer); 274 275 if (stencilBits > 0) 276 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer); 277 } 278 279 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating framebuffer"); 280 281 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 282 throw tcu::NotSupportedError("Framebuffer is not complete"); 283 284 // Set up correct viewport for first test case. 285 gl.viewport(0, 0, width, height); 286 287 m_renderTarget = tcu::RenderTarget(width, height, pixelFormat, depthBits, stencilBits, config.numSamples); 288 } 289 290 void FboRenderContext::destroyFramebuffer (void) 291 { 292 const glw::Functions& gl = m_context->getFunctions(); 293 294 if (m_framebuffer) 295 { 296 gl.deleteFramebuffers(1, &m_framebuffer); 297 m_framebuffer = 0; 298 } 299 300 if (m_depthStencilBuffer) 301 { 302 gl.deleteRenderbuffers(1, &m_depthStencilBuffer); 303 m_depthStencilBuffer = 0; 304 } 305 306 if (m_colorBuffer) 307 { 308 gl.deleteRenderbuffers(1, &m_colorBuffer); 309 m_colorBuffer = 0; 310 } 311 } 312 313 } // glu 314