示例#1
0
Renderbuffer::Obj::Obj( int aWidth, int aHeight, GLenum internalFormat, int msaaSamples, int coverageSamples )
	: mWidth( aWidth ), mHeight( aHeight ), mInternalFormat( internalFormat ), mSamples( msaaSamples ), mCoverageSamples( coverageSamples )
{
#if defined( CINDER_MSW )
	static bool csaaSupported = ( GLEE_NV_framebuffer_multisample_coverage != 0 );
#else
	static bool csaaSupported = false;
#endif

	GL_SUFFIX(glGenRenderbuffers)( 1, &mId );

	if( mSamples > Fbo::getMaxSamples() )
		mSamples = Fbo::getMaxSamples();

	if( ! csaaSupported )
		mCoverageSamples = 0;

	GL_SUFFIX(glBindRenderbuffer)( GL_SUFFIX(GL_RENDERBUFFER_), mId );

#if ! defined( CINDER_GLES )
  #if defined( CINDER_MSW )
	if( mCoverageSamples ) // create a CSAA buffer
		glRenderbufferStorageMultisampleCoverageNV( GL_RENDERBUFFER_EXT, mCoverageSamples, mSamples, mInternalFormat, mWidth, mHeight );
	else
  #endif
	if( mSamples ) // create a regular MSAA buffer
		glRenderbufferStorageMultisampleEXT( GL_RENDERBUFFER_EXT, mSamples, mInternalFormat, mWidth, mHeight );
	else
#endif
		GL_SUFFIX(glRenderbufferStorage)( GL_SUFFIX(GL_RENDERBUFFER_), mInternalFormat, mWidth, mHeight );
}
示例#2
0
bool CFrameBufferObject::createCSAA( GLuint width, GLuint height, fboConfig *p_config, fboData *p_data )
{
    GLint query;
    bool ret = false;

    // Step #1
    {
        glGenRenderbuffersEXT( 1, &p_data->depthRB);
        glGenRenderbuffersEXT( 1, &p_data->colorRB);
        glGenFramebuffersEXT( 1, &p_data->resolveFB);
        p_data->depthTex = 0; //no resolve of depth buffer for now
        
        //multisample, so we need to resolve from the FBO, bind the texture to the resolve FBO
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, p_data->resolveFB); 

        glFramebufferTexture2DEXT(	GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 
									m_eGLTarget, p_data->colorTex, 0);

        ret &= checkStatus(__FILE__, __LINE__, true);

        //now handle the rendering FBO
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, p_data->fb);

        // initialize color renderbuffer
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, p_data->colorRB);
    }

	// Step #2
	{
		glRenderbufferStorageMultisampleCoverageNV( GL_RENDERBUFFER_EXT, 
													p_config->coverageSamples, 
													p_config->depthSamples, 
													p_config->colorFormat,
													width, height);

		glGetRenderbufferParameterivEXT( GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_COVERAGE_SAMPLES_NV, &query);

		if ( query < p_config->coverageSamples) {
		   ret = false;
		}
		else if ( query > p_config->coverageSamples) {
			// report back the actual number
			p_config->coverageSamples = query;
		}

		glGetRenderbufferParameterivEXT( GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_COLOR_SAMPLES_NV, &query);

		if ( query < p_config->depthSamples) {
		   ret = false;
		}
		else if ( query > p_config->depthSamples) {
			// report back the actual number
			p_config->depthSamples = query;
		}
	}

	// Step #3
	{
        // attach the multisampled color buffer
        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, p_data->colorRB);

        ret &= checkStatus(__FILE__, __LINE__, true);

        // bind the multisampled depth buffer
        glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, p_data->depthRB);
	}

	// Step #4 create the multisampled depth buffer (with coverage sampling)
	{
        // create a coverage sampled MSAA depth buffer
        glRenderbufferStorageMultisampleCoverageNV( GL_RENDERBUFFER_EXT, 
													p_config->coverageSamples, 
													p_config->depthSamples, 
													p_config->depthFormat,
                                                    width, height);

        // check the number of coverage samples
        glGetRenderbufferParameterivEXT( GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_COVERAGE_SAMPLES_NV, &query);

        if ( query < p_config->coverageSamples) {
            ret = false;
        }
        else if ( query > p_config->coverageSamples) {
            // set the coverage samples value to return the actual value
            p_config->coverageSamples = query;
        } 

        // cehck the number of stored color samples (same as depth samples)
        glGetRenderbufferParameterivEXT( GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_COLOR_SAMPLES_NV, &query);

        if ( query < p_config->depthSamples) {
            ret = false;
        }
        else if ( query > p_config->depthSamples) {
            // set the depth samples value to return the actual value
            p_config->depthSamples = query;
        }
	}
	return ret;
}
FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, int msaaCoverageSamples)
{
    m_efbFramebuffer = 0;
    m_efbColor = 0;
    m_efbDepth = 0;
    m_resolvedFramebuffer = 0;
    m_resolvedColorTexture = 0;
    m_resolvedDepthTexture = 0;
    m_xfbFramebuffer = 0;

	m_targetWidth = targetWidth;
	m_targetHeight = targetHeight;

	m_msaaSamples = msaaSamples;
	m_msaaCoverageSamples = msaaCoverageSamples;

	// The EFB can be set to different pixel formats by the game through the
	// BPMEM_ZCOMPARE register (which should probably have a different name).
	// They are:
	// - 24-bit RGB (8-bit components) with 24-bit Z
	// - 24-bit RGBA (6-bit components) with 24-bit Z
	// - Multisampled 16-bit RGB (5-6-5 format) with 16-bit Z
	// We only use one EFB format here: 32-bit ARGB with 24-bit Z.
	// Multisampling depends on user settings.
	// The distinction becomes important for certain operations, i.e. the
	// alpha channel should be ignored if the EFB does not have one.

	// Create EFB target.

	glGenFramebuffersEXT(1, &m_efbFramebuffer);

	if (m_msaaSamples <= 1)
	{
		// EFB targets will be textures in non-MSAA mode.

		GLuint glObj[2];
		glGenTextures(2, glObj);
		m_efbColor = glObj[0];
		m_efbDepth = glObj[1];

		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbColor);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_efbDepth);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);

		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);

		// Bind target textures to the EFB framebuffer.

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);

		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbColor, 0);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_efbDepth, 0);

		GL_REPORT_FBO_ERROR();
	}
	else
	{
		// EFB targets will be renderbuffers in MSAA mode (required by OpenGL).
		// Resolve targets will be created to transfer EFB to RAM textures.
		// XFB framebuffer will be created to transfer EFB to XFB texture.

		// Create EFB target renderbuffers.

		GLuint glObj[2];
		glGenRenderbuffersEXT(2, glObj);
		m_efbColor = glObj[0];
		m_efbDepth = glObj[1];

		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbColor);
		if (m_msaaCoverageSamples)
			glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);
		else
			glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_RGBA8, m_targetWidth, m_targetHeight);

		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_efbDepth);
		if (m_msaaCoverageSamples)
			glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, m_msaaCoverageSamples, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);
		else
			glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, m_msaaSamples, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight);

		glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);

		// Bind target renderbuffers to EFB framebuffer.

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);

		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_efbColor);
		glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_efbDepth);

		GL_REPORT_FBO_ERROR();

		// Create resolved targets for transferring multisampled EFB to texture.

		glGenFramebuffersEXT(1, &m_resolvedFramebuffer);

		glGenTextures(2, glObj);
		m_resolvedColorTexture = glObj[0];
		m_resolvedDepthTexture = glObj[1];

		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, m_targetWidth, m_targetHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture);
		glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_DEPTH_COMPONENT24, m_targetWidth, m_targetHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);

		glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);

		// Bind resolved textures to resolved framebuffer.

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_resolvedFramebuffer);

		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedColorTexture, 0);
		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, m_resolvedDepthTexture, 0);

		GL_REPORT_FBO_ERROR();

		// Return to EFB framebuffer.

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_efbFramebuffer);
	}

	// Create XFB framebuffer; targets will be created elsewhere.

	glGenFramebuffersEXT(1, &m_xfbFramebuffer);

	// EFB framebuffer is currently bound, make sure to clear its alpha value to 1.f
	glViewport(0, 0, m_targetWidth, m_targetHeight);
	glScissor(0, 0, m_targetWidth, m_targetHeight);
	glClearColor(0.f, 0.f, 0.f, 1.f);
	glClearDepth(1.0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
}
示例#4
0
 void Renderbuffer::resizeCSAA()
 {
   glRenderbufferStorageMultisampleCoverageNV( GL_RENDERBUFFER_EXT, m_coverageSamples, m_colorSamples, m_internalFormat, m_width, m_height );
 }
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_NVFramebufferMultisampleCoverage_nglRenderbufferStorageMultisampleCoverageNV(JNIEnv *env, jclass clazz, jint target, jint coverageSamples, jint colorSamples, jint internalformat, jint width, jint height, jlong function_pointer) {
	glRenderbufferStorageMultisampleCoverageNVPROC glRenderbufferStorageMultisampleCoverageNV = (glRenderbufferStorageMultisampleCoverageNVPROC)((intptr_t)function_pointer);
	glRenderbufferStorageMultisampleCoverageNV(target, coverageSamples, colorSamples, internalformat, width, height);
}
示例#6
0
文件: rtt.cpp 项目: a2flo/a2elight
rtt::fbo* rtt::add_buffer(const unsigned int width_, const unsigned int height_,
                          const GLenum* target, const TEXTURE_FILTERING* filtering,
                          const TEXTURE_ANTI_ALIASING* taa,
                          const GLint* wrap_s, const GLint* wrap_t,
                          const GLint* internal_format,
                          const GLenum* format,
                          const GLenum* type,
                          const unsigned int attachment_count,
                          const rtt::DEPTH_TYPE depth_type,
                          const rtt::STENCIL_TYPE stencil_type) {
    unsigned int width = width_;
    unsigned int height = height_;

    rtt::fbo* buffer = new rtt::fbo(attachment_count);
    buffers.push_back(buffer);
    buffer->width = width;
    buffer->height = height;
    buffer->draw_width = width;
    buffer->draw_height = height;
    buffer->depth_type = depth_type;
    buffer->stencil_type = stencil_type;
    buffer->samples = 0;

    //
    const size_t max_tex_size = exts->get_max_texture_size();
    const float fmax_tex_size = max_tex_size;
    size2 orig_resolution = size2(width, height);
    float ssaa = 0.0f;
    for(unsigned int i = 0; i < buffer->attachment_count; i++) {
        buffer->anti_aliasing[i] = taa[i];

        float ssaa_factor = get_anti_aliasing_scale(buffer->anti_aliasing[i]);
        if(ssaa_factor <= 1.0f) continue;

        //
        // try lower ssaa setting
        float cur_ssaa_factor = ssaa_factor;
        while(cur_ssaa_factor >= 2.0f) {
            if(float(orig_resolution.x) * ssaa_factor > fmax_tex_size ||
                    float(orig_resolution.y) * ssaa_factor > fmax_tex_size) {
                cur_ssaa_factor -= 2.0f;
                continue;
            }
            else break;
        }

        if(cur_ssaa_factor <= 0.0f) {
            log_error("couldn't create a SSAA%u buffer (nor using a smaller SSAA setting)!", ssaa_factor);
            break; // break, since this won't work with any setting
        }

        if(cur_ssaa_factor < ssaa_factor) {
            log_error("couldn't create a SSAA%u buffer - using SSAA%u instead!", ssaa_factor, cur_ssaa_factor);
        }

        ssaa = std::max(ssaa, cur_ssaa_factor);
    }

    // apply ssaa
    if(ssaa > 0.0f) {
        const float2 ssaa_res = get_resolution_for_scale(ssaa, size2(width, height));
        width = (unsigned int)ssaa_res.x;
        height = (unsigned int)ssaa_res.y;
        buffer->width = width;
        buffer->height = height;
        buffer->draw_width = width;
        buffer->draw_height = height;
    }

    //
    glGenFramebuffers(1, &buffer->fbo_id);
    glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo_id);

    glGenTextures((GLsizei)attachment_count, &buffer->tex[0]);
    for(unsigned int i = 0; i < buffer->attachment_count; i++) {
#if defined(FLOOR_IOS) && !defined(PLATFORM_X64)
        if(i > 0) {
            log_error("too many FBO attachments - only one is allowed on iOS!");
            break;
        }
#endif

        buffer->target[i] = target[i];
        glBindTexture(buffer->target[i], buffer->tex[i]);

        glTexParameteri(buffer->target[i], GL_TEXTURE_MAG_FILTER,
                        (filtering[i] == TEXTURE_FILTERING::POINT ? GL_NEAREST : GL_LINEAR));
        glTexParameteri(buffer->target[i], GL_TEXTURE_MIN_FILTER, texman::select_filter(filtering[i]));
        glTexParameteri(buffer->target[i], GL_TEXTURE_WRAP_S, wrap_s[i]);
        glTexParameteri(buffer->target[i], GL_TEXTURE_WRAP_T, wrap_t[i]);
        if(exts->is_anisotropic_filtering_support() && filtering[i] >= TEXTURE_FILTERING::BILINEAR) {
            glTexParameteri(buffer->target[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, (GLint)exts->get_max_anisotropic_filtering());
        }

        switch(buffer->target[i]) {
#if !defined(FLOOR_IOS)
        case GL_TEXTURE_1D:
            glTexImage1D(buffer->target[i], 0, texman::convert_internal_format(internal_format[i]), (GLsizei)width, 0, format[i], type[i], nullptr);
            break;
#endif
        case GL_TEXTURE_2D:
            glTexImage2D(buffer->target[i], 0, texman::convert_internal_format(internal_format[i]), (GLsizei)width, (GLsizei)height, 0, format[i], type[i], nullptr);
            break;
#if !defined(FLOOR_IOS)
        case GL_TEXTURE_2D_MULTISAMPLE:
            glTexImage2DMultisample(buffer->target[i], (GLsizei)get_sample_count(buffer->anti_aliasing[0]), texman::convert_internal_format(internal_format[i]), (GLsizei)width, (GLsizei)height, false);
            break;
#endif
        default:
            glTexImage2D(buffer->target[i], 0, texman::convert_internal_format(internal_format[i]), (GLsizei)width, (GLsizei)height, 0, format[i], type[i], nullptr);
            break;
        }

        if(filtering[i] > TEXTURE_FILTERING::LINEAR) {
            buffer->auto_mipmap[i] = true;
            //glGenerateMipmap(buffer->target[i]);
        }
        else buffer->auto_mipmap[i] = false;

        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, buffer->target[i], buffer->tex[i], 0);

#if !defined(FLOOR_IOS)
#if defined(A2E_DEBUG)
        // TODO: fbo/texture checking
        GLint check_internal_format = 0, check_type = 0, check_size = 0;
        glGetTexLevelParameteriv(buffer->target[i], 0, GL_TEXTURE_INTERNAL_FORMAT, &check_internal_format);
        glGetTexLevelParameteriv(buffer->target[i], 0, GL_TEXTURE_RED_TYPE, &check_type);
        glGetTexLevelParameteriv(buffer->target[i], 0, GL_TEXTURE_RED_SIZE, &check_size);
        //log_debug("FBO: iformat: %X, type: %X, size: %d", check_internal_format, check_type, check_size);
#endif
#endif
    }

    current_buffer = buffer;
    check_fbo(current_buffer);

    // check if a depth attachment should be created
    if(depth_type != DEPTH_TYPE::NONE) {
        // apparently opencl/opengl depth texture sharing only works with a float format
#if !defined(A2E_INFERRED_RENDERING_CL)
        GLenum depth_internel_format = GL_DEPTH_COMPONENT24;
        GLenum depth_storage_type = GL_UNSIGNED_INT;
#else
        GLenum depth_internel_format = GL_DEPTH_COMPONENT32F;
        GLenum depth_storage_type = GL_FLOAT;
#endif
        GLenum depth_format = GL_DEPTH_COMPONENT;
        GLenum depth_attachment_type = GL_DEPTH_ATTACHMENT;
        if(stencil_type == STENCIL_TYPE::STENCIL_8) {
#if !defined(A2E_INFERRED_RENDERING_CL)
            depth_internel_format = GL_DEPTH24_STENCIL8;
            depth_storage_type = GL_UNSIGNED_INT_24_8;
#else
            depth_internel_format = GL_DEPTH32F_STENCIL8;
            depth_storage_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
#endif
            depth_format = GL_DEPTH_STENCIL;
            depth_attachment_type = GL_DEPTH_STENCIL_ATTACHMENT;
        }
        buffer->depth_attachment_type = depth_attachment_type;

        switch(buffer->anti_aliasing[0]) {
        case TEXTURE_ANTI_ALIASING::NONE:
        case TEXTURE_ANTI_ALIASING::SSAA_2:
        case TEXTURE_ANTI_ALIASING::SSAA_4:
        case TEXTURE_ANTI_ALIASING::FXAA:
        case TEXTURE_ANTI_ALIASING::SSAA_4_3_FXAA:
        case TEXTURE_ANTI_ALIASING::SSAA_2_FXAA:
            if(depth_type == DEPTH_TYPE::RENDERBUFFER) {
                glGenRenderbuffers(1, &buffer->depth_buffer);
                glBindRenderbuffer(GL_RENDERBUFFER, buffer->depth_buffer);
                glRenderbufferStorage(GL_RENDERBUFFER, depth_internel_format, (GLsizei)width, (GLsizei)height);
            }
            else if(depth_type == DEPTH_TYPE::TEXTURE_2D) {
                glGenTextures(1, &buffer->depth_buffer);
                glBindTexture(GL_TEXTURE_2D, buffer->depth_buffer);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);

                glTexImage2D(GL_TEXTURE_2D, 0, texman::convert_internal_format((GLint)depth_internel_format), (GLsizei)width, (GLsizei)height, 0, depth_format, depth_storage_type, nullptr);
                glFramebufferTexture2D(GL_FRAMEBUFFER, depth_attachment_type, GL_TEXTURE_2D, buffer->depth_buffer, 0);
            }

            check_fbo(current_buffer);
            break;
        case TEXTURE_ANTI_ALIASING::MSAA_2:
        case TEXTURE_ANTI_ALIASING::MSAA_4:
        case TEXTURE_ANTI_ALIASING::MSAA_8:
        case TEXTURE_ANTI_ALIASING::MSAA_16:
        case TEXTURE_ANTI_ALIASING::MSAA_32:
        case TEXTURE_ANTI_ALIASING::MSAA_64: {
            buffer->samples = get_sample_count(buffer->anti_aliasing[0]);

            glGenFramebuffers((GLsizei)attachment_count, &buffer->resolve_buffer[0]);
            for(size_t i = 0; i < attachment_count; i++) {
                glBindFramebuffer(GL_FRAMEBUFFER, buffer->resolve_buffer[i]);
                glFramebufferTexture2D(GL_FRAMEBUFFER, (GLenum)(GL_COLOR_ATTACHMENT0+i), target[i], buffer->tex[i], 0);
            }
            check_fbo(current_buffer);

            glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo_id);

            glGenRenderbuffers(1, &buffer->color_buffer);
            glBindRenderbuffer(GL_RENDERBUFFER, buffer->color_buffer);
            glRenderbufferStorageMultisample(GL_RENDERBUFFER, (GLsizei)buffer->samples, (GLenum)internal_format[0], (GLsizei)buffer->width, (GLsizei)buffer->height);
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, buffer->color_buffer);
            check_fbo(current_buffer);

            if(depth_type == DEPTH_TYPE::RENDERBUFFER) {
                glGenRenderbuffers(1, &buffer->depth_buffer);
                glBindRenderbuffer(GL_RENDERBUFFER, buffer->depth_buffer);
                glRenderbufferStorageMultisample(GL_RENDERBUFFER, (GLsizei)buffer->samples, depth_internel_format, (GLsizei)buffer->width, (GLsizei)buffer->height);
                glFramebufferRenderbuffer(GL_FRAMEBUFFER, depth_attachment_type, GL_RENDERBUFFER, buffer->depth_buffer);
            }
