1 // 2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer 8 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. 9 10 #include "libGLESv2/Framebuffer.h" 11 12 #include "libGLESv2/main.h" 13 #include "libGLESv2/Renderbuffer.h" 14 #include "libGLESv2/Texture.h" 15 #include "libGLESv2/utilities.h" 16 17 namespace gl 18 { 19 20 Framebuffer::Framebuffer() 21 { 22 mColorbufferType = GL_NONE; 23 mDepthbufferType = GL_NONE; 24 mStencilbufferType = GL_NONE; 25 } 26 27 Framebuffer::~Framebuffer() 28 { 29 mColorbufferPointer.set(NULL); 30 mDepthbufferPointer.set(NULL); 31 mStencilbufferPointer.set(NULL); 32 } 33 34 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const 35 { 36 gl::Context *context = gl::getContext(); 37 Renderbuffer *buffer = NULL; 38 39 if (type == GL_NONE) 40 { 41 buffer = NULL; 42 } 43 else if (type == GL_RENDERBUFFER) 44 { 45 buffer = context->getRenderbuffer(handle); 46 } 47 else if (IsTextureTarget(type)) 48 { 49 buffer = context->getTexture(handle)->getColorbuffer(type); 50 } 51 else 52 { 53 UNREACHABLE(); 54 } 55 56 return buffer; 57 } 58 59 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) 60 { 61 mColorbufferType = type; 62 mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer)); 63 } 64 65 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) 66 { 67 mDepthbufferType = type; 68 mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer)); 69 } 70 71 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) 72 { 73 mStencilbufferType = type; 74 mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer)); 75 } 76 77 void Framebuffer::detachTexture(GLuint texture) 78 { 79 if (mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType)) 80 { 81 mColorbufferType = GL_NONE; 82 mColorbufferPointer.set(NULL); 83 } 84 85 if (mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType)) 86 { 87 mDepthbufferType = GL_NONE; 88 mDepthbufferPointer.set(NULL); 89 } 90 91 if (mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType)) 92 { 93 mStencilbufferType = GL_NONE; 94 mStencilbufferPointer.set(NULL); 95 } 96 } 97 98 void Framebuffer::detachRenderbuffer(GLuint renderbuffer) 99 { 100 if (mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER) 101 { 102 mColorbufferType = GL_NONE; 103 mColorbufferPointer.set(NULL); 104 } 105 106 if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER) 107 { 108 mDepthbufferType = GL_NONE; 109 mDepthbufferPointer.set(NULL); 110 } 111 112 if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER) 113 { 114 mStencilbufferType = GL_NONE; 115 mStencilbufferPointer.set(NULL); 116 } 117 } 118 119 unsigned int Framebuffer::getRenderTargetSerial() 120 { 121 Renderbuffer *colorbuffer = mColorbufferPointer.get(); 122 123 if (colorbuffer) 124 { 125 return colorbuffer->getSerial(); 126 } 127 128 return 0; 129 } 130 131 IDirect3DSurface9 *Framebuffer::getRenderTarget() 132 { 133 Renderbuffer *colorbuffer = mColorbufferPointer.get(); 134 135 if (colorbuffer) 136 { 137 return colorbuffer->getRenderTarget(); 138 } 139 140 return NULL; 141 } 142 143 IDirect3DSurface9 *Framebuffer::getDepthStencil() 144 { 145 Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get(); 146 147 if (!depthstencilbuffer) 148 { 149 depthstencilbuffer = mStencilbufferPointer.get(); 150 } 151 152 if (depthstencilbuffer) 153 { 154 return depthstencilbuffer->getDepthStencil(); 155 } 156 157 return NULL; 158 } 159 160 unsigned int Framebuffer::getDepthbufferSerial() 161 { 162 Renderbuffer *depthbuffer = mDepthbufferPointer.get(); 163 164 if (depthbuffer) 165 { 166 return depthbuffer->getSerial(); 167 } 168 169 return 0; 170 } 171 172 unsigned int Framebuffer::getStencilbufferSerial() 173 { 174 Renderbuffer *stencilbuffer = mStencilbufferPointer.get(); 175 176 if (stencilbuffer) 177 { 178 return stencilbuffer->getSerial(); 179 } 180 181 return 0; 182 } 183 184 Colorbuffer *Framebuffer::getColorbuffer() 185 { 186 Renderbuffer *rb = mColorbufferPointer.get(); 187 188 if (rb != NULL && rb->isColorbuffer()) 189 { 190 return static_cast<Colorbuffer*>(rb->getStorage()); 191 } 192 else 193 { 194 return NULL; 195 } 196 } 197 198 DepthStencilbuffer *Framebuffer::getDepthbuffer() 199 { 200 Renderbuffer *rb = mDepthbufferPointer.get(); 201 202 if (rb != NULL && rb->isDepthbuffer()) 203 { 204 return static_cast<DepthStencilbuffer*>(rb->getStorage()); 205 } 206 else 207 { 208 return NULL; 209 } 210 } 211 212 DepthStencilbuffer *Framebuffer::getStencilbuffer() 213 { 214 Renderbuffer *rb = mStencilbufferPointer.get(); 215 216 if (rb != NULL && rb->isStencilbuffer()) 217 { 218 return static_cast<DepthStencilbuffer*>(rb->getStorage()); 219 } 220 else 221 { 222 return NULL; 223 } 224 } 225 226 GLenum Framebuffer::getColorbufferType() 227 { 228 return mColorbufferType; 229 } 230 231 GLenum Framebuffer::getDepthbufferType() 232 { 233 return mDepthbufferType; 234 } 235 236 GLenum Framebuffer::getStencilbufferType() 237 { 238 return mStencilbufferType; 239 } 240 241 GLuint Framebuffer::getColorbufferHandle() 242 { 243 return mColorbufferPointer.id(); 244 } 245 246 GLuint Framebuffer::getDepthbufferHandle() 247 { 248 return mDepthbufferPointer.id(); 249 } 250 251 GLuint Framebuffer::getStencilbufferHandle() 252 { 253 return mStencilbufferPointer.id(); 254 } 255 256 bool Framebuffer::hasStencil() 257 { 258 if (mStencilbufferType != GL_NONE) 259 { 260 DepthStencilbuffer *stencilbufferObject = getStencilbuffer(); 261 262 if (stencilbufferObject) 263 { 264 return stencilbufferObject->getStencilSize() > 0; 265 } 266 } 267 268 return false; 269 } 270 271 bool Framebuffer::isMultisample() 272 { 273 // If the framebuffer is not complete, attachment samples may be mismatched, and it 274 // cannot be used as a multisample framebuffer. If it is complete, it is required to 275 // have a color attachment, and all its attachments must have the same number of samples, 276 // so the number of samples for the colorbuffer will indicate whether the framebuffer is 277 // multisampled. 278 if (completeness() == GL_FRAMEBUFFER_COMPLETE && getColorbuffer()->getSamples() > 0) 279 { 280 return true; 281 } 282 else 283 { 284 return false; 285 } 286 } 287 288 GLenum Framebuffer::completeness() 289 { 290 int width = 0; 291 int height = 0; 292 int samples = -1; 293 294 if (mColorbufferType != GL_NONE) 295 { 296 Colorbuffer *colorbuffer = getColorbuffer(); 297 298 if (!colorbuffer) 299 { 300 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 301 } 302 303 if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) 304 { 305 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 306 } 307 308 if (mColorbufferType == GL_RENDERBUFFER) 309 { 310 if (!gl::IsColorRenderable(colorbuffer->getFormat())) 311 { 312 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 313 } 314 } 315 else if (IsTextureTarget(mColorbufferType)) 316 { 317 if (IsCompressed(colorbuffer->getFormat())) 318 { 319 return GL_FRAMEBUFFER_UNSUPPORTED; 320 } 321 322 if (colorbuffer->isFloatingPoint() && (!getContext()->supportsFloatRenderableTextures() || 323 !getContext()->supportsHalfFloatRenderableTextures())) 324 { 325 return GL_FRAMEBUFFER_UNSUPPORTED; 326 } 327 328 if (colorbuffer->getFormat() == GL_LUMINANCE || colorbuffer->getFormat() == GL_LUMINANCE_ALPHA) 329 { 330 return GL_FRAMEBUFFER_UNSUPPORTED; 331 } 332 } 333 else UNREACHABLE(); 334 335 width = colorbuffer->getWidth(); 336 height = colorbuffer->getHeight(); 337 samples = colorbuffer->getSamples(); 338 } 339 else 340 { 341 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; 342 } 343 344 DepthStencilbuffer *depthbuffer = NULL; 345 DepthStencilbuffer *stencilbuffer = NULL; 346 347 if (mDepthbufferType != GL_NONE) 348 { 349 if (mDepthbufferType != GL_RENDERBUFFER) 350 { 351 return GL_FRAMEBUFFER_UNSUPPORTED; // Requires GL_OES_depth_texture 352 } 353 354 depthbuffer = getDepthbuffer(); 355 356 if (!depthbuffer) 357 { 358 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 359 } 360 361 if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) 362 { 363 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 364 } 365 366 if (width == 0) 367 { 368 width = depthbuffer->getWidth(); 369 height = depthbuffer->getHeight(); 370 } 371 else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) 372 { 373 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; 374 } 375 376 if (samples == -1) 377 { 378 samples = depthbuffer->getSamples(); 379 } 380 else if (samples != depthbuffer->getSamples()) 381 { 382 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; 383 } 384 } 385 386 if (mStencilbufferType != GL_NONE) 387 { 388 if (mStencilbufferType != GL_RENDERBUFFER) 389 { 390 return GL_FRAMEBUFFER_UNSUPPORTED; 391 } 392 393 stencilbuffer = getStencilbuffer(); 394 395 if (!stencilbuffer) 396 { 397 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 398 } 399 400 if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) 401 { 402 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 403 } 404 405 if (width == 0) 406 { 407 width = stencilbuffer->getWidth(); 408 height = stencilbuffer->getHeight(); 409 } 410 else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) 411 { 412 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; 413 } 414 415 if (samples == -1) 416 { 417 samples = stencilbuffer->getSamples(); 418 } 419 else if (samples != stencilbuffer->getSamples()) 420 { 421 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE; 422 } 423 } 424 425 if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER) 426 { 427 if (depthbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES || 428 stencilbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES || 429 depthbuffer->getSerial() != stencilbuffer->getSerial()) 430 { 431 return GL_FRAMEBUFFER_UNSUPPORTED; 432 } 433 } 434 435 return GL_FRAMEBUFFER_COMPLETE; 436 } 437 438 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil) 439 { 440 mColorbufferType = GL_RENDERBUFFER; 441 mDepthbufferType = (depthStencil->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; 442 mStencilbufferType = (depthStencil->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; 443 444 mColorbufferPointer.set(new Renderbuffer(0, color)); 445 446 Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil); 447 mDepthbufferPointer.set(depthStencilRenderbuffer); 448 mStencilbufferPointer.set(depthStencilRenderbuffer); 449 } 450 451 int Framebuffer::getSamples() 452 { 453 if (completeness() == GL_FRAMEBUFFER_COMPLETE) 454 { 455 return getColorbuffer()->getSamples(); 456 } 457 else 458 { 459 return 0; 460 } 461 } 462 463 GLenum DefaultFramebuffer::completeness() 464 { 465 // The default framebuffer should always be complete 466 ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE); 467 468 return GL_FRAMEBUFFER_COMPLETE; 469 } 470 471 } 472