libobs-opengl: Store FBOs per texture instead of per device

The previous model stored a new FBO per texture width/height/format on
a array in the device struct. This allocated memory was only released
on gs_device_destroy (obs exit).

The new approach stores a FBO on gs_texture and the its info is
destroyed once the texture is deleted.
master
Shaolin 2018-08-31 18:07:00 -03:00
parent 11b84a5d85
commit acd44b525e
7 changed files with 58 additions and 72 deletions

View File

@ -57,13 +57,11 @@ bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
return success;
}
static bool gl_copy_fbo(struct gs_device *device,
GLuint dst, GLenum dst_target, uint32_t dst_x, uint32_t dst_y,
GLuint src, GLenum src_target, uint32_t src_x, uint32_t src_y,
uint32_t width, uint32_t height,
enum gs_color_format format)
static bool gl_copy_fbo(struct gs_texture *dst, uint32_t dst_x, uint32_t dst_y,
struct gs_texture *src, uint32_t src_x, uint32_t src_y,
uint32_t width, uint32_t height)
{
struct fbo_info *fbo = get_fbo(device, width, height, format);
struct fbo_info *fbo = get_fbo(src, width, height);
GLint last_fbo;
bool success = false;
@ -74,11 +72,11 @@ static bool gl_copy_fbo(struct gs_device *device,
return false;
if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, fbo->fbo))
return false;
if (!gl_bind_texture(dst_target, dst))
if (!gl_bind_texture(dst->gl_target, dst->texture))
goto fail;
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0,
src_target, src, 0);
src->gl_target, src->texture, 0);
if (!gl_success("glFrameBufferTexture2D"))
goto fail;
@ -86,7 +84,7 @@ static bool gl_copy_fbo(struct gs_device *device,
if (!gl_success("glReadBuffer"))
goto fail;
glCopyTexSubImage2D(dst_target, 0, dst_x, dst_y, src_x, src_y,
glCopyTexSubImage2D(dst->gl_target, 0, dst_x, dst_y, src_x, src_y,
width, height);
if (!gl_success("glCopyTexSubImage2D"))
goto fail;
@ -94,7 +92,7 @@ static bool gl_copy_fbo(struct gs_device *device,
success = true;
fail:
if (!gl_bind_texture(dst_target, 0))
if (!gl_bind_texture(dst->gl_target, 0))
success = false;
if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, last_fbo))
success = false;
@ -102,29 +100,28 @@ fail:
return success;
}
bool gl_copy_texture(struct gs_device *device,
GLuint dst, GLenum dst_target, uint32_t dst_x, uint32_t dst_y,
GLuint src, GLenum src_target, uint32_t src_x, uint32_t src_y,
uint32_t width, uint32_t height, enum gs_color_format format)
bool gl_copy_texture(struct gs_device *device, struct gs_texture *dst,
uint32_t dst_x, uint32_t dst_y, struct gs_texture *src,
uint32_t src_x, uint32_t src_y, uint32_t width,
uint32_t height)
{
bool success = false;
if (device->copy_type == COPY_TYPE_ARB) {
glCopyImageSubData(src, src_target, 0, src_x, src_y, 0,
dst, dst_target, 0, dst_x, dst_y, 0,
width, height, 1);
glCopyImageSubData(src->texture, src->gl_target, 0, src_x,
src_y, 0, dst->texture, dst->gl_target, 0,
dst_x, dst_y, 0, width, height, 1);
success = gl_success("glCopyImageSubData");
} else if (device->copy_type == COPY_TYPE_NV) {
glCopyImageSubDataNV(src, src_target, 0, src_x, src_y, 0,
dst, dst_target, 0, dst_x, dst_y, 0,
width, height, 1);
glCopyImageSubDataNV(src->texture, src->gl_target, 0, src_x,
src_y, 0, dst->texture, dst->gl_target, 0,
dst_x, dst_y, 0, width, height, 1);
success = gl_success("glCopyImageSubDataNV");
} else if (device->copy_type == COPY_TYPE_FBO_BLIT) {
success = gl_copy_fbo(device, dst, dst_target, dst_x, dst_y,
src, src_target, src_x, src_y,
width, height, format);
success = gl_copy_fbo(dst, dst_x, dst_y, src, src_x, src_y,
width, height);
if (!success)
blog(LOG_ERROR, "gl_copy_texture failed");
}

View File

@ -148,11 +148,10 @@ extern bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
uint32_t width, uint32_t height, uint32_t size,
const uint8_t ***p_data);
extern bool gl_copy_texture(struct gs_device *device,
GLuint dst, GLenum dst_target, uint32_t dst_x, uint32_t dst_y,
GLuint src, GLenum src_target, uint32_t src_x, uint32_t src_y,
uint32_t width, uint32_t height,
enum gs_color_format format);
extern bool gl_copy_texture(struct gs_device *device, struct gs_texture *dst,
uint32_t dst_x, uint32_t dst_y, struct gs_texture *src,
uint32_t src_x, uint32_t src_y, uint32_t width,
uint32_t height);
extern bool gl_create_buffer(GLenum target, GLuint *buffer, GLsizeiptr size,
const GLvoid *data, GLenum usage);

View File

