mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-14 23:34:08 +00:00
Implement FBO blit texture copy
This trick uses FBOs to allow for copying textures without the need for special texture copy functions.
This commit is contained in:
parent
9879eead83
commit
6ffcd5e74e
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue