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 25namespace gl 26{ 27 28Framebuffer::Framebuffer() 29{ 30 mColorbufferType = GL_NONE; 31 mDepthbufferType = GL_NONE; 32 mStencilbufferType = GL_NONE; 33} 34 35Framebuffer::~Framebuffer() 36{ 37 mColorbufferPointer = nullptr; 38 mDepthbufferPointer = nullptr; 39 mStencilbufferPointer = nullptr; 40} 41 42Renderbuffer *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 64void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) 65{ 66 mColorbufferType = (colorbuffer != 0) ? type : GL_NONE; 67 mColorbufferPointer = lookupRenderbuffer(type, colorbuffer); 68} 69 70void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) 71{ 72 mDepthbufferType = (depthbuffer != 0) ? type : GL_NONE; 73 mDepthbufferPointer = lookupRenderbuffer(type, depthbuffer); 74} 75 76void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) 77{ 78 mStencilbufferType = (stencilbuffer != 0) ? type : GL_NONE; 79 mStencilbufferPointer = lookupRenderbuffer(type, stencilbuffer); 80} 81 82void 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 103void 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 126Image *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 140Image *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 157Renderbuffer *Framebuffer::getColorbuffer() 158{ 159 return mColorbufferPointer; 160} 161 162Renderbuffer *Framebuffer::getDepthbuffer() 163{ 164 return mDepthbufferPointer; 165} 166 167Renderbuffer *Framebuffer::getStencilbuffer() 168{ 169 return mStencilbufferPointer; 170} 171 172GLenum Framebuffer::getColorbufferType() 173{ 174 return mColorbufferType; 175} 176 177GLenum Framebuffer::getDepthbufferType() 178{ 179 return mDepthbufferType; 180} 181 182GLenum Framebuffer::getStencilbufferType() 183{ 184 return mStencilbufferType; 185} 186 187GLuint Framebuffer::getColorbufferName() 188{ 189 return mColorbufferPointer.name(); 190} 191 192GLuint Framebuffer::getDepthbufferName() 193{ 194 return mDepthbufferPointer.name(); 195} 196 197GLuint Framebuffer::getStencilbufferName() 198{ 199 return mStencilbufferPointer.name(); 200} 201 202bool 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 217GLenum Framebuffer::completeness() 218{ 219 int width; 220 int height; 221 int samples; 222 223 return completeness(width, height, samples); 224} 225 226GLenum 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 402DefaultFramebuffer::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 415GLenum 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