diff --git a/libobs-opengl/gl-helpers.c b/libobs-opengl/gl-helpers.c new file mode 100644 index 000000000..15e19b87d --- /dev/null +++ b/libobs-opengl/gl-helpers.c @@ -0,0 +1,50 @@ +/****************************************************************************** + Copyright (C) 2013 by Hugh Bailey + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +#include "gl-subsystem.h" + +bool upload_face(GLenum type, uint32_t num_levels, + GLenum format, GLint internal_format, bool compressed, + uint32_t width, uint32_t height, uint32_t size, void ***p_data) +{ + bool success = true; + void **data = *p_data; + uint32_t i; + + for (i = 0; i < num_levels; i++) { + if (compressed) { + glCompressedTexImage2D(type, i, internal_format, + width, height, 0, size, *data); + if (!gl_success("glCompressedTexImage2D")) + success = false; + + } else { + glTexImage2D(type, i, internal_format, width, height, 0, + format, GL_UNSIGNED_BYTE, *data); + if (!gl_success("glTexImage2D")) + success = false; + } + + data++; + size /= 4; + width /= 2; + height /= 2; + } + + *p_data = data; + return success; +} diff --git a/libobs-opengl/gl-helpers.h b/libobs-opengl/gl-helpers.h index 23a0fdcce..efbf05884 100644 --- a/libobs-opengl/gl-helpers.h +++ b/libobs-opengl/gl-helpers.h @@ -48,4 +48,20 @@ static inline bool gl_bind_texture(GLenum target, GLuint texture) return gl_success("glBindTexture"); } +static inline bool gl_gen_buffers(GLsizei num_buffers, GLuint *buffers) +{ + glGenBuffers(num_buffers, buffers); + return gl_success("glGenBuffers"); +} + +static inline bool gl_bind_buffer(GLenum target, GLuint buffer) +{ + glBindBuffer(target, buffer); + return gl_success("glBindBuffer"); +} + +extern bool upload_face(GLenum type, uint32_t num_levels, + GLenum format, GLint internal_format, bool compressed, + uint32_t width, uint32_t height, uint32_t size, void ***p_data); + #endif diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c index ae2e6559b..964d1aa9f 100644 --- a/libobs-opengl/gl-subsystem.c +++ b/libobs-opengl/gl-subsystem.c @@ -16,7 +16,6 @@ ******************************************************************************/ #include "gl-subsystem.h" -#include "gl-exports.h" device_t device_create(struct gs_init_data *info) { @@ -81,17 +80,13 @@ uint32_t device_getheight(device_t device) return device->cur_swap->info.cy; } -texture_t device_create_cubetexture(device_t device, uint32_t size, - enum gs_color_format color_format, uint32_t levels, - void **data, uint32_t flags) -{ -} - texture_t device_create_volumetexture(device_t device, uint32_t width, uint32_t height, uint32_t depth, enum gs_color_format color_format, uint32_t levels, void **data, uint32_t flags) { + /* TODO */ + return NULL; } zstencil_t device_create_zstencil(device_t device, uint32_t width, @@ -354,38 +349,6 @@ void swapchain_destroy(swapchain_t swapchain) { } -uint32_t texture_getwidth(texture_t tex) -{ -} - -uint32_t texture_getheight(texture_t tex) -{ -} - -enum gs_color_format texture_getcolorformat(texture_t tex) -{ -} - -bool texture_map(texture_t tex, void **ptr, uint32_t *byte_width) -{ -} - -void texture_unmap(texture_t tex) -{ -} - -void cubetexture_destroy(texture_t cubetex) -{ -} - -uint32_t cubetexture_getsize(texture_t cubetex) -{ -} - -enum gs_color_format cubetexture_getcolorformat(texture_t cubetex) -{ -} - void volumetexture_destroy(texture_t voltex) { } diff --git a/libobs-opengl/gl-subsystem.h b/libobs-opengl/gl-subsystem.h index fb1cddd27..878c17d0a 100644 --- a/libobs-opengl/gl-subsystem.h +++ b/libobs-opengl/gl-subsystem.h @@ -21,6 +21,7 @@ #include "graphics/graphics.h" #include "glew/include/GL/glew.h" #include "gl-helpers.h" +#include "gl-exports.h" struct gl_platform; struct gl_windowinfo; @@ -92,6 +93,9 @@ struct gs_texture { GLint gl_internal_format; GLuint texture; uint32_t levels; + bool is_dynamic; + bool is_render_target; + bool gen_mipmaps; }; struct gs_texture_2d { @@ -100,6 +104,7 @@ struct gs_texture_2d { uint32_t width; uint32_t height; bool gen_mipmaps; + GLuint unpack_buffer; }; struct gs_texture_cube { diff --git a/libobs-opengl/gl-texture2d.c b/libobs-opengl/gl-texture2d.c index adc8b43ab..aee0712cd 100644 --- a/libobs-opengl/gl-texture2d.c +++ b/libobs-opengl/gl-texture2d.c @@ -17,7 +17,7 @@ #include "gl-subsystem.h" -static inline uint32_t num_actual_levels(struct gs_texture_2d *tex) +static uint32_t num_actual_levels(struct gs_texture_2d *tex) { uint32_t num_levels; uint32_t size; @@ -36,41 +36,20 @@ static inline uint32_t num_actual_levels(struct gs_texture_2d *tex) return num_levels; } -static inline bool upload_texture_data(struct gs_texture_2d *tex, void **data) +static bool upload_texture_2d(struct gs_texture_2d *tex, void **data) { uint32_t row_size = tex->width * get_format_bpp(tex->base.format); uint32_t tex_size = tex->height * row_size / 8; uint32_t num_levels = num_actual_levels(tex); - bool success = true; bool compressed = is_compressed_format(tex->base.format); - uint32_t i; + bool success; if (!gl_bind_texture(GL_TEXTURE_2D, tex->base.texture)) return false; - for (i = 0; i < num_levels; i++) { - uint32_t size = tex_size; - - if (compressed) { - glCompressedTexImage2D(GL_TEXTURE_2D, i, - tex->base.gl_internal_format, - tex->width, tex->height, 0, - size, *data); - if (!gl_success("glCompressedTexImage2D")) - success = false; - - } else { - glTexImage2D(GL_TEXTURE_2D, i, - tex->base.gl_internal_format, - tex->width, tex->height, 0, - tex->base.gl_format, GL_UNSIGNED_BYTE, - *data); - if (!gl_success("glTexImage2D")) - success = false; - } - - data++; - } + success = upload_face(GL_TEXTURE_2D, num_levels, + tex->base.gl_format, tex->base.gl_internal_format, + compressed, tex->width, tex->height, tex_size, &data); if (!gl_bind_texture(GL_TEXTURE_2D, 0)) success = false; @@ -78,6 +57,29 @@ static inline bool upload_texture_data(struct gs_texture_2d *tex, void **data) return success; } +static bool create_pixel_unpack_buffer(struct gs_texture_2d *tex) +{ + GLsizeiptr size; + bool success = true; + + if (!gl_gen_buffers(1, &tex->unpack_buffer)) + return false; + + if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex->unpack_buffer)) + return false; + + size = tex->width * tex->height * get_format_bpp(tex->base.format) / 8; + + glBufferData(GL_PIXEL_UNPACK_BUFFER, size, 0, GL_DYNAMIC_DRAW); + if (!gl_success("glBufferData")) + success = false; + + if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0)) + success = false; + + return success; +} + texture_t device_create_texture(device_t device, uint32_t width, uint32_t height, enum gs_color_format color_format, uint32_t levels, void **data, uint32_t flags) @@ -90,12 +92,17 @@ texture_t device_create_texture(device_t device, uint32_t width, tex->base.format = color_format; tex->base.gl_format = convert_gs_format(color_format); tex->base.gl_internal_format = convert_gs_internal_format(color_format); + tex->base.is_dynamic = flags & GS_DYNAMIC; + tex->base.is_render_target = flags & GS_RENDERTARGET; + tex->base.gen_mipmaps = flags & GS_BUILDMIPMAPS; tex->width = width; tex->height = height; if (!gl_gen_textures(1, &tex->base.texture)) goto fail; - if (data && !upload_texture_data(tex, data)) + if (tex->base.is_dynamic && !create_pixel_unpack_buffer(tex)) + goto fail; + if (data && !upload_texture_2d(tex, data)) goto fail; return (texture_t)tex; @@ -114,3 +121,79 @@ void texture_destroy(texture_t tex) glDeleteTextures(1, &tex->texture); bfree(tex); } + +static inline bool is_texture_2d(texture_t tex, const char *func) +{ + bool is_tex2d = tex->type == GS_TEXTURE_2D; + if (!is_tex2d) + blog(LOG_ERROR, "%s (GL) failed: Not a 2D texture", func); + return is_tex2d; +} + +uint32_t texture_getwidth(texture_t tex) +{ + struct gs_texture_2d *tex2d = (struct gs_texture_2d*)tex; + if (!is_texture_2d(tex, "texture_getwidth")) + return 0; + + return tex2d->width; +} + +uint32_t texture_getheight(texture_t tex) +{ + struct gs_texture_2d *tex2d = (struct gs_texture_2d*)tex; + if (!is_texture_2d(tex, "texture_getheight")) + return 0; + + return tex2d->height; +} + +enum gs_color_format texture_getcolorformat(texture_t tex) +{ + return tex->format; +} + +bool texture_map(texture_t tex, void **ptr, uint32_t *byte_width) +{ + struct gs_texture_2d *tex2d = (struct gs_texture_2d*)tex; + + if (!is_texture_2d(tex, "texture_map")) + goto fail; + + if (!tex2d->base.is_dynamic) { + blog(LOG_ERROR, "Texture is not dynamic"); + goto fail; + } + + if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex2d->unpack_buffer)) + goto fail; + + *ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (!*ptr) { + gl_success("glMapBuffer"); + goto fail; + } + + gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0); + + *byte_width = tex2d->width * get_format_bpp(tex->format) / 8; + return true; + +fail: + blog(LOG_ERROR, "texture_map (GL) failed"); + return false; +} + +void texture_unmap(texture_t tex) +{ + struct gs_texture_2d *tex2d = (struct gs_texture_2d*)tex; + if (!is_texture_2d(tex, "texture_unmap")) + return; + + if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex2d->unpack_buffer)) + return; + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + gl_success("glUnmapBuffer"); + + gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0); +} diff --git a/libobs-opengl/gl-texturecube.c b/libobs-opengl/gl-texturecube.c new file mode 100644 index 000000000..25c55a45e --- /dev/null +++ b/libobs-opengl/gl-texturecube.c @@ -0,0 +1,125 @@ +/****************************************************************************** + Copyright (C) 2013 by Hugh Bailey + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +#include "gl-subsystem.h" + +static inline uint32_t num_actual_levels(struct gs_texture_cube *tex) +{ + uint32_t num_levels; + uint32_t size; + + if (tex->base.levels > 0) + return tex->base.levels; + + size = tex->size; + num_levels = 0; + + while (size > 1) { + size /= 2; + num_levels++; + } + + return num_levels; +} + +static inline bool upload_texture_cube(struct gs_texture_cube *tex, void **data) +{ + uint32_t row_size = tex->size * get_format_bpp(tex->base.format); + uint32_t tex_size = tex->size * row_size / 8; + uint32_t num_levels = num_actual_levels(tex); + bool compressed = is_compressed_format(tex->base.format); + bool success = true; + uint32_t i; + + for (i = 0; i < 6; i++) { + GLenum type = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; + + if (!gl_bind_texture(type, tex->base.texture)) + success = false; + + if (!upload_face(type, num_levels, tex->base.gl_format, + tex->base.gl_internal_format, + compressed, tex->size, tex->size, + tex_size, &data)) + success = false; + + if (!gl_bind_texture(type, 0)) + success = false; + + data++; + } + + return success; +} + +texture_t device_create_cubetexture(device_t device, uint32_t size, + enum gs_color_format color_format, uint32_t levels, + void **data, uint32_t flags) +{ + struct gs_texture_cube *tex = bmalloc(sizeof(struct gs_texture_cube)); + memset(tex, 0, sizeof(struct gs_texture_2d)); + + tex->base.device = device; + tex->base.type = GS_TEXTURE_2D; + tex->base.format = color_format; + tex->base.gl_format = convert_gs_format(color_format); + tex->base.gl_internal_format = convert_gs_internal_format(color_format); + tex->size = size; + + if (!gl_gen_textures(1, &tex->base.texture)) + goto fail; + if (data && !upload_texture_cube(tex, data)) + goto fail; + + return (texture_t)tex; + +fail: + texture_destroy((texture_t)tex); + blog(LOG_ERROR, "device_create_texture (GL) failed"); + return NULL; +} + +void cubetexture_destroy(texture_t tex) +{ + if (!tex) + return; + + glDeleteTextures(1, &tex->texture); + bfree(tex); +} + +static inline bool is_texture_cube(texture_t tex, const char *func) +{ + bool is_texcube = tex->type == GS_TEXTURE_CUBE; + if (!is_texcube) + blog(LOG_ERROR, "%s (GL) failed: Not a cubemap texture", func); + return is_texcube; +} + +uint32_t cubetexture_getsize(texture_t cubetex) +{ + struct gs_texture_cube *cube = (struct gs_texture_cube*)cubetex; + if (!is_texture_cube(cubetex, "cubetexture_getsize")) + return 0; + + return cube->size; +} + +enum gs_color_format cubetexture_getcolorformat(texture_t cubetex) +{ + return cubetex->format; +} diff --git a/libobs-opengl/gl-windows.c b/libobs-opengl/gl-windows.c index 6418d9786..f34f41a4c 100644 --- a/libobs-opengl/gl-windows.c +++ b/libobs-opengl/gl-windows.c @@ -341,7 +341,6 @@ struct gl_platform *gl_platform_create(device_t device, if (!gl_dummy_context_init(&dummy)) goto fail; - if (!gl_init_extensions()) goto fail; @@ -359,6 +358,11 @@ struct gl_platform *gl_platform_create(device_t device, if (!plat->hrc) goto fail; + if (GLEW_ARB_seamless_cube_map) { + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + gl_success("GL_TEXTURE_CUBE_MAP_SEAMLESS"); + } + return plat; fail: diff --git a/vs/2010/libobs-opengl/libobs-opengl.vcxproj b/vs/2010/libobs-opengl/libobs-opengl.vcxproj index 5e436fa6f..69dc17576 100644 --- a/vs/2010/libobs-opengl/libobs-opengl.vcxproj +++ b/vs/2010/libobs-opengl/libobs-opengl.vcxproj @@ -160,8 +160,10 @@ + + diff --git a/vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters b/vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters index 8aef33291..6e756ae24 100644 --- a/vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters +++ b/vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters @@ -35,5 +35,11 @@ Source Files + + Source Files + + + Source Files + \ No newline at end of file