1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Framebuffer.cpp: Implements the Framebuffer class. Implements GL framebuffer 16 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. 17 18 #include "Framebuffer.h" 19 20 #include "main.h" 21 #include "Renderbuffer.h" 22 #include "Texture.h" 23 #include "utilities.h" 24 25 namespace es1 26 { 27 28 Framebuffer::Framebuffer() 29 { 30 mColorbufferType = GL_NONE_OES; 31 mDepthbufferType = GL_NONE_OES; 32 mStencilbufferType = GL_NONE_OES; 33 } 34 35 Framebuffer::~Framebuffer() 36 { 37 mColorbufferPointer = nullptr; 38 mDepthbufferPointer = nullptr; 39 mStencilbufferPointer = nullptr; 40 } 41 42 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle, GLint level) const 43 { 44 Context *context = getContext(); 45 Renderbuffer *buffer = nullptr; 46 47 if(type == GL_NONE_OES) 48 { 49 buffer = nullptr; 50 } 51 else if(type == GL_RENDERBUFFER_OES) 52 { 53 buffer = context->getRenderbuffer(handle); 54 } 55 else if(IsTextureTarget(type)) 56 { 57 buffer = context->getTexture(handle)->getRenderbuffer(type, level); 58 } 59 else UNREACHABLE(type); 60 61 return buffer; 62 } 63 64 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer, GLint level) 65 { 66 mColorbufferType = (colorbuffer != 0) ? type : GL_NONE_OES; 67 mColorbufferPointer = lookupRenderbuffer(type, colorbuffer, level); 68 } 69 70 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level) 71 { 72 mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE_OES; 73 mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer, level); 74 } 75 76 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level) 77 { 78 mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE_OES; 79 mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer, level); 80 } 81 82 void Framebuffer::detachTexture(GLuint texture) 83 { 84 if(mColorbufferPointer.name() == texture && IsTextureTarget(mColorbufferType)) 85 { 86 mColorbufferType = GL_NONE_OES; 87 mColorbufferPointer = nullptr; 88 } 89 90 if(mDepthbufferPointer.name() == texture && IsTextureTarget(mDepthbufferType)) 91 { 92 mDepthbufferType = GL_NONE_OES; 93 mDepthbufferPointer = nullptr; 94 } 95 96 if(mStencilbufferPointer.name() == texture && IsTextureTarget(mStencilbufferType)) 97 { 98 mStencilbufferType = GL_NONE_OES; 99 mStencilbufferPointer = nullptr; 100 } 101 } 102 103 void Framebuffer::detachRenderbuffer(GLuint renderbuffer) 104 { 105 if(mColorbufferPointer.name() == renderbuffer && mColorbufferType == GL_RENDERBUFFER_OES) 106 { 107 mColorbufferType = GL_NONE_OES; 108 mColorbufferPointer = nullptr; 109 } 110 111 if(mDepthbufferPointer.name() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER_OES) 112 { 113 mDepthbufferType = GL_NONE_OES; 114 mDepthbufferPointer = nullptr; 115 } 116 117 if(mStencilbufferPointer.name() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER_OES) 118 { 119 mStencilbufferType = GL_NONE_OES; 120 mStencilbufferPointer = nullptr; 121 } 122 } 123 124 // Increments refcount on surface. 125 // caller must Release() the returned surface 126 egl::Image *Framebuffer::getRenderTarget() 127 { 128 Renderbuffer *colorbuffer = mColorbufferPointer; 129 130 if(colorbuffer) 131 { 132 return colorbuffer->getRenderTarget(); 133 } 134 135 return nullptr; 136 } 137 138 // Increments refcount on surface. 139 // caller must Release() the returned surface 140 egl::Image *Framebuffer::getDepthBuffer() 141 { 142 Renderbuffer *depthbuffer = mDepthbufferPointer; 143 144 if(depthbuffer) 145 { 146 return depthbuffer->getRenderTarget(); 147 } 148 149 return nullptr; 150 } 151 152 // Increments refcount on surface. 153 // caller must Release() the returned surface 154 egl::Image *Framebuffer::getStencilBuffer() 155 { 156 Renderbuffer *stencilbuffer = mStencilbufferPointer; 157 158 if(stencilbuffer) 159 { 160 return stencilbuffer->getRenderTarget(); 161 } 162 163 return nullptr; 164 } 165 166 Renderbuffer *Framebuffer::getColorbuffer() 167 { 168 return mColorbufferPointer; 169 } 170 171 Renderbuffer *Framebuffer::getDepthbuffer() 172 { 173 return mDepthbufferPointer; 174 } 175 176 Renderbuffer *Framebuffer::getStencilbuffer() 177 { 178 return mStencilbufferPointer; 179 } 180 181 GLenum Framebuffer::getColorbufferType() 182 { 183 return mColorbufferType; 184 } 185 186 GLenum Framebuffer::getDepthbufferType() 187 { 188 return mDepthbufferType; 189 } 190 191 GLenum Framebuffer::getStencilbufferType() 192 { 193 return mStencilbufferType; 194 } 195 196 GLuint Framebuffer::getColorbufferName() 197 { 198 return mColorbufferPointer.name(); 199 } 200 201 GLuint Framebuffer::getDepthbufferName() 202 { 203 return mDepthbufferPointer.name(); 204 } 205 206 GLuint Framebuffer::getStencilbufferName() 207 { 208 return mStencilbufferPointer.name(); 209 } 210 211 bool Framebuffer::hasStencil() 212 { 213 if(mStencilbufferType != GL_NONE_OES) 214 { 215 Renderbuffer *stencilbufferObject = getStencilbuffer(); 216 217 if(stencilbufferObject) 218 { 219 return stencilbufferObject->getStencilSize() > 0; 220 } 221 } 222 223 return false; 224 } 225 226 GLenum Framebuffer::completeness() 227 { 228 int width; 229 int height; 230 int samples; 231 232 return completeness(width, height, samples); 233 } 234 235 GLenum Framebuffer::completeness(int &width, int &height, int &samples) 236 { 237 width = -1; 238 height = -1; 239 samples = -1; 240 241 if(mColorbufferType != GL_NONE_OES) 242 { 243 Renderbuffer *colorbuffer = getColorbuffer(); 244 245 if(!colorbuffer) 246 { 247 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 248 } 249 250 if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) 251 { 252 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 253 } 254 255 if(mColorbufferType == GL_RENDERBUFFER_OES) 256 { 257 if(!IsColorRenderable(colorbuffer->getFormat())) 258 { 259 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 260 } 261 } 262 else if(IsTextureTarget(mColorbufferType)) 263 { 264 GLenum format = colorbuffer->getFormat(); 265 266 if(!IsColorRenderable(format)) 267 { 268 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 269 } 270 271 if(IsDepthTexture(format) || IsStencilTexture(format)) 272 { 273 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 274 } 275 } 276 else 277 { 278 UNREACHABLE(mColorbufferType); 279 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 280 } 281 282 width = colorbuffer->getWidth(); 283 height = colorbuffer->getHeight(); 284 samples = colorbuffer->getSamples(); 285 } 286 287 Renderbuffer *depthbuffer = nullptr; 288 Renderbuffer *stencilbuffer = nullptr; 289 290 if(mDepthbufferType != GL_NONE_OES) 291 { 292 depthbuffer = getDepthbuffer(); 293 294 if(!depthbuffer) 295 { 296 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 297 } 298 299 if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) 300 { 301 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 302 } 303 304 if(mDepthbufferType == GL_RENDERBUFFER_OES) 305 { 306 if(!es1::IsDepthRenderable(depthbuffer->getFormat())) 307 { 308 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 309 } 310 } 311 else if(IsTextureTarget(mDepthbufferType)) 312 { 313 if(!es1::IsDepthTexture(depthbuffer->getFormat())) 314 { 315 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 316 } 317 } 318 else 319 { 320 UNREACHABLE(mDepthbufferType); 321 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 322 } 323 324 if(width == -1 || height == -1) 325 { 326 width = depthbuffer->getWidth(); 327 height = depthbuffer->getHeight(); 328 samples = depthbuffer->getSamples(); 329 } 330 else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) 331 { 332 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES; 333 } 334 else if(samples != depthbuffer->getSamples()) 335 { 336 UNREACHABLE(0); 337 } 338 } 339 340 if(mStencilbufferType != GL_NONE_OES) 341 { 342 stencilbuffer = getStencilbuffer(); 343 344 if(!stencilbuffer) 345 { 346 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 347 } 348 349 if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) 350 { 351 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 352 } 353 354 if(mStencilbufferType == GL_RENDERBUFFER_OES) 355 { 356 if(!es1::IsStencilRenderable(stencilbuffer->getFormat())) 357 { 358 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 359 } 360 } 361 else if(IsTextureTarget(mStencilbufferType)) 362 { 363 GLenum internalformat = stencilbuffer->getFormat(); 364 365 if(!es1::IsStencilTexture(internalformat)) 366 { 367 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 368 } 369 } 370 else 371 { 372 UNREACHABLE(mStencilbufferType); 373 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES; 374 } 375 376 if(width == -1 || height == -1) 377 { 378 width = stencilbuffer->getWidth(); 379 height = stencilbuffer->getHeight(); 380 samples = stencilbuffer->getSamples(); 381 } 382 else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) 383 { 384 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES; 385 } 386 else if(samples != stencilbuffer->getSamples()) 387 { 388 UNREACHABLE(0); 389 return GL_FRAMEBUFFER_UNSUPPORTED_OES; // GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_OES; 390 } 391 } 392 393 // We need to have at least one attachment to be complete 394 if(width == -1 || height == -1) 395 { 396 return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES; 397 } 398 399 return GL_FRAMEBUFFER_COMPLETE_OES; 400 } 401 402 GLenum Framebuffer::getImplementationColorReadFormat() 403 { 404 Renderbuffer *colorbuffer = mColorbufferPointer; 405 406 if(colorbuffer) 407 { 408 switch(colorbuffer->getFormat()) 409 { 410 case GL_BGRA8_EXT: return GL_BGRA_EXT; 411 case GL_RGBA4_OES: return GL_RGBA; 412 case GL_RGB5_A1_OES: return GL_RGBA; 413 case GL_RGBA8_OES: return GL_RGBA; 414 case GL_RGB565_OES: return GL_RGBA; 415 case GL_RGB8_OES: return GL_RGB; 416 default: 417 UNREACHABLE(colorbuffer->getFormat()); 418 } 419 } 420 421 return GL_RGBA; 422 } 423 424 GLenum Framebuffer::getImplementationColorReadType() 425 { 426 Renderbuffer *colorbuffer = mColorbufferPointer; 427 428 if(colorbuffer) 429 { 430 switch(colorbuffer->getFormat()) 431 { 432 case GL_BGRA8_EXT: return GL_UNSIGNED_BYTE; 433 case GL_RGBA4_OES: return GL_UNSIGNED_SHORT_4_4_4_4; 434 case GL_RGB5_A1_OES: return GL_UNSIGNED_SHORT_5_5_5_1; 435 case GL_RGBA8_OES: return GL_UNSIGNED_BYTE; 436 case GL_RGB565_OES: return GL_UNSIGNED_SHORT_5_6_5; 437 case GL_RGB8_OES: return GL_UNSIGNED_BYTE; 438 default: 439 UNREACHABLE(colorbuffer->getFormat()); 440 } 441 } 442 443 return GL_UNSIGNED_BYTE; 444 } 445 446 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) 447 { 448 mColorbufferPointer = new Renderbuffer(0, colorbuffer); 449 450 Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil); 451 mDepthbufferPointer = depthStencilRenderbuffer; 452 mStencilbufferPointer = depthStencilRenderbuffer; 453 454 mColorbufferType = GL_RENDERBUFFER_OES; 455 mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER_OES : GL_NONE_OES; 456 mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER_OES : GL_NONE_OES; 457 } 458 459 } 460