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 17namespace gl 18{ 19 20Framebuffer::Framebuffer() 21{ 22 mColorbufferType = GL_NONE; 23 mDepthbufferType = GL_NONE; 24 mStencilbufferType = GL_NONE; 25} 26 27Framebuffer::~Framebuffer() 28{ 29 mColorbufferPointer.set(NULL); 30 mDepthbufferPointer.set(NULL); 31 mStencilbufferPointer.set(NULL); 32} 33 34Renderbuffer *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 59void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) 60{ 61 mColorbufferType = type; 62 mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer)); 63} 64 65void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) 66{ 67 mDepthbufferType = type; 68 mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer)); 69} 70 71void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) 72{ 73 mStencilbufferType = type; 74 mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer)); 75} 76 77void 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 98void 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 119unsigned 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 131IDirect3DSurface9 *Framebuffer::getRenderTarget() 132{ 133 Renderbuffer *colorbuffer = mColorbufferPointer.get(); 134 135 if (colorbuffer) 136 { 137 return colorbuffer->getRenderTarget(); 138 } 139 140 return NULL; 141} 142 143IDirect3DSurface9 *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 160unsigned 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 172unsigned 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 184Colorbuffer *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 198DepthStencilbuffer *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 212DepthStencilbuffer *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 226GLenum Framebuffer::getColorbufferType() 227{ 228 return mColorbufferType; 229} 230 231GLenum Framebuffer::getDepthbufferType() 232{ 233 return mDepthbufferType; 234} 235 236GLenum Framebuffer::getStencilbufferType() 237{ 238 return mStencilbufferType; 239} 240 241GLuint Framebuffer::getColorbufferHandle() 242{ 243 return mColorbufferPointer.id(); 244} 245 246GLuint Framebuffer::getDepthbufferHandle() 247{ 248 return mDepthbufferPointer.id(); 249} 250 251GLuint Framebuffer::getStencilbufferHandle() 252{ 253 return mStencilbufferPointer.id(); 254} 255 256bool 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 271bool 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 288GLenum 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 438DefaultFramebuffer::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 451int Framebuffer::getSamples() 452{ 453 if (completeness() == GL_FRAMEBUFFER_COMPLETE) 454 { 455 return getColorbuffer()->getSamples(); 456 } 457 else 458 { 459 return 0; 460 } 461} 462 463GLenum 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