New upstream version 25.0.3+dfsg1
This commit is contained in:
parent
04fe0efc67
commit
8b2e5f2130
569 changed files with 62491 additions and 5875 deletions
|
|
@ -58,6 +58,7 @@ set(libobs-opengl_SOURCES
|
|||
gl-stagesurf.c
|
||||
gl-subsystem.c
|
||||
gl-texture2d.c
|
||||
gl-texture3d.c
|
||||
gl-texturecube.c
|
||||
gl-vertexbuffer.c
|
||||
gl-zstencil.c)
|
||||
|
|
|
|||
|
|
@ -25,13 +25,16 @@
|
|||
|
||||
struct gl_windowinfo {
|
||||
NSView *view;
|
||||
NSOpenGLContext *context;
|
||||
gs_texture_t *texture;
|
||||
GLuint fbo;
|
||||
};
|
||||
|
||||
struct gl_platform {
|
||||
NSOpenGLContext *context;
|
||||
};
|
||||
|
||||
static NSOpenGLContext *gl_context_create(void)
|
||||
static NSOpenGLContext *gl_context_create(NSOpenGLContext *share)
|
||||
{
|
||||
unsigned attrib_count = 0;
|
||||
|
||||
|
|
@ -62,7 +65,8 @@ static NSOpenGLContext *gl_context_create(void)
|
|||
}
|
||||
|
||||
NSOpenGLContext *context;
|
||||
context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil];
|
||||
context = [[NSOpenGLContext alloc] initWithFormat:pf
|
||||
shareContext:share];
|
||||
[pf release];
|
||||
if (!context) {
|
||||
blog(LOG_ERROR, "Failed to create context");
|
||||
|
|
@ -76,28 +80,29 @@ static NSOpenGLContext *gl_context_create(void)
|
|||
|
||||
struct gl_platform *gl_platform_create(gs_device_t *device, uint32_t adapter)
|
||||
{
|
||||
struct gl_platform *plat = bzalloc(sizeof(struct gl_platform));
|
||||
GLint interval = 0;
|
||||
|
||||
plat->context = gl_context_create();
|
||||
if (!plat->context)
|
||||
goto fail;
|
||||
|
||||
[plat->context makeCurrentContext];
|
||||
[plat->context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
|
||||
|
||||
if (!gladLoadGL())
|
||||
goto fail;
|
||||
|
||||
return plat;
|
||||
|
||||
fail:
|
||||
blog(LOG_ERROR, "gl_platform_create failed");
|
||||
gl_platform_destroy(plat);
|
||||
|
||||
UNUSED_PARAMETER(device);
|
||||
UNUSED_PARAMETER(adapter);
|
||||
return NULL;
|
||||
|
||||
NSOpenGLContext *context = gl_context_create(nil);
|
||||
if (!context) {
|
||||
blog(LOG_ERROR, "gl_context_create failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
[context makeCurrentContext];
|
||||
GLint interval = 0;
|
||||
[context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
|
||||
const bool success = gladLoadGL() != 0;
|
||||
|
||||
if (!success) {
|
||||
blog(LOG_ERROR, "gladLoadGL failed");
|
||||
[context release];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct gl_platform *plat = bzalloc(sizeof(struct gl_platform));
|
||||
plat->context = context;
|
||||
return plat;
|
||||
}
|
||||
|
||||
void gl_platform_destroy(struct gl_platform *platform)
|
||||
|
|
@ -113,14 +118,72 @@ void gl_platform_destroy(struct gl_platform *platform)
|
|||
|
||||
bool gl_platform_init_swapchain(struct gs_swap_chain *swap)
|
||||
{
|
||||
UNUSED_PARAMETER(swap);
|
||||
NSOpenGLContext *parent = swap->device->plat->context;
|
||||
NSOpenGLContext *context = gl_context_create(parent);
|
||||
bool success = context != nil;
|
||||
if (success) {
|
||||
CGLContextObj parent_obj = [parent CGLContextObj];
|
||||
CGLLockContext(parent_obj);
|
||||
|
||||
return true;
|
||||
[parent makeCurrentContext];
|
||||
struct gs_init_data *init_data = &swap->info;
|
||||
swap->wi->texture = device_texture_create(
|
||||
swap->device, init_data->cx, init_data->cy,
|
||||
init_data->format, 1, NULL, GS_RENDER_TARGET);
|
||||
glFlush();
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
CGLContextObj context_obj = [context CGLContextObj];
|
||||
CGLLockContext(context_obj);
|
||||
|
||||
[context makeCurrentContext];
|
||||
[context setView:swap->wi->view];
|
||||
GLint interval = 0;
|
||||
[context setValues:&interval
|
||||
forParameter:NSOpenGLCPSwapInterval];
|
||||
gl_gen_framebuffers(1, &swap->wi->fbo);
|
||||
gl_bind_framebuffer(GL_FRAMEBUFFER, swap->wi->fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
swap->wi->texture->texture, 0);
|
||||
gl_success("glFrameBufferTexture2D");
|
||||
glFlush();
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
CGLUnlockContext(context_obj);
|
||||
|
||||
CGLUnlockContext(parent_obj);
|
||||
|
||||
swap->wi->context = context;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void gl_platform_cleanup_swapchain(struct gs_swap_chain *swap)
|
||||
{
|
||||
UNUSED_PARAMETER(swap);
|
||||
NSOpenGLContext *parent = swap->device->plat->context;
|
||||
CGLContextObj parent_obj = [parent CGLContextObj];
|
||||
CGLLockContext(parent_obj);
|
||||
|
||||
NSOpenGLContext *context = swap->wi->context;
|
||||
CGLContextObj context_obj = [context CGLContextObj];
|
||||
CGLLockContext(context_obj);
|
||||
|
||||
[context makeCurrentContext];
|
||||
gl_delete_framebuffers(1, &swap->wi->fbo);
|
||||
glFlush();
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
CGLUnlockContext(context_obj);
|
||||
|
||||
[parent makeCurrentContext];
|
||||
gs_texture_destroy(swap->wi->texture);
|
||||
glFlush();
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
swap->wi->context = nil;
|
||||
|
||||
CGLUnlockContext(parent_obj);
|
||||
}
|
||||
|
||||
struct gl_windowinfo *gl_windowinfo_create(const struct gs_init_data *info)
|
||||
|
|
@ -150,19 +213,62 @@ void gl_windowinfo_destroy(struct gl_windowinfo *wi)
|
|||
|
||||
void gl_update(gs_device_t *device)
|
||||
{
|
||||
[device->plat->context update];
|
||||
gs_swapchain_t *swap = device->cur_swap;
|
||||
NSOpenGLContext *parent = device->plat->context;
|
||||
NSOpenGLContext *context = swap->wi->context;
|
||||
dispatch_async(dispatch_get_main_queue(), ^() {
|
||||
CGLContextObj parent_obj = [parent CGLContextObj];
|
||||
CGLLockContext(parent_obj);
|
||||
|
||||
CGLContextObj context_obj = [context CGLContextObj];
|
||||
CGLLockContext(context_obj);
|
||||
|
||||
[context makeCurrentContext];
|
||||
[context update];
|
||||
struct gs_init_data *info = &swap->info;
|
||||
gs_texture_t *previous = swap->wi->texture;
|
||||
swap->wi->texture = device_texture_create(device, info->cx,
|
||||
info->cy,
|
||||
info->format, 1, NULL,
|
||||
GS_RENDER_TARGET);
|
||||
gl_bind_framebuffer(GL_FRAMEBUFFER, swap->wi->fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
swap->wi->texture->texture, 0);
|
||||
gl_success("glFrameBufferTexture2D");
|
||||
gs_texture_destroy(previous);
|
||||
glFlush();
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
CGLUnlockContext(context_obj);
|
||||
|
||||
CGLUnlockContext(parent_obj);
|
||||
});
|
||||
}
|
||||
|
||||
void gl_clear_context(gs_device_t *device)
|
||||
{
|
||||
UNUSED_PARAMETER(device);
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
}
|
||||
|
||||
void device_enter_context(gs_device_t *device)
|
||||
{
|
||||
CGLLockContext([device->plat->context CGLContextObj]);
|
||||
|
||||
[device->plat->context makeCurrentContext];
|
||||
}
|
||||
|
||||
void device_leave_context(gs_device_t *device)
|
||||
{
|
||||
UNUSED_PARAMETER(device);
|
||||
|
||||
glFlush();
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
device->cur_render_target = NULL;
|
||||
device->cur_zstencil_buffer = NULL;
|
||||
device->cur_swap = NULL;
|
||||
device->cur_fbo = NULL;
|
||||
|
||||
CGLUnlockContext([device->plat->context CGLContextObj]);
|
||||
}
|
||||
|
||||
void *device_get_device_obj(gs_device_t *device)
|
||||
|
|
@ -177,15 +283,35 @@ void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap)
|
|||
|
||||
device->cur_swap = swap;
|
||||
if (swap) {
|
||||
[device->plat->context setView:swap->wi->view];
|
||||
} else {
|
||||
[device->plat->context clearDrawable];
|
||||
device_set_render_target(device, swap->wi->texture, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void device_present(gs_device_t *device)
|
||||
{
|
||||
[device->plat->context flushBuffer];
|
||||
glFlush();
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
CGLUnlockContext([device->plat->context CGLContextObj]);
|
||||
|
||||
CGLLockContext([device->cur_swap->wi->context CGLContextObj]);
|
||||
|
||||
[device->cur_swap->wi->context makeCurrentContext];
|
||||
gl_bind_framebuffer(GL_READ_FRAMEBUFFER, device->cur_swap->wi->fbo);
|
||||
gl_bind_framebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
const uint32_t width = device->cur_swap->info.cx;
|
||||
const uint32_t height = device->cur_swap->info.cy;
|
||||
glBlitFramebuffer(0, 0, width, height, 0, height, width, 0,
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
[device->cur_swap->wi->context flushBuffer];
|
||||
glFlush();
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
CGLUnlockContext([device->cur_swap->wi->context CGLContextObj]);
|
||||
|
||||
CGLLockContext([device->plat->context CGLContextObj]);
|
||||
|
||||
[device->plat->context makeCurrentContext];
|
||||
}
|
||||
|
||||
void gl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width,
|
||||
|
|
|
|||
|
|
@ -45,13 +45,10 @@ bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
|
|||
data++;
|
||||
|
||||
size /= 4;
|
||||
width /= 2;
|
||||
height /= 2;
|
||||
|
||||
if (width == 0)
|
||||
width = 1;
|
||||
if (height == 0)
|
||||
height = 1;
|
||||
if (width > 1)
|
||||
width /= 2;
|
||||
if (height > 1)
|
||||
height /= 2;
|
||||
}
|
||||
|
||||
if (data)
|
||||
|
|
|
|||
|
|
@ -149,12 +149,24 @@ static inline bool gl_bind_renderbuffer(GLenum target, GLuint buffer)
|
|||
return gl_success("glBindRendebuffer");
|
||||
}
|
||||
|
||||
static inline bool gl_gen_framebuffers(GLsizei num_arrays, GLuint *arrays)
|
||||
{
|
||||
glGenFramebuffers(num_arrays, arrays);
|
||||
return gl_success("glGenFramebuffers");
|
||||
}
|
||||
|
||||
static inline bool gl_bind_framebuffer(GLenum target, GLuint buffer)
|
||||
{
|
||||
glBindFramebuffer(target, buffer);
|
||||
return gl_success("glBindFramebuffer");
|
||||
}
|
||||
|
||||
static inline void gl_delete_framebuffers(GLsizei num_arrays, GLuint *arrays)
|
||||
{
|
||||
glDeleteFramebuffers(num_arrays, arrays);
|
||||
gl_success("glDeleteFramebuffers");
|
||||
}
|
||||
|
||||
static inline bool gl_tex_param_f(GLenum target, GLenum param, GLfloat val)
|
||||
{
|
||||
glTexParameterf(target, param, val);
|
||||
|
|
|
|||
|
|
@ -692,7 +692,7 @@ static bool gl_shader_buildstring(struct gl_shader_parser *glsp)
|
|||
return false;
|
||||
}
|
||||
|
||||
dstr_copy(&glsp->gl_string, "#version 150\n\n");
|
||||
dstr_copy(&glsp->gl_string, "#version 330\n\n");
|
||||
dstr_cat(&glsp->gl_string, "const bool obs_glsl_compile = true;\n\n");
|
||||
gl_write_params(glsp);
|
||||
gl_write_inputs(glsp, main_func);
|
||||
|
|
|
|||
|
|
@ -130,23 +130,15 @@ static void gl_enable_debug() {}
|
|||
|
||||
static bool gl_init_extensions(struct gs_device *device)
|
||||
{
|
||||
if (!GLAD_GL_VERSION_2_1) {
|
||||
blog(LOG_ERROR, "obs-studio requires OpenGL version 2.1 or "
|
||||
"higher.");
|
||||
if (!GLAD_GL_VERSION_3_3) {
|
||||
blog(LOG_ERROR,
|
||||
"obs-studio requires OpenGL version 3.3 or higher.");
|
||||
return false;
|
||||
}
|
||||
|
||||
gl_enable_debug();
|
||||
|
||||
if (!GLAD_GL_VERSION_3_0 && !GLAD_GL_ARB_framebuffer_object) {
|
||||
blog(LOG_ERROR, "OpenGL extension ARB_framebuffer_object "
|
||||
"is required.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GLAD_GL_VERSION_3_2 || GLAD_GL_ARB_seamless_cube_map) {
|
||||
gl_enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
}
|
||||
gl_enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
|
||||
if (GLAD_GL_VERSION_4_3 || GLAD_GL_ARB_copy_image)
|
||||
device->copy_type = COPY_TYPE_ARB;
|
||||
|
|
@ -182,8 +174,11 @@ void convert_sampler_info(struct gs_sampler_state *sampler,
|
|||
sampler->max_anisotropy = info->max_anisotropy;
|
||||
|
||||
max_anisotropy_max = 1;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy_max);
|
||||
gl_success("glGetIntegerv(GL_MAX_TEXTURE_ANISOTROPY_MAX)");
|
||||
if (GLAD_GL_EXT_texture_filter_anisotropic) {
|
||||
glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
&max_anisotropy_max);
|
||||
gl_success("glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT)");
|
||||
}
|
||||
|
||||
if (1 <= sampler->max_anisotropy &&
|
||||
sampler->max_anisotropy <= max_anisotropy_max)
|
||||
|
|
@ -250,7 +245,7 @@ int device_create(gs_device_t **p_device, uint32_t adapter)
|
|||
gl_enable(GL_CULL_FACE);
|
||||
gl_gen_vertex_arrays(1, &device->empty_vao);
|
||||
|
||||
device_leave_context(device);
|
||||
gl_clear_context(device);
|
||||
device->cur_swap = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
@ -354,24 +349,6 @@ uint32_t device_get_height(const gs_device_t *device)
|
|||
}
|
||||
}
|
||||
|
||||
gs_texture_t *device_voltexture_create(gs_device_t *device, uint32_t width,
|
||||
uint32_t height, uint32_t depth,
|
||||
enum gs_color_format color_format,
|
||||
uint32_t levels, const uint8_t **data,
|
||||
uint32_t flags)
|
||||
{
|
||||
/* TODO */
|
||||
UNUSED_PARAMETER(device);
|
||||
UNUSED_PARAMETER(width);
|
||||
UNUSED_PARAMETER(height);
|
||||
UNUSED_PARAMETER(depth);
|
||||
UNUSED_PARAMETER(color_format);
|
||||
UNUSED_PARAMETER(levels);
|
||||
UNUSED_PARAMETER(data);
|
||||
UNUSED_PARAMETER(flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gs_samplerstate_t *
|
||||
device_samplerstate_create(gs_device_t *device,
|
||||
const struct gs_sampler_info *info)
|
||||
|
|
@ -475,9 +452,12 @@ static bool load_texture_sampler(gs_texture_t *tex, gs_samplerstate_t *ss)
|
|||
success = false;
|
||||
if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_WRAP_R, ss->address_w))
|
||||
success = false;
|
||||
if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
ss->max_anisotropy))
|
||||
success = false;
|
||||
if (GLAD_GL_EXT_texture_filter_anisotropic) {
|
||||
if (!gl_tex_param_i(tex->gl_target,
|
||||
GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
ss->max_anisotropy))
|
||||
success = false;
|
||||
}
|
||||
|
||||
apply_swizzle(tex);
|
||||
|
||||
|
|
@ -929,6 +909,12 @@ void device_copy_texture(gs_device_t *device, gs_texture_t *dst,
|
|||
device_copy_texture_region(device, dst, 0, 0, src, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void device_begin_frame(gs_device_t *device)
|
||||
{
|
||||
/* does nothing */
|
||||
UNUSED_PARAMETER(device);
|
||||
}
|
||||
|
||||
void device_begin_scene(gs_device_t *device)
|
||||
{
|
||||
clear_textures(device);
|
||||
|
|
@ -1421,12 +1407,6 @@ void gs_swapchain_destroy(gs_swapchain_t *swapchain)
|
|||
bfree(swapchain);
|
||||
}
|
||||
|
||||
void gs_voltexture_destroy(gs_texture_t *voltex)
|
||||
{
|
||||
/* TODO */
|
||||
UNUSED_PARAMETER(voltex);
|
||||
}
|
||||
|
||||
uint32_t gs_voltexture_get_width(const gs_texture_t *voltex)
|
||||
{
|
||||
/* TODO */
|
||||
|
|
|
|||
|
|
@ -144,17 +144,17 @@ static inline GLenum get_gl_format_type(enum gs_color_format format)
|
|||
case GS_R16:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
case GS_RGBA16F:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
return GL_HALF_FLOAT;
|
||||
case GS_RGBA32F:
|
||||
return GL_FLOAT;
|
||||
case GS_RG16F:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
return GL_HALF_FLOAT;
|
||||
case GS_RG32F:
|
||||
return GL_FLOAT;
|
||||
case GS_R8G8:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case GS_R16F:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
return GL_HALF_FLOAT;
|
||||
case GS_R32F:
|
||||
return GL_FLOAT;
|
||||
case GS_DXT1:
|
||||
|
|
@ -527,6 +527,16 @@ struct gs_texture_2d {
|
|||
GLuint unpack_buffer;
|
||||
};
|
||||
|
||||
struct gs_texture_3d {
|
||||
struct gs_texture base;
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t depth;
|
||||
bool gen_mipmaps;
|
||||
GLuint unpack_buffer;
|
||||
};
|
||||
|
||||
struct gs_texture_cube {
|
||||
struct gs_texture base;
|
||||
|
||||
|
|
@ -617,6 +627,7 @@ extern struct fbo_info *get_fbo(gs_texture_t *tex, uint32_t width,
|
|||
uint32_t height);
|
||||
|
||||
extern void gl_update(gs_device_t *device);
|
||||
extern void gl_clear_context(gs_device_t *device);
|
||||
|
||||
extern struct gl_platform *gl_platform_create(gs_device_t *device,
|
||||
uint32_t adapter);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ static bool upload_texture_2d(struct gs_texture_2d *tex, const uint8_t **data)
|
|||
bool success;
|
||||
|
||||
if (!num_levels)
|
||||
num_levels = gs_get_total_levels(tex->width, tex->height);
|
||||
num_levels = gs_get_total_levels(tex->width, tex->height, 1);
|
||||
|
||||
if (!gl_bind_texture(GL_TEXTURE_2D, tex->base.texture))
|
||||
return false;
|
||||
|
|
@ -145,18 +145,25 @@ static inline bool is_texture_2d(const gs_texture_t *tex, const char *func)
|
|||
|
||||
void gs_texture_destroy(gs_texture_t *tex)
|
||||
{
|
||||
struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex;
|
||||
if (!tex)
|
||||
return;
|
||||
|
||||
if (!is_texture_2d(tex, "gs_texture_destroy"))
|
||||
return;
|
||||
|
||||
if (tex->cur_sampler)
|
||||
gs_samplerstate_destroy(tex->cur_sampler);
|
||||
|
||||
if (!tex->is_dummy && tex->is_dynamic && tex2d->unpack_buffer)
|
||||
gl_delete_buffers(1, &tex2d->unpack_buffer);
|
||||
if (!tex->is_dummy && tex->is_dynamic) {
|
||||
if (tex->type == GS_TEXTURE_2D) {
|
||||
struct gs_texture_2d *tex2d =
|
||||
(struct gs_texture_2d *)tex;
|
||||
if (tex2d->unpack_buffer)
|
||||
gl_delete_buffers(1, &tex2d->unpack_buffer);
|
||||
} else if (tex->type == GS_TEXTURE_3D) {
|
||||
struct gs_texture_3d *tex3d =
|
||||
(struct gs_texture_3d *)tex;
|
||||
if (tex3d->unpack_buffer)
|
||||
gl_delete_buffers(1, &tex3d->unpack_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (tex->texture)
|
||||
gl_delete_textures(1, &tex->texture);
|
||||
|
|
@ -253,19 +260,22 @@ failed:
|
|||
|
||||
bool gs_texture_is_rect(const gs_texture_t *tex)
|
||||
{
|
||||
const struct gs_texture_2d *tex2d = (const struct gs_texture_2d *)tex;
|
||||
if (!is_texture_2d(tex, "gs_texture_unmap")) {
|
||||
if (tex->type == GS_TEXTURE_3D)
|
||||
return false;
|
||||
|
||||
if (!is_texture_2d(tex, "gs_texture_is_rect")) {
|
||||
blog(LOG_ERROR, "gs_texture_is_rect (GL) failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct gs_texture_2d *tex2d = (const struct gs_texture_2d *)tex;
|
||||
return tex2d->base.gl_target == GL_TEXTURE_RECTANGLE;
|
||||
}
|
||||
|
||||
void *gs_texture_get_obj(gs_texture_t *tex)
|
||||
{
|
||||
struct gs_texture_2d *tex2d = (struct gs_texture_2d *)tex;
|
||||
if (!is_texture_2d(tex, "gs_texture_unmap")) {
|
||||
if (!is_texture_2d(tex, "gs_texture_get_obj")) {
|
||||
blog(LOG_ERROR, "gs_texture_get_obj (GL) failed");
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
186
libobs-opengl/gl-texture3d.c
Normal file
186
libobs-opengl/gl-texture3d.c
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/******************************************************************************
|
||||
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 2 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 gl_init_volume(GLenum type, uint32_t num_levels, GLenum format,
|
||||
GLint internal_format, bool compressed,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
const uint8_t *const **p_data)
|
||||
{
|
||||
bool success = true;
|
||||
const uint8_t *const *data = p_data ? *p_data : NULL;
|
||||
uint32_t i;
|
||||
const uint32_t bpp = gs_get_format_bpp(format);
|
||||
|
||||
for (i = 0; i < num_levels; i++) {
|
||||
if (compressed) {
|
||||
uint32_t mip_size = width * height * depth * bpp / 8;
|
||||
glCompressedTexImage3D(GL_TEXTURE_3D, i,
|
||||
internal_format, width, height,
|
||||
depth, 0, mip_size,
|
||||
data ? *data : NULL);
|
||||
if (!gl_success("glCompressedTexImage3D"))
|
||||
success = false;
|
||||
|
||||
} else {
|
||||
glTexImage3D(GL_TEXTURE_3D, i, internal_format, width,
|
||||
height, depth, 0, format, type,
|
||||
data ? *data : NULL);
|
||||
if (!gl_success("glTexImage3D"))
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (data)
|
||||
data++;
|
||||
|
||||
if (width > 1)
|
||||
width /= 2;
|
||||
if (height > 1)
|
||||
height /= 2;
|
||||
if (depth > 1)
|
||||
depth /= 2;
|
||||
}
|
||||
|
||||
if (data)
|
||||
*p_data = data;
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool upload_texture_3d(struct gs_texture_3d *tex,
|
||||
const uint8_t *const *data)
|
||||
{
|
||||
uint32_t num_levels = tex->base.levels;
|
||||
bool compressed = gs_is_compressed_format(tex->base.format);
|
||||
bool success;
|
||||
|
||||
if (!num_levels)
|
||||
num_levels = gs_get_total_levels(tex->width, tex->height,
|
||||
tex->depth);
|
||||
|
||||
if (!gl_bind_texture(GL_TEXTURE_3D, tex->base.texture))
|
||||
return false;
|
||||
|
||||
success = gl_init_volume(tex->base.gl_type, num_levels,
|
||||
tex->base.gl_format,
|
||||
tex->base.gl_internal_format, compressed,
|
||||
tex->width, tex->height, tex->depth, &data);
|
||||
|
||||
if (!gl_tex_param_i(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL,
|
||||
num_levels - 1))
|
||||
success = false;
|
||||
if (!gl_bind_texture(GL_TEXTURE_3D, 0))
|
||||
success = false;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool create_pixel_unpack_buffer(struct gs_texture_3d *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 * gs_get_format_bpp(tex->base.format);
|
||||
if (!gs_is_compressed_format(tex->base.format)) {
|
||||
size /= 8;
|
||||
size = (size + 3) & 0xFFFFFFFC;
|
||||
size *= tex->height;
|
||||
size *= tex->depth;
|
||||
} else {
|
||||
size *= tex->height;
|
||||
size *= tex->depth;
|
||||
size /= 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;
|
||||
}
|
||||
|
||||
gs_texture_t *device_voltexture_create(gs_device_t *device, uint32_t width,
|
||||
uint32_t height, uint32_t depth,
|
||||
enum gs_color_format color_format,
|
||||
uint32_t levels,
|
||||
const uint8_t *const *data,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct gs_texture_3d *tex = bzalloc(sizeof(struct gs_texture_3d));
|
||||
tex->base.device = device;
|
||||
tex->base.type = GS_TEXTURE_3D;
|
||||
tex->base.format = color_format;
|
||||
tex->base.levels = levels;
|
||||
tex->base.gl_format = convert_gs_format(color_format);
|
||||
tex->base.gl_internal_format = convert_gs_internal_format(color_format);
|
||||
tex->base.gl_type = get_gl_format_type(color_format);
|
||||
tex->base.gl_target = GL_TEXTURE_3D;
|
||||
tex->base.is_dynamic = (flags & GS_DYNAMIC) != 0;
|
||||
tex->base.is_render_target = false;
|
||||
tex->base.is_dummy = (flags & GS_GL_DUMMYTEX) != 0;
|
||||
tex->base.gen_mipmaps = (flags & GS_BUILD_MIPMAPS) != 0;
|
||||
tex->width = width;
|
||||
tex->height = height;
|
||||
tex->depth = depth;
|
||||
|
||||
if (!gl_gen_textures(1, &tex->base.texture))
|
||||
goto fail;
|
||||
|
||||
if (!tex->base.is_dummy) {
|
||||
if (tex->base.is_dynamic && !create_pixel_unpack_buffer(tex))
|
||||
goto fail;
|
||||
if (!upload_texture_3d(tex, data))
|
||||
goto fail;
|
||||
} else {
|
||||
if (!gl_bind_texture(GL_TEXTURE_3D, tex->base.texture))
|
||||
goto fail;
|
||||
|
||||
bool compressed = gs_is_compressed_format(tex->base.format);
|
||||
bool did_init = gl_init_volume(tex->base.gl_type, 1,
|
||||
tex->base.gl_format,
|
||||
tex->base.gl_internal_format,
|
||||
compressed, tex->width,
|
||||
tex->height, tex->depth, NULL);
|
||||
did_init =
|
||||
gl_tex_param_i(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
bool did_unbind = gl_bind_texture(GL_TEXTURE_3D, 0);
|
||||
if (!did_init || !did_unbind)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return (gs_texture_t *)tex;
|
||||
|
||||
fail:
|
||||
gs_texture_destroy((gs_texture_t *)tex);
|
||||
blog(LOG_ERROR, "device_voltexture_create (GL) failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void gs_voltexture_destroy(gs_texture_t *voltex)
|
||||
{
|
||||
gs_texture_destroy(voltex);
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ static inline bool upload_texture_cube(struct gs_texture_cube *tex,
|
|||
uint32_t i;
|
||||
|
||||
if (!num_levels)
|
||||
num_levels = gs_get_total_levels(tex->size, tex->size);
|
||||
num_levels = gs_get_total_levels(tex->size, tex->size, 1);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ static inline int get_color_format_bits(enum gs_color_format format)
|
|||
{
|
||||
switch ((uint32_t)format) {
|
||||
case GS_RGBA:
|
||||
case GS_BGRA:
|
||||
return 32;
|
||||
default:
|
||||
return 0;
|
||||
|
|
@ -154,35 +155,37 @@ static inline HGLRC gl_init_basic_context(HDC hdc)
|
|||
return hglrc;
|
||||
}
|
||||
|
||||
static const int attribs[] = {
|
||||
#ifdef _DEBUG
|
||||
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||
#endif
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0, 0};
|
||||
|
||||
static inline HGLRC gl_init_context(HDC hdc)
|
||||
{
|
||||
static const int attribs[] = {
|
||||
#ifdef _DEBUG
|
||||
if (GLAD_WGL_ARB_create_context) {
|
||||
HGLRC hglrc = wglCreateContextAttribsARB(hdc, 0, attribs);
|
||||
if (!hglrc) {
|
||||
blog(LOG_ERROR,
|
||||
"wglCreateContextAttribsARB failed, "
|
||||
"%lu",
|
||||
GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!wgl_make_current(hdc, hglrc)) {
|
||||
wglDeleteContext(hglrc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hglrc;
|
||||
}
|
||||
WGL_CONTEXT_FLAGS_ARB,
|
||||
WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||
#endif
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB,
|
||||
WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB,
|
||||
3,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB,
|
||||
3,
|
||||
0,
|
||||
0};
|
||||
|
||||
return gl_init_basic_context(hdc);
|
||||
HGLRC hglrc = wglCreateContextAttribsARB(hdc, 0, attribs);
|
||||
if (!hglrc) {
|
||||
blog(LOG_ERROR,
|
||||
"wglCreateContextAttribsARB failed, "
|
||||
"%lu",
|
||||
GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!wgl_make_current(hdc, hglrc)) {
|
||||
wglDeleteContext(hglrc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hglrc;
|
||||
}
|
||||
|
||||
static bool gl_dummy_context_init(struct dummy_context *dummy)
|
||||
|
|
@ -412,6 +415,12 @@ void gl_update(gs_device_t *device)
|
|||
UNUSED_PARAMETER(device);
|
||||
}
|
||||
|
||||
void gl_clear_context(gs_device_t *device)
|
||||
{
|
||||
UNUSED_PARAMETER(device);
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
}
|
||||
|
||||
static void init_dummy_swap_info(struct gs_init_data *info)
|
||||
{
|
||||
info->format = GS_RGBA;
|
||||
|
|
@ -538,8 +547,8 @@ void device_enter_context(gs_device_t *device)
|
|||
|
||||
void device_leave_context(gs_device_t *device)
|
||||
{
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
UNUSED_PARAMETER(device);
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
}
|
||||
|
||||
void *device_get_device_obj(gs_device_t *device)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ static const int ctx_attribs[] = {
|
|||
GLX_CONTEXT_MAJOR_VERSION_ARB,
|
||||
3,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB,
|
||||
2,
|
||||
3,
|
||||
None,
|
||||
};
|
||||
|
||||
|
|
@ -95,53 +95,6 @@ struct gl_platform {
|
|||
GLXPbuffer pbuffer;
|
||||
};
|
||||
|
||||
static void print_info_stuff(const struct gs_init_data *info)
|
||||
{
|
||||
blog(LOG_INFO,
|
||||
"X and Y: %i %i\n"
|
||||
"Backbuffers: %i\n"
|
||||
"Color Format: %i\n"
|
||||
"ZStencil Format: %i\n"
|
||||
"Adapter: %i\n",
|
||||
info->cx, info->cy, info->num_backbuffers, info->format,
|
||||
info->zsformat, info->adapter);
|
||||
}
|
||||
/* The following utility functions are copied verbatim from WGL code.
|
||||
* GLX and WGL are more similar than most people realize. */
|
||||
|
||||
/* For now, only support basic 32bit formats for graphics output. */
|
||||
static inline int get_color_format_bits(enum gs_color_format format)
|
||||
{
|
||||
switch ((uint32_t)format) {
|
||||
case GS_RGBA:
|
||||
return 32;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int get_depth_format_bits(enum gs_zstencil_format zsformat)
|
||||
{
|
||||
switch ((uint32_t)zsformat) {
|
||||
case GS_Z16:
|
||||
return 16;
|
||||
case GS_Z24_S8:
|
||||
return 24;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int get_stencil_format_bits(enum gs_zstencil_format zsformat)
|
||||
{
|
||||
switch ((uint32_t)zsformat) {
|
||||
case GS_Z24_S8:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we cannot take advantage of the asynchronous nature of xcb,
|
||||
* all of the helper functions are synchronous but thread-safe.
|
||||
|
|
@ -277,7 +230,6 @@ gl_windowinfo_create(const struct gs_init_data *info)
|
|||
|
||||
extern void gl_windowinfo_destroy(struct gl_windowinfo *info)
|
||||
{
|
||||
UNUSED_PARAMETER(info);
|
||||
bfree(info);
|
||||
}
|
||||
|
||||
|
|
@ -532,6 +484,15 @@ extern void gl_getclientsize(const struct gs_swap_chain *swap, uint32_t *width,
|
|||
free(geometry);
|
||||
}
|
||||
|
||||
extern void gl_clear_context(gs_device_t *device)
|
||||
{
|
||||
Display *display = device->plat->display;
|
||||
|
||||
if (!glXMakeContextCurrent(display, None, None, NULL)) {
|
||||
blog(LOG_ERROR, "Failed to reset current context.");
|
||||
}
|
||||
}
|
||||
|
||||
extern void gl_update(gs_device_t *device)
|
||||
{
|
||||
Display *display = device->plat->display;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue