ext/say_image_target.c in ray-0.1.1 vs ext/say_image_target.c in ray-0.2.0

- old
+ new

@@ -1,11 +1,51 @@ #include "say.h" +typedef struct { + GLuint id; + say_image *img; + say_context *ctxt; +} say_fbo; + static say_context *say_image_target_make_context(void *data) { return say_context_create(); } +static void say_fbo_delete_current(void *data) { + say_fbo *fbo = (say_fbo*)data; + + if (fbo->ctxt == say_context_current() && fbo->id) { + glDeleteFramebuffers(1, &fbo->id); + } +} + +void say_fbo_make_current(GLuint fbo); +void say_rbo_make_current(GLuint rbo); + +static void say_fbo_build(say_image_target *target, say_fbo *fbo) { + if (!fbo->id) + glGenFramebuffers(1, &fbo->id); + + say_fbo_make_current(fbo->id); + + say_image_bind(target->img); + glGenerateMipmap(GL_TEXTURE_2D); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, target->img->texture, 0); + + say_rbo_make_current(target->rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, + say_image_get_width(target->img), + say_image_get_height(target->img)); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, target->rbo); + + fbo->img = target->img; +} + static GLuint say_current_fbo = 0; static say_context *say_fbo_last_context = NULL; void say_fbo_make_current(GLuint fbo) { say_context *context = say_context_current(); @@ -13,11 +53,11 @@ if (context != say_fbo_last_context || fbo != say_current_fbo) { say_current_fbo = fbo; say_fbo_last_context = context; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); } } static GLuint say_current_rbo = 0; static say_context *say_rbo_last_context = NULL; @@ -28,46 +68,56 @@ if (context != say_rbo_last_context || rbo != say_current_rbo) { say_current_rbo = rbo; say_rbo_last_context = context; - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); } } -void say_image_target_will_delete(GLuint fbo, GLuint rbo) { - if (say_current_fbo == fbo) - say_current_fbo = 0; +void say_image_target_will_delete(mo_hash *fbos, GLuint rbo) { + mo_hash_it it = mo_hash_begin(fbos); + for (; !mo_hash_it_is_end(&it); mo_hash_it_next(&it)) { + say_fbo *fbo = mo_hash_it_val_ptr(&it, say_fbo); + if (fbo->id == say_current_fbo) { + say_current_fbo = 0; + break; + } + } if (say_current_rbo == rbo) say_current_rbo = 0; } bool say_image_target_is_available() { say_context_ensure(); - return __GLEW_EXT_framebuffer_object != 0; + return GLEW_EXT_framebuffer_object || GLEW_VERSION_3_0; } say_image_target *say_image_target_create() { say_context_ensure(); say_image_target *target = malloc(sizeof(say_image_target)); target->target = say_target_create(); target->img = NULL; - glGenFramebuffersEXT(1, &(target->fbo)); - glGenRenderbuffersEXT(1, &(target->rbo)); + target->fbos = mo_hash_create(sizeof(say_context*), sizeof(say_fbo)); + target->fbos->release = say_fbo_delete_current; + target->fbos->hash_of = mo_hash_of_pointer; + target->fbos->key_cmp = mo_hash_pointer_cmp; + glGenRenderbuffers(1, &target->rbo); + return target; } void say_image_target_free(say_image_target *target) { say_context_ensure(); - say_image_target_will_delete(target->fbo, target->rbo); + say_image_target_will_delete(target->fbos, target->rbo); - glDeleteRenderbuffersEXT(1, &(target->rbo)); - glDeleteFramebuffersEXT(1, &(target->fbo)); + glDeleteRenderbuffers(1, &target->rbo); + mo_hash_free(target->fbos); say_target_free(target->target); free(target); } @@ -75,57 +125,61 @@ say_context_ensure(); target->img = image; if (target->img) { say_target_set_custom_data(target->target, target); - //say_target_need_own_contxt(target->target, 0); say_target_set_context_proc(target->target, say_image_target_make_context); say_target_set_bind_hook(target->target, (say_bind_hook)say_image_target_bind); say_vector2 size = say_image_get_size(image); say_target_set_size(target->target, size); say_view_set_size(target->target->view, size); say_view_set_center(target->target->view, say_make_vector2(size.x / 2.0, size.y / 2.0)); - say_view_flip_y(target->target->view, 0); - say_fbo_make_current(target->fbo); - - say_image_bind(image); - glGenerateMipmapEXT(GL_TEXTURE_2D); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, image->texture, 0); - - say_rbo_make_current(target->rbo); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, - say_image_get_width(image), - say_image_get_height(image)); - - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, target->rbo); - + say_target_make_current(target->target); } } say_image *say_image_target_get_image(say_image_target *target) { return target->img; } void say_image_target_update(say_image_target *target) { if (target->img) { say_target_update(target->target); - - say_image_bind(target->img); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, - say_image_get_buffer(target->img)); + say_image_mark_out_of_date(target->img); } } void say_image_target_bind(say_image_target *target) { say_context_ensure(); - say_fbo_make_current(target->fbo); + + /* + * As FBOs aren't shared, we need to fetch the FBO for the current context. If + * we don't find one, we need to build it. + */ + say_context *ctxt = say_context_current(); + + if (!mo_hash_has_key(target->fbos, &ctxt)) { + say_fbo tmp = {0, NULL, NULL}; + mo_hash_set(target->fbos, &ctxt, &tmp); + + say_fbo_build(target, mo_hash_get(target->fbos, &ctxt)); + } + else { + say_fbo *fbo = mo_hash_get(target->fbos, &ctxt); + + if (fbo->img != target->img && target->img) + say_fbo_build(target, fbo); + else + say_fbo_make_current(fbo->id); + } + + /* + * Needed to avoid having garbage data there. + */ glClear(GL_DEPTH_BUFFER_BIT); } void say_image_target_unbind() { if (say_image_target_is_available())