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. 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 gl 26 { 27 28 Framebuffer::Framebuffer() 29 { 30 mColorbufferType = GL_NONE; 31 mDepthbufferType = GL_NONE; 32 mStencilbufferType = GL_NONE; 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) const 43 { 44 Context *context = getContext(); 45 Renderbuffer *buffer = nullptr; 46 47 if(type == GL_NONE) 48 { 49 buffer = nullptr; 50 } 51 else if(type == GL_RENDERBUFFER) 52 { 53 buffer = context->getRenderbuffer(handle); 54 } 55 else if(IsTextureTarget(type)) 56 { 57 buffer = context->getTexture(handle)->getRenderbuffer(type); 58 } 59 else UNREACHABLE(type); 60 61 return buffer; 62 } 63 64 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) 65 { 66 mColorbufferType = (colorbuffer != 0) ? type : GL_NONE; 67 mColorbufferPointer = lookupRenderbuffer(type, colorbuffer); 68 } 69 70 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) 71 { 72 mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE; 73 mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer); 74 } 75 76 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) 77 { 78 mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE; 79 mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer); 80 } 81 82 void Framebuffer::detachTexture(GLuint texture) 83 { 84 if(mColorbufferPointer.name() == texture && IsTextureTarget(mColorbufferType)) 85 { 86 mColorbufferType = GL_NONE; 87 mColorbufferPointer = nullptr; 88 } 89 90 if(mDepthbufferPointer.name() == texture && IsTextureTarget(mDepthbufferType)) 91 { 92 mDepthbufferType = GL_NONE; 93 mDepthbufferPointer = nullptr; 94 } 95 96 if(mStencilbufferPointer.name() == texture && IsTextureTarget(mStencilbufferType)) 97 { 98 mStencilbufferType = GL_NONE; 99 mStencilbufferPointer = nullptr; 100 } 101 } 102 103 void Framebuffer::detachRenderbuffer(GLuint renderbuffer) 104 { 105 if(mColorbufferPointer.name() == renderbuffer && mColorbufferType == GL_RENDERBUFFER) 106 { 107 mColorbufferType = GL_NONE; 108 mColorbufferPointer = nullptr; 109 } 110 111 if(mDepthbufferPointer.name() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER) 112 { 113 mDepthbufferType = GL_NONE; 114 mDepthbufferPointer = nullptr; 115 } 116 117 if(mStencilbufferPointer.name() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER) 118 { 119 mStencilbufferType = GL_NONE; 120 mStencilbufferPointer = nullptr; 121 } 122 } 123 124 // Increments refcount on surface. 125 // caller must Release() the returned surface 126 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 Image *Framebuffer::getDepthStencil() 141 { 142 Renderbuffer *depthstencilbuffer = mDepthbufferPointer; 143 144 if(!depthstencilbuffer) 145 { 146 depthstencilbuffer = mStencilbufferPointer; 147 } 148 149 if(depthstencilbuffer) 150 { 151 return depthstencilbuffer->getRenderTarget(); 152 } 153 154 return nullptr; 155 } 156 157 Renderbuffer *Framebuffer::getColorbuffer() 158 { 159 return mColorbufferPointer; 160 } 161 162 Renderbuffer *Framebuffer::getDepthbuffer() 163 { 164 return mDepthbufferPointer; 165 } 166 167 Renderbuffer *Framebuffer::getStencilbuffer() 168 { 169 return mStencilbufferPointer; 170 } 171 172 GLenum Framebuffer::getColorbufferType() 173 { 174 return mColorbufferType; 175 } 176 177 GLenum Framebuffer::getDepthbufferType() 178 { 179 return mDepthbufferType; 180 } 181 182 GLenum Framebuffer::getStencilbufferType() 183 { 184 return mStencilbufferType; 185 } 186 187 GLuint Framebuffer::getColorbufferName() 188 { 189 return mColorbufferPointer.name(); 190 } 191 192 GLuint Framebuffer::getDepthbufferName() 193 { 194 return mDepthbufferPointer.name(); 195 } 196 197 GLuint Framebuffer::getStencilbufferName() 198 { 199 return mStencilbufferPointer.name(); 200 } 201 202 bool Framebuffer::hasStencil() 203 { 204 if(mStencilbufferType != GL_NONE) 205 { 206 Renderbuffer *stencilbufferObject = getStencilbuffer(); 207 208 if(stencilbufferObject) 209 { 210 return stencilbufferObject->getStencilSize() > 0; 211 } 212 } 213 214 return false; 215 } 216 217 GLenum Framebuffer::completeness() 218 { 219 int width; 220 int height; 221 int samples; 222 223 return completeness(width, height, samples); 224 } 225 226 GLenum Framebuffer::completeness(int &width, int &height, int &samples) 227 { 228 width = -1; 229 height = -1; 230 samples = -1; 231 232 if(mColorbufferType != GL_NONE) 233 { 234 Renderbuffer *colorbuffer = getColorbuffer(); 235 236 if(!colorbuffer) 237 { 238 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 239 } 240 241 if(colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) 242 { 243 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 244 } 245 246 if(mColorbufferType == GL_RENDERBUFFER) 247 { 248 if(!gl::IsColorRenderable(colorbuffer->getFormat())) 249 { 250 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 251 } 252 } 253 else if(IsTextureTarget(mColorbufferType)) 254 { 255 GLenum format = colorbuffer->getFormat(); 256 257 if(IsCompressed(format) || 258 format == GL_ALPHA || 259 format == GL_LUMINANCE || 260 format == GL_LUMINANCE_ALPHA) 261 { 262 return GL_FRAMEBUFFER_UNSUPPORTED; 263 } 264 265 if(gl::IsDepthTexture(format) || gl::IsStencilTexture(format)) 266 { 267 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 268 } 269 } 270 else 271 { 272 UNREACHABLE(mColorbufferType); 273 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 274 } 275 276 width = colorbuffer->getWidth(); 277 height = colorbuffer->getHeight(); 278 samples = colorbuffer->getSamples(); 279 } 280 281 Renderbuffer *depthbuffer = nullptr; 282 Renderbuffer *stencilbuffer = nullptr; 283 284 if(mDepthbufferType != GL_NONE) 285 { 286 depthbuffer = getDepthbuffer(); 287 288 if(!depthbuffer) 289 { 290 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 291 } 292 293 if(depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) 294 { 295 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 296 } 297 298 if(mDepthbufferType == GL_RENDERBUFFER) 299 { 300 if(!gl::IsDepthRenderable(depthbuffer->getFormat())) 301 { 302 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 303 } 304 } 305 else if(IsTextureTarget(mDepthbufferType)) 306 { 307 if(!gl::IsDepthTexture(depthbuffer->getFormat())) 308 { 309 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 310 } 311 } 312 else 313 { 314 UNREACHABLE(mDepthbufferType); 315 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 316 } 317 318 if(width == -1 || height == -1) 319 { 320 width = depthbuffer->getWidth(); 321 height = depthbuffer->getHeight(); 322 samples = depthbuffer->getSamples(); 323 } 324 else if(width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) 325 { 326 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 327 } 328 else if(samples != depthbuffer->getSamples()) 329 { 330 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; 331 } 332 } 333 334 if(mStencilbufferType != GL_NONE) 335 { 336 stencilbuffer = getStencilbuffer(); 337 338 if(!stencilbuffer) 339 { 340 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 341 } 342 343 if(stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) 344 { 345 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 346 } 347 348 if(mStencilbufferType == GL_RENDERBUFFER) 349 { 350 if(!gl::IsStencilRenderable(stencilbuffer->getFormat())) 351 { 352 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 353 } 354 } 355 else if(IsTextureTarget(mStencilbufferType)) 356 { 357 GLenum internalformat = stencilbuffer->getFormat(); 358 359 if(!gl::IsStencilTexture(internalformat)) 360 { 361 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 362 } 363 } 364 else 365 { 366 UNREACHABLE(mStencilbufferType); 367 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; 368 } 369 370 if(width == -1 || height == -1) 371 { 372 width = stencilbuffer->getWidth(); 373 height = stencilbuffer->getHeight(); 374 samples = stencilbuffer->getSamples(); 375 } 376 else if(width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) 377 { 378 return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT; 379 } 380 else if(samples != stencilbuffer->getSamples()) 381 { 382 return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; 383 } 384 } 385 386 // If we have both a depth and stencil buffer, they must refer to the same object 387 // since we only support packed_depth_stencil and not separate depth and stencil 388 if(depthbuffer && stencilbuffer && (depthbuffer != stencilbuffer)) 389 { 390 return GL_FRAMEBUFFER_UNSUPPORTED; 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; 397 } 398 399 return GL_FRAMEBUFFER_COMPLETE; 400 } 401 402 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) 403 { 404 mColorbufferPointer = new Renderbuffer(0, colorbuffer); 405 406 Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil); 407 mDepthbufferPointer = depthStencilRenderbuffer; 408 mStencilbufferPointer = depthStencilRenderbuffer; 409 410 mColorbufferType = GL_RENDERBUFFER; 411 mDepthbufferType = (depthStencilRenderbuffer->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE; 412 mStencilbufferType = (depthStencilRenderbuffer->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE; 413 } 414 415 GLenum DefaultFramebuffer::completeness() 416 { 417 // The default framebuffer should always be complete 418 ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE); 419 420 return GL_FRAMEBUFFER_COMPLETE; 421 } 422 423 } 424