Add multisampled FBO support

This commit is contained in:
mid 2025-05-10 18:19:38 +03:00
parent f20d32eb3a
commit f84505f36b
3 changed files with 81 additions and 30 deletions

103
src/k3.c
View File

@ -2744,46 +2744,81 @@ struct k3ARBFP *k3ProgramARBFP(const char *src) {
return (struct k3ARBFP*) (uintptr_t) p;
}
struct k3Offscreen *k3OffscreenCreate(struct k3Tex *diffuse, struct k3Tex *depth) {
struct k3Offscreen *k3OffscreenCreateMultisampled(struct k3Tex *diffuse, struct k3Tex *depth, uint8_t samples) {
k3Log(k3_INFO, "Init %sFBO", !diffuse && depth ? "depth-only " : "");
GLuint fbo = 0;
if(GLAD_GL_EXT_framebuffer_object) {
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
if(diffuse) {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, GL_FROM_K3TEX(diffuse), 0);
} else {
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
if(depth) {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, GL_FROM_K3TEX(depth), 0);
}
if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
k3Log(k3_WARN, "Framebuffer incomplete");
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK); // XXX: this should not be necessary
} else {
if(samples && (!GLAD_GL_EXT_framebuffer_multisample || !GLAD_GL_EXT_framebuffer_blit)) {
samples = 0;
k3Log(k3_WARN, "Multisampled offscreens not supported.");
}
if(!GLAD_GL_EXT_framebuffer_object) {
k3Log(k3_ERR, "Non-FBO offscreens not implemented");
return NULL;
}
struct k3Offscreen *ret = malloc(sizeof(*ret));
GLuint fbo = 0;
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
struct k3Offscreen *ret = calloc(1, sizeof(*ret));
ret->fbo = fbo;
ret->diffuse = diffuse;
ret->depth = depth;
ret->multisampling.samples = samples;
if(diffuse) {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, GL_FROM_K3TEX(diffuse), 0);
} else {
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
if(depth) {
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, GL_FROM_K3TEX(depth), 0);
}
if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
k3Log(k3_WARN, "Framebuffer incomplete");
}
if(samples) {
GLuint msfbo;
glGenFramebuffersEXT(1, &msfbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, msfbo);
ret->multisampling.fbo = msfbo;
if(diffuse) {
glGenRenderbuffersEXT(1, &ret->multisampling.rboDiffuse);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, ret->multisampling.rboDiffuse);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, diffuse->glInternalFormat, diffuse->szX, diffuse->szY);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, ret->multisampling.rboDiffuse);
}
if(depth) {
glGenRenderbuffersEXT(1, &ret->multisampling.rboDepth);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, ret->multisampling.rboDepth);
glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, depth->glInternalFormat, depth->szX, depth->szY);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, ret->multisampling.rboDepth);
}
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK); // XXX: this should not be necessary
return ret;
}
struct k3Offscreen *k3OffscreenCreate(struct k3Tex *diffuse, struct k3Tex *depth) {
return k3OffscreenCreateMultisampled(diffuse, depth, 0);
}
void k3BeginOffscreen(struct k3Offscreen *offscr) {
if(GLAD_GL_EXT_framebuffer_object) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, offscr->fbo);
GLuint fbo = offscr->multisampling.samples > 0 ? offscr->multisampling.fbo : offscr->fbo;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
struct k3Tex *t = offscr->diffuse ? offscr->diffuse : offscr->depth;
glViewport(0, 0, k3TexSzX(t), k3TexSzY(t));
@ -2794,6 +2829,12 @@ void k3BeginOffscreen(struct k3Offscreen *offscr) {
void k3EndOffscreen(struct k3Offscreen *offscr) {
if(GLAD_GL_EXT_framebuffer_object) {
if(offscr->multisampling.samples) {
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, offscr->fbo);
glBlitFramebufferEXT(0, 0, offscr->diffuse->szX, offscr->diffuse->szY, 0, 0, offscr->diffuse->szX, offscr->diffuse->szY, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glViewport(0, 0, MainWidth, MainHeight);
} else {
@ -2809,7 +2850,9 @@ void k3BlitToScreenEffect(struct k3Offscreen *offscr, int additive, int effect,
if(GLAD_GL_EXT_framebuffer_object) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, GL_FROM_K3TEX(offscr->diffuse));
struct k3Tex *tex = offscr->diffuse ? offscr->diffuse : offscr->depth;
glBindTexture(GL_TEXTURE_2D, GL_FROM_K3TEX(tex));
if(additive) {
glEnable(GL_BLEND);
@ -2856,7 +2899,7 @@ void k3BlitToScreenEffect(struct k3Offscreen *offscr, int additive, int effect,
}
GLint uSz = glGetUniformLocation(GL_FROM_K3GLSL(basicBlitProgram), "u_sz");
glUniform2f(uSz, k3TexSzX(offscr->diffuse), k3TexSzY(offscr->diffuse));
glUniform2f(uSz, k3TexSzX(tex), k3TexSzY(tex));
glDrawArrays(GL_TRIANGLES, 0, 3);
} else {
@ -2864,8 +2907,8 @@ void k3BlitToScreenEffect(struct k3Offscreen *offscr, int additive, int effect,
glUseProgramObjectARB(effect == k3_GLSL ? GL_FROM_K3GLSL(program) : 0);
}
float bleedW = 1.0f / k3TexSzX(offscr->diffuse);
float bleedH = 1.0f / k3TexSzY(offscr->diffuse);
float bleedW = 1.0f / k3TexSzX(tex);
float bleedH = 1.0f / k3TexSzY(tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

View File

@ -190,6 +190,7 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull);
void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr);
struct k3Offscreen;
struct k3Offscreen *k3OffscreenCreateMultisampled(struct k3Tex *diffuse, struct k3Tex *depth, uint8_t samples);
struct k3Offscreen *k3OffscreenCreate(struct k3Tex *diffuse, struct k3Tex *depth);
void k3BeginOffscreen(struct k3Offscreen*);
void k3EndOffscreen(struct k3Offscreen*);

View File

@ -45,6 +45,13 @@ struct k3Offscreen {
GLuint fbo;
struct k3Tex *diffuse;
struct k3Tex *depth;
struct {
uint8_t samples;
GLuint fbo;
GLuint rboDiffuse;
GLuint rboDepth;
} multisampling;
};
struct k3Mdl {