add stage surfaces and texture copying

master
jp9000 2013-10-10 17:39:56 -07:00
parent c1939de49b
commit 85e2fc6b07
11 changed files with 285 additions and 57 deletions

View File

@ -17,7 +17,7 @@
#include "gl-subsystem.h"
bool upload_face(GLenum type, uint32_t num_levels,
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, void ***p_data)
{
@ -27,18 +27,20 @@ bool upload_face(GLenum type, uint32_t num_levels,
for (i = 0; i < num_levels; i++) {
if (compressed) {
glCompressedTexImage2D(type, i, internal_format,
width, height, 0, size, *data);
glCompressedTexImage2D(target, i, internal_format,
width, height, 0, size,
data ? *data : NULL);
if (!gl_success("glCompressedTexImage2D"))
success = false;
} else {
glTexImage2D(type, i, internal_format, width, height, 0,
format, GL_UNSIGNED_BYTE, *data);
glTexImage2D(target, i, internal_format, width, height,
0, format, type, data ? *data : NULL);
if (!gl_success("glTexImage2D"))
success = false;
}
if (data)
data++;
size /= 4;
width /= 2;
@ -51,3 +53,29 @@ bool upload_face(GLenum type, uint32_t num_levels,
*p_data = data;
return success;
}
bool gl_copy_texture(struct gs_device *device,
GLuint src, GLenum src_target,
GLuint dst, GLenum dst_target,
uint32_t width, uint32_t height)
{
bool success = false;
if (device->copy_type == COPY_TYPE_ARB) {
glCopyImageSubData(src, src_target, 0, 0, 0, 0,
dst, dst_target, 0, 0, 0, 0,
width, height, 1);
success = gl_success("glCopyImageSubData");
} else if (device->copy_type == COPY_TYPE_NV) {
glCopyImageSubDataNV(src, src_target, 0, 0, 0, 0,
dst, dst_target, 0, 0, 0, 0,
width, height, 1);
success = gl_success("glCopyImageSubDataNV");
} else if (device->copy_type == COPY_TYPE_FBO_BLIT) {
/* TODO (implement FBOs) */
}
return success;
}

View File

@ -66,8 +66,13 @@ static inline bool gl_bind_renderbuffer(GLenum target, GLuint buffer)
return gl_success("glBindRendebuffer");
}
extern bool upload_face(GLenum type, uint32_t num_levels,
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, void ***p_data);
extern bool gl_copy_texture(struct gs_device *device,
GLuint src, GLenum src_target,
GLuint dst, GLenum dst_target,
uint32_t width, uint32_t height);
#endif

View File

@ -0,0 +1,174 @@
/******************************************************************************
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
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 <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "gl-subsystem.h"
static bool create_pixel_pack_buffer(struct gs_stage_surface *surf)
{
GLsizeiptr size;
bool success = true;
if (!gl_gen_buffers(1, &surf->pack_buffer))
return false;
if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, surf->pack_buffer))
return false;
size = surf->width * surf->height * surf->bytes_per_pixel;
glBufferData(GL_PIXEL_PACK_BUFFER, size, 0, GL_DYNAMIC_READ);
if (!gl_success("glBufferData"))
success = false;
if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0))
success = false;
return success;
}
static bool gl_init_stage_surface(struct gs_stage_surface *surf)
{
GLenum gl_type = get_gl_format_type(surf->format);
bool success = true;
if (!gl_gen_textures(1, &surf->texture))
return false;
if (!gl_bind_texture(GL_TEXTURE_2D, surf->texture))
return false;
if (!gl_init_face(GL_TEXTURE_2D, gl_type, 1, surf->gl_format,
surf->gl_internal_format, false,
surf->width, surf->height, 0, NULL))
success = false;
if (!gl_bind_texture(GL_TEXTURE_2D, 0))
success = false;
if (success)
success = create_pixel_pack_buffer(surf);
return success;
}
stagesurf_t device_create_stagesurface(device_t device, uint32_t width,
uint32_t height, enum gs_color_format color_format)
{
struct gs_stage_surface *surf;
surf = bmalloc(sizeof(struct gs_stage_surface));
memset(surf, 0, sizeof(struct gs_stage_surface));
surf->format = color_format;
surf->width = width;
surf->height = height;
surf->gl_format = convert_gs_format(color_format);
surf->gl_internal_format = convert_gs_internal_format(color_format);
surf->bytes_per_pixel = gs_get_format_bpp(color_format)/8;
if (!gl_init_stage_surface(surf)) {
blog(LOG_ERROR, "device_create_stagesurface (GL) failed");
stagesurface_destroy(surf);
return NULL;
}
return surf;
}
void stagesurface_destroy(stagesurf_t stagesurf)
{
if (stagesurf) {
if (stagesurf->pack_buffer) {
glDeleteBuffers(1, &stagesurf->pack_buffer);
gl_success("glDeleteBuffers");
}
if (stagesurf->texture) {
glDeleteTextures(1, &stagesurf->texture);
gl_success("glDeleteTextures");
}
bfree(stagesurf);
}
}
void device_stage_texture(device_t device, stagesurf_t dst, texture_t src)
{
struct gs_texture_2d *tex2d = (struct gs_texture_2d*)src;
if (src->type != GS_TEXTURE_2D) {
blog(LOG_ERROR, "Source texture must be a 2D texture");
goto failed;
}
if (tex2d->width != dst->width || tex2d->height != dst->height) {
blog(LOG_ERROR, "Source and destination do not match in size");
goto failed;
}
if (!gl_copy_texture(device, tex2d->base.texture, GL_TEXTURE_2D,
dst->texture, GL_TEXTURE_2D,
dst->width, dst->height))
goto failed;
return;
failed:
blog(LOG_ERROR, "device_stage_texture (GL) failed");
}
uint32_t stagesurface_getwidth(stagesurf_t stagesurf)
{
return stagesurf->width;
}
uint32_t stagesurface_getheight(stagesurf_t stagesurf)
{
return stagesurf->height;
}
enum gs_color_format stagesurface_getcolorformat(stagesurf_t stagesurf)
{
return stagesurf->format;
}
bool stagesurface_map(stagesurf_t stagesurf, const void **data,
uint32_t *byte_width)
{
if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, stagesurf->pack_buffer))
goto fail;
*data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
if (!gl_success("glMapBuffer"))
goto fail;
gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
*byte_width = stagesurf->bytes_per_pixel * stagesurf->width;
return true;
fail:
blog(LOG_ERROR, "stagesurf_map (GL) failed");
return false;
}
void stagesurface_unmap(stagesurf_t stagesurf)
{
if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, stagesurf->pack_buffer))
return;
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
gl_success("glUnmapBuffer");
gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
}

View File

@ -100,11 +100,6 @@ texture_t device_create_volumetexture(device_t device, uint32_t width,
return NULL;
}
stagesurf_t device_create_stagesurface(device_t device, uint32_t width,
uint32_t height, enum gs_color_format color_format)
{
}
samplerstate_t device_create_samplerstate(device_t device,
struct gs_sampler_info *info)
{
@ -196,11 +191,6 @@ void device_copy_texture(device_t device, texture_t dst, texture_t src)
{
}
void device_stage_texture(device_t device, stagesurf_t dst,
texture_t src)
{
}
void device_beginscene(device_t device)
{
}
@ -363,31 +353,6 @@ enum gs_color_format volumetexture_getcolorformat(texture_t voltex)
{
}
void stagesurface_destroy(stagesurf_t stagesurf)
{
}
uint32_t stagesurface_getwidth(stagesurf_t stagesurf)
{
}
uint32_t stagesurface_getheight(stagesurf_t stagesurf)
{
}
enum gs_color_format stagesurface_getcolorformat(stagesurf_t stagesurf)
{
}
bool stagesurface_map(stagesurf_t stagesurf, const void **data,
uint32_t *byte_width)
{
}
void stagesurface_unmap(stagesurf_t stagesurf)
{
}
void samplerstate_destroy(samplerstate_t samplerstate)
{
}

View File

@ -27,6 +27,12 @@
struct gl_platform;
struct gl_windowinfo;
enum copy_type {
COPY_TYPE_ARB,
COPY_TYPE_NV,
COPY_TYPE_FBO_BLIT
};
static inline GLint convert_gs_format(enum gs_color_format format)
{
switch (format) {
@ -75,6 +81,30 @@ static inline GLint convert_gs_internal_format(enum gs_color_format format)
}
}
static inline GLenum get_gl_format_type(enum color_format format)
{
switch (format) {
case GS_A8: return GL_UNSIGNED_BYTE;
case GS_R8: return GL_UNSIGNED_BYTE;
case GS_RGBA: return GL_UNSIGNED_BYTE;
case GS_BGRX: return GL_UNSIGNED_BYTE;
case GS_BGRA: return GL_UNSIGNED_BYTE;
case GS_R10G10B10A2: return GL_UNSIGNED_INT_10_10_10_2;
case GS_RGBA16: return GL_UNSIGNED_SHORT;
case GS_R16: return GL_UNSIGNED_SHORT;
case GS_RGBA16F: return GL_UNSIGNED_SHORT;
case GS_RGBA32F: return GL_FLOAT;
case GS_RG16F: return GL_UNSIGNED_SHORT;
case GS_RG32F: return GL_FLOAT;
case GS_R16F: return GL_UNSIGNED_SHORT;
case GS_R32F: return GL_FLOAT;
case GS_DXT1: return GL_UNSIGNED_BYTE;
case GS_DXT3: return GL_UNSIGNED_BYTE;
case GS_DXT5: return GL_UNSIGNED_BYTE;
default: return 0;
}
}
static inline GLenum convert_zstencil_format(enum gs_zstencil_format format)
{
switch (format) {
@ -218,6 +248,18 @@ struct gs_texture_cube {
uint32_t size;
};
struct gs_stage_surface {
enum gs_color_format format;
uint32_t width;
uint32_t height;
uint32_t bytes_per_pixel;
GLenum gl_format;
GLint gl_internal_format;
GLuint texture;
GLuint pack_buffer;
};
struct gs_zstencil_buffer {
device_t device;
GLuint buffer;
@ -232,6 +274,7 @@ struct gs_swap_chain {
struct gs_device {
struct gl_platform *plat;
enum copy_type copy_type;
struct gs_texture *cur_render_texture;
int cur_render_side;

View File

@ -23,6 +23,7 @@ static bool upload_texture_2d(struct gs_texture_2d *tex, void **data)
uint32_t tex_size = tex->height * row_size / 8;
uint32_t num_levels = tex->base.levels;
bool compressed = gs_is_compressed_format(tex->base.format);
GLenum gl_type = get_gl_format_type(tex->base.format);
bool success;
if (!num_levels)
@ -31,7 +32,7 @@ static bool upload_texture_2d(struct gs_texture_2d *tex, void **data)
if (!gl_bind_texture(GL_TEXTURE_2D, tex->base.texture))
return false;
success = upload_face(GL_TEXTURE_2D, num_levels,
success = gl_init_face(GL_TEXTURE_2D, gl_type, num_levels,
tex->base.gl_format, tex->base.gl_internal_format,
compressed, tex->width, tex->height, tex_size, &data);
@ -87,7 +88,7 @@ texture_t device_create_texture(device_t device, uint32_t width,
goto fail;
if (tex->base.is_dynamic && !create_pixel_unpack_buffer(tex))
goto fail;
if (data && !upload_texture_2d(tex, data))
if (!upload_texture_2d(tex, data))
goto fail;
return (texture_t)tex;
@ -167,10 +168,8 @@ bool texture_map(texture_t tex, void **ptr, uint32_t *byte_width)
goto fail;
*ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
if (!*ptr) {
gl_success("glMapBuffer");
if (!gl_success("glMapBuffer"))
goto fail;
}
gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0);
@ -190,8 +189,8 @@ void texture_unmap(texture_t tex)
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);
}

View File

@ -23,6 +23,7 @@ static inline bool upload_texture_cube(struct gs_texture_cube *tex, void **data)
uint32_t tex_size = tex->size * row_size / 8;
uint32_t num_levels = tex->base.levels;
bool compressed = gs_is_compressed_format(tex->base.format);
GLenum gl_type = get_gl_format_type(tex->base.format);
bool success = true;
uint32_t i;
@ -30,20 +31,22 @@ static inline bool upload_texture_cube(struct gs_texture_cube *tex, void **data)
num_levels = gs_num_total_levels(tex->size, tex->size);
for (i = 0; i < 6; i++) {
GLenum type = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
if (!gl_bind_texture(type, tex->base.texture))
if (!gl_bind_texture(target, tex->base.texture))
success = false;
if (!upload_face(type, num_levels, tex->base.gl_format,
if (!gl_init_face(target, gl_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))
if (!gl_bind_texture(target, 0))
success = false;
if (data)
data++;
}
@ -68,7 +71,7 @@ texture_t device_create_cubetexture(device_t device, uint32_t size,
if (!gl_gen_textures(1, &tex->base.texture))
goto fail;
if (data && !upload_texture_cube(tex, data))
if (!upload_texture_cube(tex, data))
goto fail;
return (texture_t)tex;

View File

@ -194,7 +194,7 @@ static inline void required_extension_error(const char *extension)
blog(LOG_ERROR, "OpenGL extension %s is required", extension);
}
static bool gl_init_extensions(void)
static bool gl_init_extensions(device_t device)
{
GLenum errorcode = glewInit();
if (errorcode != GLEW_OK) {
@ -218,6 +218,13 @@ static bool gl_init_extensions(void)
return false;
}
if (GL_ARB_copy_image)
device->copy_type = COPY_TYPE_ARB;
else if (GLEW_NV_copy_image)
device->copy_type = COPY_TYPE_NV;
else
device->copy_type = COPY_TYPE_FBO_BLIT;
return true;
}
@ -341,7 +348,7 @@ struct gl_platform *gl_platform_create(device_t device,
if (!gl_dummy_context_init(&dummy))
goto fail;
if (!gl_init_extensions())
if (!gl_init_extensions(device))
goto fail;
/* you have to have a dummy context open before you can actually
@ -401,7 +408,6 @@ struct gl_windowinfo *gl_windowinfo_create(struct gs_init_data *info)
if (!gl_get_pixel_format(wi->hdc, info, &pixel_format, &pfd))
goto fail;
if (!gl_set_pixel_format(wi->hdc, pixel_format, &pfd))
goto fail;

View File

@ -45,6 +45,7 @@ zstencil_t device_create_zstencil(device_t device, uint32_t width,
zs->format = convert_zstencil_format(format);
if (!gl_init_zsbuffer(zs, width, height)) {
blog(LOG_ERROR, "device_create_zstencil (GL) failed");
zstencil_destroy(zs);
return NULL;
}

View File

@ -164,6 +164,7 @@
<ClCompile Include="..\..\..\libobs-opengl\gl-helpers.c" />
<ClCompile Include="..\..\..\libobs-opengl\gl-shader.c" />
<ClCompile Include="..\..\..\libobs-opengl\gl-shaderparser.c" />
<ClCompile Include="..\..\..\libobs-opengl\gl-stagesurf.c" />
<ClCompile Include="..\..\..\libobs-opengl\gl-subsystem.c" />
<ClCompile Include="..\..\..\libobs-opengl\gl-texture2d.c" />
<ClCompile Include="..\..\..\libobs-opengl\gl-texturecube.c" />

View File

@ -53,5 +53,8 @@
<ClCompile Include="..\..\..\libobs-opengl\gl-zstencil.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\libobs-opengl\gl-stagesurf.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>