Browse Source

Implement FBO blit texture copy

This trick uses FBOs to allow for copying textures without the need for
special texture copy functions.
jp9000 11 years ago
parent
commit
6ffcd5e74e

+ 51 - 2
libobs-opengl/gl-helpers.c

@@ -56,10 +56,55 @@ 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,
+		GLuint src, GLenum src_target,
+		uint32_t width, uint32_t height,
+		enum gs_color_format format)
+{
+	struct fbo_info *fbo = get_fbo(device, width, height, format);
+	GLint last_fbo;
+	bool success = false;
+
+	if (!fbo)
+		return false;
+
+	if (!gl_get_integer_v(GL_READ_FRAMEBUFFER_BINDING, &last_fbo))
+		return false;
+	if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, fbo->fbo))
+		return false;
+	if (!gl_bind_texture(dst_target, dst))
+		goto fail;
+
+	glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 0,
+			src_target, src, 0);
+	if (!gl_success("glFrameBufferTexture2D"))
+		goto fail;
+
+	glReadBuffer(GL_COLOR_ATTACHMENT0 + 0);
+	if (!gl_success("glReadBuffer"))
+		goto fail;
+
+	glCopyTexSubImage2D(dst_target, 0, 0, 0, 0, 0, width, height);
+	if (!gl_success("glCopyTexSubImage2D"))
+		goto fail;
+
+	success = true;
+
+fail:
+	if (!gl_bind_texture(dst_target, 0))
+		success = false;
+	if (!gl_bind_framebuffer(GL_READ_FRAMEBUFFER, last_fbo))
+		success = false;
+
+	return success;
+}
+
 bool gl_copy_texture(struct gs_device *device,
                      GLuint dst, GLenum dst_target,
                      GLuint src, GLenum src_target,
-                     uint32_t width, uint32_t height)
+                     uint32_t width, uint32_t height,
+                     enum gs_color_format format)
 {
 	bool success = false;
 
@@ -76,7 +121,11 @@ bool gl_copy_texture(struct gs_device *device,
 		success = gl_success("glCopyImageSubDataNV");
 
 	} else if (device->copy_type == COPY_TYPE_FBO_BLIT) {
-		/* TODO (implement FBOs) */
+		if (gl_copy_fbo(device, dst, dst_target, src,  src_target,
+					width, height, format))
+			success = true;
+		else
+			blog(LOG_ERROR, "gl_copy_texture failed");
 	}
 
 	return success;

+ 8 - 1
libobs-opengl/gl-helpers.h

@@ -137,6 +137,12 @@ static inline bool gl_cull_face(GLenum faces)
 	return gl_success("glCullFace");
 }
 
+static inline bool gl_get_integer_v(GLenum pname, GLint *params)
+{
+	glGetIntegerv(pname, params);
+	return gl_success("glGetIntegerv");
+}
+
 extern bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
 		GLenum format, GLint internal_format, bool compressed,
 		uint32_t width, uint32_t height, uint32_t size,
@@ -145,7 +151,8 @@ extern bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
 extern bool gl_copy_texture(struct gs_device *device,
                             GLuint dst, GLenum dst_target,
                             GLuint src, GLenum src_target,
-                            uint32_t width, uint32_t height);
+                            uint32_t width, uint32_t height,
+			    enum gs_color_format format);
 
 extern bool gl_create_buffer(GLenum target, GLuint *buffer, GLsizeiptr size,
 		const GLvoid *data, GLenum usage);

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

@@ -141,7 +141,7 @@ void device_stage_texture(device_t device, stagesurf_t dst, texture_t src)
 
 	if (!gl_copy_texture(device, dst->texture, GL_TEXTURE_2D,
 				tex2d->base.texture, GL_TEXTURE_2D,
-				dst->width, dst->height))
+				dst->width, dst->height, dst->format))
 		goto failed;
 
 	if (!gl_bind_texture(GL_TEXTURE_2D, dst->texture))

+ 17 - 10
libobs-opengl/gl-subsystem.c

@@ -120,7 +120,7 @@ static bool gl_init_extensions(struct gs_device* device)
 	else if (ogl_ext_NV_copy_image)
 		device->copy_type = COPY_TYPE_NV;
 	else
-		device->copy_type = COPY_TYPE_FBO_BLIT; /* ?? */
+		device->copy_type = COPY_TYPE_FBO_BLIT;
 
 	return true;
 }
@@ -577,21 +577,18 @@ static bool get_tex_dimensions(texture_t tex, uint32_t *width, uint32_t *height)
  * This automatically manages FBOs so that render targets are always given
  * an FBO that matches their width/height/format to maximize optimization
  */
-static struct fbo_info *get_fbo(struct gs_device *device, texture_t tex)
+struct fbo_info *get_fbo(struct gs_device *device,
+		uint32_t width, uint32_t height, enum gs_color_format format)
 {
 	size_t i;
-	uint32_t width, height;
 	GLuint fbo;
 	struct fbo_info *ptr;
 
-	if (!get_tex_dimensions(tex, &width, &height))
-		return NULL;
-
 	for (i = 0; i < device->fbos.num; i++) {
 		ptr = device->fbos.array[i];
 
 		if (ptr->width  == width && ptr->height == height &&
-		    ptr->format == tex->format)
+		    ptr->format == format)
 			return ptr;
 	}
 
@@ -603,7 +600,7 @@ static struct fbo_info *get_fbo(struct gs_device *device, texture_t tex)
 	ptr->fbo                 = fbo;
 	ptr->width               = width;
 	ptr->height              = height;
-	ptr->format              = tex->format;
+	ptr->format              = format;
 	ptr->cur_render_target   = NULL;
 	ptr->cur_render_side     = 0;
 	ptr->cur_zstencil_buffer = NULL;
@@ -612,6 +609,16 @@ static struct fbo_info *get_fbo(struct gs_device *device, texture_t tex)
 	return ptr;
 }
 
+static inline struct fbo_info *get_fbo_by_tex(struct gs_device *device,
+		texture_t tex)
+{
+	uint32_t width, height;
+	if (!get_tex_dimensions(tex, &width, &height))
+		return NULL;
+
+	return get_fbo(device, width, height, tex->format);
+}
+
 static bool set_current_fbo(device_t device, struct fbo_info *fbo)
 {
 	if (device->cur_fbo != fbo) {
@@ -688,7 +695,7 @@ static bool set_target(device_t device, texture_t tex, int side, zstencil_t zs)
 	if (!tex)
 		return set_current_fbo(device, NULL);
 
-	fbo = get_fbo(device, tex);
+	fbo = get_fbo_by_tex(device, tex);
 	if (!fbo)
 		return false;
 
@@ -783,7 +790,7 @@ void device_copy_texture(device_t device, texture_t dst, texture_t src)
 
 	if (!gl_copy_texture(device, dst->texture, dst->gl_target,
 				src->texture, src->gl_target,
-				src2d->width, src2d->height))
+				src2d->width, src2d->height, src->format))
 		goto fail;
 
 	return;

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

@@ -479,6 +479,9 @@ struct gs_device {
 	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 void                  gl_update(device_t device);
 
 extern struct gl_platform   *gl_platform_create(device_t device,