@ -124,7 +124,7 @@ void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst,
if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, dst->pack_buffer))
goto failed;
fbo = get_fbo(device, dst->width, dst->height, dst->format);
fbo = get_fbo(src, dst->width, dst->height);
if (!gl_get_integer_v(GL_READ_FRAMEBUFFER_BINDING, &last_fbo))
goto failed_unbind_buffer;
@ -152,6 +152,8 @@ failed_unbind_buffer:
failed:
if (!success)
blog(LOG_ERROR, "device_stage_texture (GL) failed");
UNUSED_PARAMETER(device);
}
#else

View File

@ -259,16 +259,10 @@ fail:
void device_destroy(gs_device_t *device)
{
if (device) {
size_t i;
for (i = 0; i < device->fbos.num; i++)
fbo_info_destroy(device->fbos.array[i]);
while (device->first_program)
gs_program_destroy(device->first_program);
da_free(device->proj_stack);
da_free(device->fbos);
gl_platform_destroy(device->plat);
bfree(device);
}
@ -658,46 +652,37 @@ static bool get_tex_dimensions(gs_texture_t *tex, uint32_t *width,
* This automatically manages FBOs so that render targets are always given
* an FBO that matches their width/height/format to maximize optimization
*/
struct fbo_info *get_fbo(struct gs_device *device,
uint32_t width, uint32_t height, enum gs_color_format format)
struct fbo_info *get_fbo(gs_texture_t *tex, uint32_t width, uint32_t height)
{
size_t i;
if (tex->fbo && tex->fbo->width == width &&
tex->fbo->height == height &&
tex->fbo->format == tex->format)
return tex->fbo;
GLuint fbo;
struct fbo_info *ptr;
for (i = 0; i < device->fbos.num; i++) {
ptr = device->fbos.array[i];
if (ptr->width == width && ptr->height == height &&
ptr->format == format)
return ptr;
}
glGenFramebuffers(1, &fbo);
if (!gl_success("glGenFramebuffers"))
return NULL;
ptr = bmalloc(sizeof(struct fbo_info));
ptr->fbo = fbo;
ptr->width = width;
ptr->height = height;
ptr->format = format;
ptr->cur_render_target = NULL;
ptr->cur_render_side = 0;
ptr->cur_zstencil_buffer = NULL;
tex->fbo = bmalloc(sizeof(struct fbo_info));
tex->fbo->fbo = fbo;
tex->fbo->width = width;
tex->fbo->height = height;
tex->fbo->format = tex->format;
tex->fbo->cur_render_target = NULL;
tex->fbo->cur_render_side = 0;
tex->fbo->cur_zstencil_buffer = NULL;
da_push_back(device->fbos, &ptr);
return ptr;
return tex->fbo;
}
static inline struct fbo_info *get_fbo_by_tex(struct gs_device *device,
gs_texture_t *tex)
static inline struct fbo_info *get_fbo_by_tex(gs_texture_t *tex)
{
uint32_t width, height;
if (!get_tex_dimensions(tex, &width, &height))
return NULL;
return get_fbo(device, width, height, tex->format);
return get_fbo(tex, width, height);
}
static bool set_current_fbo(gs_device_t *device, struct fbo_info *fbo)
@ -783,7 +768,7 @@ static bool set_target(gs_device_t *device, gs_texture_t *tex, int side,
if (!tex)
return set_current_fbo(device, NULL);
fbo = get_fbo_by_tex(device, tex);
fbo = get_fbo_by_tex(tex);
if (!fbo)
return false;
@ -885,9 +870,8 @@ void device_copy_texture_region(gs_device_t *device,
goto fail;
}
if (!gl_copy_texture(device, dst->texture, dst->gl_target, dst_x, dst_y,
src->texture, src->gl_target, src_x, src_y,
nw, nh, src->format))
if (!gl_copy_texture(device, dst, dst_x, dst_y, src, src_x, src_y, nw,
nh))
goto fail;
return;

View File

@ -409,6 +409,7 @@ struct gs_texture {
bool gen_mipmaps;
gs_samplerstate_t *cur_sampler;
struct fbo_info *fbo;
};
struct gs_texture_2d {
@ -501,12 +502,11 @@ struct gs_device {
DARRAY(struct matrix4) proj_stack;
DARRAY(struct fbo_info*) fbos;
struct fbo_info *cur_fbo;
};
extern struct fbo_info *get_fbo(struct gs_device *device,
uint32_t width, uint32_t height, enum gs_color_format format);
extern struct fbo_info *get_fbo(gs_texture_t *tex, uint32_t width,
uint32_t height);
extern void gl_update(gs_device_t *device);

View File

@ -138,6 +138,9 @@ void gs_texture_destroy(gs_texture_t *tex)
if (tex->texture)
gl_delete_textures(1, &tex->texture);
if (tex->fbo)
fbo_info_destroy(tex->fbo);
bfree(tex);
}

View File

@ -92,10 +92,11 @@ void gs_cubetexture_destroy(gs_texture_t *tex)
if (!tex)
return;
if (tex->texture) {
glDeleteTextures(1, &tex->texture);
gl_success("glDeleteTextures");
}
if (tex->texture)
gl_delete_textures(1, &tex->texture);
if (tex->fbo)
fbo_info_destroy(tex->fbo);
bfree(tex);
}