示例#1
0
void FrameBufferObject::Begin(GraphicsState & glstate, std::ostream & error_output, float viewscale)
{
	CheckForOpenGLErrors("before FBO begin", error_output);

	assert(inited);
	assert(framebuffer_object > 0);
	assert(!textures.empty());

	glstate.BindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);

	CheckForOpenGLErrors("FBO bind to framebuffer", error_output);

	FrameBufferTexture * tex = textures.back();
	if (tex->GetTarget() == FrameBufferTexture::CUBEMAP)
	{
		glFramebufferTexture2D(GL_FRAMEBUFFER, tex->GetAttachment(), tex->GetSide(), tex->GetId(), 0);
		CheckForOpenGLErrors("FBO cubemap side attachment", error_output);
	}

	assert(CheckStatus(error_output));

	glstate.SetViewport(int(tex->GetW() * viewscale), int(tex->GetH() * viewscale));

	CheckForOpenGLErrors("during FBO begin", error_output);
}
示例#2
0
void FrameBufferObject::End(GraphicsState & glstate, std::ostream & error_output)
{
	CheckForOpenGLErrors("start of FBO end", error_output);

	if (singlesample_framebuffer_object)
	{
		glstate.BindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer_object);
		glstate.BindFramebuffer(GL_DRAW_FRAMEBUFFER, singlesample_framebuffer_object->framebuffer_object);

		assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
		assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);

		CheckForOpenGLErrors("FBO end multisample binding", error_output);

		const int w = singlesample_framebuffer_object->GetWidth();
		const int h = singlesample_framebuffer_object->GetHeight();
		glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);

		CheckForOpenGLErrors("FBO end multisample blit", error_output);
	}

	CheckForOpenGLErrors("FBO multisample blit", error_output);

	// optionally rebuild mipmaps
	for (std::vector <FrameBufferTexture*>::const_iterator i = textures.begin(); i != textures.end(); i++)
	{
		if ((*i)->HasMipMap())
		{
			glstate.BindTexture(0, (*i)->GetTarget(), (*i)->GetId());
			glGenerateMipmap((*i)->GetTarget());
			glstate.BindTexture(0, (*i)->GetTarget(), 0);
		}
	}

	CheckForOpenGLErrors("end of FBO end", error_output);
}
示例#3
0
void FrameBufferObject::Init(
	GraphicsState & glstate,
	const std::vector <FrameBufferTexture*> & newtextures,
	std::ostream & error_output,
	bool force_multisample_off)
{
	CheckForOpenGLErrors("FBO init start", error_output);

	const bool verbose = false;

	if (inited)
	{
		if (verbose) error_output << "INFO: deinitializing existing FBO" << std::endl;

		DeInit();

		CheckForOpenGLErrors("FBO deinit", error_output);
	}
	inited = true;

	// need at least some textures
	assert(!newtextures.empty());
	textures = newtextures;

	width = -1;
	height = -1;
	std::vector <FrameBufferTexture*> color_textures;
	FrameBufferTexture * depth_texture = 0;
	for (std::vector <FrameBufferTexture*>::const_iterator i = textures.begin(); i != textures.end(); i++)
	{
		// ensure consistent sizes
		if (width == -1)
			width = (*i)->GetW();
		if (height == -1)
			height = (*i)->GetH();
		assert(width == int((*i)->GetW()));
		assert(height == int((*i)->GetH()));

		// separate textures by type
		if ((*i)->GetFormat() == FrameBufferTexture::DEPTH24)
		{
			// can't have more than one depth attachment
			assert(!depth_texture);
			depth_texture = *i;
		}
		else
		{
			color_textures.push_back(*i);
		}
	}
	if (verbose) error_output << "INFO: width " << width << ", height " << height << std::endl;
	if (verbose) error_output << "INFO: color textures: " << color_textures.size() << std::endl;
	if (verbose && depth_texture) error_output << "INFO: depth texture: 1" << std::endl;

	// can't have more than 4 color attachments
	assert(color_textures.size() < 5);

	// check for cubemaps
	for (std::vector <FrameBufferTexture*>::const_iterator i = color_textures.begin(); i != color_textures.end(); i++)
	{
		if ((*i)->GetTarget() == FrameBufferTexture::CUBEMAP)
		{
			if (verbose) error_output << "INFO: found cubemap" << std::endl;

			// can't have MRT with cubemaps
			assert(color_textures.size() == 1);

			// can't have multisample with cubemaps
			assert((*i)->GetMultiSample() == 0);

			// can't have depth texture with cubemaps
			assert(!depth_texture);
		}
	}

	// find what multisample value to use
	int multisample = 0;
	if (!color_textures.empty())
	{
		multisample = -1;
		for (std::vector <FrameBufferTexture*>::const_iterator i = textures.begin(); i != textures.end(); i++)
		{
			if (multisample == -1)
				multisample = (*i)->GetMultiSample();

			// all must have the same multisample
			assert(multisample == (*i)->GetMultiSample());
		}
	}

	if (verbose) error_output << "INFO: multisample " << multisample << " found, " << force_multisample_off << std::endl;

	if (force_multisample_off)
		multisample = 0;

	// either we have no multisample or multisample and no depth texture
	assert((multisample == 0) || ((multisample > 0) && depth_texture));

	// initialize framebuffer object
	glGenFramebuffers(1, &framebuffer_object);

	if (verbose) error_output << "INFO: generated FBO " << framebuffer_object << std::endl;

	CheckForOpenGLErrors("FBO generation", error_output);

	// bind framebuffer
	glstate.BindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);

	CheckForOpenGLErrors("FBO binding", error_output);

	if (!depth_texture)
	{
		// create depth render buffer if we're not using a depth texture
		glGenRenderbuffers(1, &depth_renderbuffer);
		glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer);

		if (verbose) error_output << "INFO: generating depth renderbuffer" << std::endl;

		CheckForOpenGLErrors("FBO renderbuffer generation", error_output);

		if (multisample > 0)
		{
			glRenderbufferStorageMultisample(GL_RENDERBUFFER, multisample, GL_DEPTH_COMPONENT, width, height);

			if (verbose) error_output << "INFO: using multisampling for depth renderbuffer" << std::endl;
		}
		else
		{
			glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
		}

		CheckForOpenGLErrors("FBO renderbuffer initialization", error_output);

		// attach depth render buffer to the FBO
		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_renderbuffer);

		if (verbose) error_output << "INFO: depth renderbuffer attached to FBO" << std::endl;

		CheckForOpenGLErrors("FBO renderbuffer attachment", error_output);
	}

	if (multisample > 0)
	{
		// create/attach separate multisample color buffers for each color texture
		multisample_renderbuffers.resize(color_textures.size(), 0);
		for (size_t i = 0; i < color_textures.size(); i++)
		{
			glGenRenderbuffers(1, &multisample_renderbuffers[i]);
			glBindRenderbuffer(GL_RENDERBUFFER, multisample_renderbuffers[i]);
			glRenderbufferStorageMultisample(GL_RENDERBUFFER, multisample, color_textures[i]->GetFormat(), width, height);

			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, multisample_renderbuffers[i]);

			if (verbose) error_output << "INFO: generating separate multisample color buffer " << i << std::endl;

			CheckForOpenGLErrors("FBO multisample color renderbuffer", error_output);
		}
	}
	else
	{
		// attach color textures to frame buffer object
		int count = 0;
		for (std::vector <FrameBufferTexture*>::iterator i = color_textures.begin(); i != color_textures.end(); i++, count++)
		{
			int attachment = GL_COLOR_ATTACHMENT0 + count;
			if ((*i)->GetTarget() == FrameBufferTexture::CUBEMAP)
			{
				// if we're using a cubemap, arbitrarily pick one of the faces to activate so we can check that the FBO is complete
				glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X, (*i)->GetId(), 0);

				if (verbose) error_output << "INFO: attaching arbitrary cubemap face to color attachment " << count << std::endl;
			}
			else
			{
				glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, (*i)->GetTarget(), (*i)->GetId(), 0);

				if (verbose) error_output << "INFO: attaching texture to color attachment " << count << std::endl;
			}
			(*i)->SetAttachment(attachment);

			CheckForOpenGLErrors("FBO attachment", error_output);
		}

		if (depth_texture)
		{
			// attach depth texture to frame buffer object
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture->GetTarget(), depth_texture->GetId(), 0);
			depth_texture->SetAttachment(GL_DEPTH_ATTACHMENT);

			if (verbose) error_output << "INFO: attaching depth texture" << std::endl;
			CheckForOpenGLErrors("FBO attachment", error_output);
		}
	}

	GLenum buffers[4] = {GL_NONE, GL_NONE, GL_NONE, GL_NONE};
	{
		int count = 0;
		for (std::vector <FrameBufferTexture*>::const_iterator i = color_textures.begin(); i != color_textures.end(); i++, count++)
		{
			buffers[count] = GL_COLOR_ATTACHMENT0 + count;
		}

		glDrawBuffers(count, buffers);
		glReadBuffer(buffers[0]);

		CheckForOpenGLErrors("FBO buffer mask set", error_output);
	}

	if (verbose) error_output << "INFO: set draw buffers: " << buffers[0] << ", " << buffers[1] << ", " << buffers[2] << ", " << buffers[3] << std::endl;
	if (verbose) error_output << "INFO: set read buffer: " << buffers[0] << std::endl;

	if (!CheckStatus(error_output))
	{
		error_output << "Error initializing FBO:" << std::endl;
		int count = 0;
		for (std::vector <FrameBufferTexture*>::const_iterator i = textures.begin(); i != textures.end(); i++)
		{
			error_output << "\t" << count << ". " << TargetToString(FrameBufferTexture::Target((*i)->GetTarget()));
			error_output << ": " << FormatToString((*i)->GetFormat()) << std::endl;
			count++;
		}
		assert(0);
	}

	// explicitely unbind framebuffer object
	glstate.BindFramebuffer(GL_FRAMEBUFFER, 0);

	CheckForOpenGLErrors("FBO unbinding", error_output);

	// if multisampling is on, create another framebuffer object for the single sample version of these textures
	if (multisample > 0)
	{
		if (verbose) error_output << "INFO: creating secondary single sample framebuffer object" << std::endl;

		assert(!singlesample_framebuffer_object);
		singlesample_framebuffer_object = new FrameBufferObject();
		singlesample_framebuffer_object->Init(glstate, newtextures, error_output, true);
	}
}