add stage surfaces and texture copying
parent
c1939de49b
commit
85e2fc6b07
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue