Home | History | Annotate | Download | only in libGL
      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