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, DE_NULL); 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