Browse Source

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.
Shaolin 7 years ago
parent
commit
acd44b525e

+ 20 - 23
libobs-opengl/gl-helpers.c

@@ -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");
 	}

+ 4 - 5
libobs-opengl/gl-helpers.h

@@ -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);

+ 3 - 1
libobs-opengl/gl-stagesurf.c

@@ -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

+ 20 - 36
libobs-opengl/gl-subsystem.c

@@ -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;
-	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;
-	}
+	if (tex->fbo && tex->fbo->width  == width &&
+			tex->fbo->height == height &&
+			tex->fbo->format == tex->format)
+		return tex->fbo;
 
+	GLuint fbo;
 	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;

+ 3 - 3
libobs-opengl/gl-subsystem.h

@@ -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);
 

+ 3 - 0
libobs-opengl/gl-texture2d.c

@@ -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);
 }
 

+ 5 - 4
libobs-opengl/gl-texturecube.c

@@ -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);
 }