#if !defined(FLOOR_IOS)
            else if(depth_type == DEPTH_TYPE::TEXTURE_2D) {
                glGenTextures(1, &buffer->depth_buffer);
                glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, buffer->depth_buffer);
                glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

                glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, (GLsizei)buffer->samples, texman::convert_internal_format((GLint)depth_internel_format), (GLsizei)width, (GLsizei)height, false);
                glFramebufferTexture2D(GL_FRAMEBUFFER, depth_attachment_type, GL_TEXTURE_2D_MULTISAMPLE, buffer->depth_buffer, 0);
            }
#endif

            check_fbo(current_buffer);
        }
        break;
#if !defined(FLOOR_IOS) && 0 // TODO: fix or remove this
        case TEXTURE_ANTI_ALIASING::CSAA_8:
        case TEXTURE_ANTI_ALIASING::CSAA_8Q:
        case TEXTURE_ANTI_ALIASING::CSAA_16:
        case TEXTURE_ANTI_ALIASING::CSAA_16Q:
        case TEXTURE_ANTI_ALIASING::CSAA_32:
        case TEXTURE_ANTI_ALIASING::CSAA_32Q: {
            int color_samples, coverage_samples;
            switch(buffer->anti_aliasing[0]) {
            case TEXTURE_ANTI_ALIASING::CSAA_8:
                color_samples = 4;
                coverage_samples = 8;
                break;
            case TEXTURE_ANTI_ALIASING::CSAA_8Q:
                color_samples = 8;
                coverage_samples = 8;
                break;
            case TEXTURE_ANTI_ALIASING::CSAA_16:
                color_samples = 4;
                coverage_samples = 16;
                break;
            case TEXTURE_ANTI_ALIASING::CSAA_16Q:
                color_samples = 8;
                coverage_samples = 16;
                break;
            case TEXTURE_ANTI_ALIASING::CSAA_32: // TODO: ratio?
            case TEXTURE_ANTI_ALIASING::CSAA_32Q: // TODO: ratio?
            default:
                color_samples = 4;
                coverage_samples = 8;
                break;
            }

            glGenRenderbuffers(1, &buffer->depth_buffer);
            glGenRenderbuffers(1, &buffer->color_buffer);

            glGenFramebuffers(1, &buffer->resolve_buffer[0]);

            glBindFramebuffer(GL_FRAMEBUFFER, buffer->resolve_buffer[0]);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, buffer->tex[0], 0);
            check_fbo(current_buffer);

            glBindFramebuffer(GL_FRAMEBUFFER, buffer->fbo_id);
            glBindRenderbuffer(GL_RENDERBUFFER, buffer->color_buffer);

            glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER, coverage_samples, color_samples, (GLenum)internal_format[0], (GLsizei)buffer->width, (GLsizei)buffer->height);
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, buffer->color_buffer);
            check_fbo(current_buffer);

            glBindRenderbuffer(GL_RENDERBUFFER, buffer->depth_buffer);
            glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER, coverage_samples, color_samples, depth_internel_format, (GLsizei)buffer->width, (GLsizei)buffer->height);
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, depth_attachment_type, GL_RENDERBUFFER, buffer->depth_buffer);
            check_fbo(current_buffer);
        }
        break;
#else
        case TEXTURE_ANTI_ALIASING::CSAA_8:
        case TEXTURE_ANTI_ALIASING::CSAA_8Q:
        case TEXTURE_ANTI_ALIASING::CSAA_16:
        case TEXTURE_ANTI_ALIASING::CSAA_16Q:
        case TEXTURE_ANTI_ALIASING::CSAA_32:
        case TEXTURE_ANTI_ALIASING::CSAA_32Q:
            log_error("CSAA not supported right now");
            break;
#endif
        }
    }

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindRenderbuffer(GL_RENDERBUFFER, 0);

    return buffer;
}