obs-studio/libobs-opengl/gl-windows.c

220 lines
5 KiB
C
Raw Normal View History

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "util/darray.h"
#include "gl-subsystem.h"
#include "glew/include/GL/wglew.h"
struct gl_platform {
HDC hdc;
HGLRC hrc;
};
struct gl_window {
HDC hdc;
};
/* would use designated initializers but microsoft sort of sucks */
static inline void init_dummy_pixel_format(PIXELFORMATDESCRIPTOR *pfd)
{
memset(&pfd, 0, sizeof(pfd));
pfd->nSize = sizeof(pfd);
pfd->nVersion = 1;
pfd->iPixelType = PFD_TYPE_RGBA;
pfd->cColorBits = 32;
pfd->cDepthBits = 24;
pfd->cStencilBits = 8;
pfd->iLayerType = PFD_MAIN_PLANE;
pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
}
static bool gl_create_false_context(struct gl_platform *plat,
struct gs_init_data *info)
{
PIXELFORMATDESCRIPTOR pfd;
int format_index;
plat->hdc = GetDC(info->hwnd);
init_dummy_pixel_format(&pfd);
format_index = ChoosePixelFormat(plat->hdc, &pfd);
if (!format_index) {
blog(LOG_ERROR, "ChoosePixelFormat failed, %u", GetLastError());
return false;
}
if (!SetPixelFormat(plat->hdc, format_index, &pfd)) {
blog(LOG_ERROR, "SetPixelFormat failed, %u", GetLastError());
return false;
}
plat->hrc = wglCreateContext(plat->hdc);
if (!plat->hrc) {
blog(LOG_ERROR, "wglCreateContext failed, %u", GetLastError());
return false;
}
if (!wglMakeCurrent(plat->hdc, plat->hrc)) {
blog(LOG_ERROR, "wglMakeCurrent failed, %u", GetLastError());
return false;
}
return true;
}
static inline void required_extension_error(const char *extension)
{
blog(LOG_ERROR, "OpenGL extension %s is required", extension);
}
static bool gl_init_extensions(void)
{
GLenum errorcode = glewInit();
if (errorcode != GLEW_OK) {
blog(LOG_ERROR, "glewInit failed, %u", errorcode);
return false;
}
if (!GLEW_VERSION_2_1) {
blog(LOG_ERROR, "OpenGL 2.1 minimum required by the graphics "
"adapter");
return false;
}
if (!GLEW_ARB_framebuffer_object) {
required_extension_error("GL_ARB_framebuffer_object");
return false;
}
if (!WGLEW_EXT_swap_control) {
required_extension_error("WGL_EXT_swap_control");
return false;
}
if (!WGLEW_ARB_pixel_format) {
required_extension_error("WGL_ARB_pixel_format");
return false;
}
return true;
}
static inline int get_color_format_bits(enum gs_color_format format)
{
switch (format) {
case GS_RGBA:
return 32;
default:
return 0;
}
}
static inline int get_depth_format_bits(enum gs_zstencil_format zsformat)
{
switch (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 (zsformat) {
case GS_Z24_S8:
return 8;
default:
return 0;
}
}
static inline void add_attrib(struct darray *list, int attrib, int val)
{
darray_push_back(sizeof(int), list, &attrib);
darray_push_back(sizeof(int), list, &val);
}
static int gl_get_pixel_format(struct gl_platform *plat,
struct gs_init_data *info)
{
struct darray attribs;
int color_bits = get_color_format_bits(info->format);
int depth_bits = get_depth_format_bits(info->zsformat);
int stencil_bits = get_stencil_format_bits(info->zsformat);
UINT num_formats;
int format;
if (!color_bits) {
blog(LOG_ERROR, "gl_init_pixel_format: color format not "
"supported");
return false;
}
darray_init(&attribs);
add_attrib(&attribs, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE);
add_attrib(&attribs, WGL_SUPPORT_OPENGL_ARB, GL_TRUE);
add_attrib(&attribs, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
add_attrib(&attribs, WGL_DOUBLE_BUFFER_ARB, GL_TRUE);
add_attrib(&attribs, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
add_attrib(&attribs, WGL_COLOR_BITS_ARB, color_bits);
add_attrib(&attribs, WGL_DEPTH_BITS_ARB, depth_bits);
add_attrib(&attribs, WGL_STENCIL_BITS_ARB, stencil_bits);
add_attrib(&attribs, 0, 0);
if (!wglChoosePixelFormatARB(plat->hdc, attribs.array, NULL, 1,
&format, &num_formats)) {
blog(LOG_ERROR, "wglChoosePixelFormatARB failed, %u",
GetLastError());
format = 0;
}
darray_free(&attribs);
return format;
}
static inline bool gl_init_pixel_format(struct gl_platform *plat,
struct gs_init_data *info)
{
PIXELFORMATDESCRIPTOR pfd;
int format = gl_get_pixel_format(plat, info);
if (!format)
return false;
if (!DescribePixelFormat(plat->hdc, format, sizeof(pfd), &pfd)) {
blog(LOG_ERROR, "DescribePixelFormat failed, %u",
GetLastError());
return false;
}
if (!SetPixelFormat(plat->hdc, format, &pfd)) {
blog(LOG_ERROR, "SetPixelFormat failed, %u", GetLastError());
return false;
}
return true;
}
bool gl_platform_init(struct gs_device *device, struct gs_init_data *info)
{
device->plat = bmalloc(sizeof(struct gl_platform));
memset(device->plat, 0, sizeof(struct gl_platform));
if (!gl_create_false_context(device->plat, info))
return false;
if (!gl_init_extensions())
return false;
if (!gl_init_pixel_format(device->plat, info))
return false;
return true;
}