Implement FBO blit texture copy

This trick uses FBOs to allow for copying textures without the need for
special texture copy functions.
master
jp9000 2014-02-09 11:37:22 -07:00
parent 9879eead83
commit 6ffcd5e74e
5 changed files with 80 additions and 14 deletions

View File

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

View File

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

View File

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

View File

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

View File

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